https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8d128aa4415c4df5e6e3e2...
commit 8d128aa4415c4df5e6e3e27d9395ac2c5192c5dc Author: Pierre Schweitzer pierre@reactos.org AuthorDate: Sun May 5 10:12:59 2019 +0200 Commit: Pierre Schweitzer pierre@reactos.org CommitDate: Sun May 5 10:17:16 2019 +0200
[KERNEL32] Reduce QueryDosDeviceA memory footprint
by using TEB static unicode string (which is already preallocated). Also, properly handle RtlUnicodeStringToAnsiString failures. Finally, make sure output buffer is properly 0 terminated. --- dll/win32/kernel32/client/dosdev.c | 124 ++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 37 deletions(-)
diff --git a/dll/win32/kernel32/client/dosdev.c b/dll/win32/kernel32/client/dosdev.c index f077b5b3b3..b32d434195 100644 --- a/dll/win32/kernel32/client/dosdev.c +++ b/dll/win32/kernel32/client/dosdev.c @@ -261,62 +261,112 @@ QueryDosDeviceA( DWORD ucchMax ) { - UNICODE_STRING DeviceNameU; + NTSTATUS Status; + USHORT CurrentPosition; + ANSI_STRING AnsiString; UNICODE_STRING TargetPathU; - ANSI_STRING TargetPathA; - DWORD Length; - DWORD CurrentLength; - PWCHAR Buffer; + PUNICODE_STRING DeviceNameU; + DWORD RetLength, CurrentLength, Length; + PWSTR DeviceNameBuffer, TargetPathBuffer;
- if (lpDeviceName) + /* If we want a specific device name, convert it */ + if (lpDeviceName != NULL) { - if (!RtlCreateUnicodeStringFromAsciiz(&DeviceNameU, - (LPSTR)lpDeviceName)) + /* Convert DeviceName using static unicode string */ + RtlInitAnsiString(&AnsiString, lpDeviceName); + DeviceNameU = &NtCurrentTeb()->StaticUnicodeString; + Status = RtlAnsiStringToUnicodeString(DeviceNameU, &AnsiString, FALSE); + if (!NT_SUCCESS(Status)) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; + /* + * If the static unicode string is too small, + * it's because the name is too long... + * so, return appropriate status! + */ + if (Status == STATUS_BUFFER_OVERFLOW) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return FALSE; + } + + BaseSetLastNTError(Status); + return FALSE; } + + DeviceNameBuffer = DeviceNameU->Buffer; + } + else + { + DeviceNameBuffer = NULL; } - Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR)); - if (Buffer == NULL) + + /* Allocate the output buffer for W call */ + TargetPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR)); + if (TargetPathBuffer == NULL) { - if (lpDeviceName) - { - RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer); - } SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; }
- Length = QueryDosDeviceW(lpDeviceName ? DeviceNameU.Buffer : NULL, - Buffer, ucchMax); - if (Length != 0) + /* Call W */ + Length = QueryDosDeviceW(DeviceNameBuffer, TargetPathBuffer, ucchMax); + /* We'll return that length in case of a success */ + RetLength = Length; + + /* Handle the case where we would fill output buffer completly */ + if (Length != 0 && Length == ucchMax) { - TargetPathA.Buffer = lpTargetPath; - TargetPathU.Buffer = Buffer; - ucchMax = Length; + /* This will be our work length (but not the one we return) */ + --Length; + /* Already 0 the last char */ + lpTargetPath[Length] = ANSI_NULL; + }
- while (ucchMax) + /* If we had an output, start the convert loop */ + if (Length != 0) + { + /* + * We'll have to loop because TargetPathBuffer may contain + * several strings (NULL separated) + * We'll start at position 0 + */ + CurrentPosition = 0; + while (CurrentPosition < Length) { - CurrentLength = min(ucchMax, MAXUSHORT / 2); - TargetPathU.MaximumLength = TargetPathU.Length = (USHORT)CurrentLength * sizeof(WCHAR); + /* Get the maximum length */ + CurrentLength = min(Length - CurrentPosition, MAXUSHORT / 2);
- TargetPathA.Length = 0; - TargetPathA.MaximumLength = (USHORT)CurrentLength; + /* Initialize our output string */ + AnsiString.Length = 0; + AnsiString.MaximumLength = CurrentLength + sizeof(ANSI_NULL); + AnsiString.Buffer = &lpTargetPath[CurrentPosition];
- RtlUnicodeStringToAnsiString(&TargetPathA, &TargetPathU, FALSE); - ucchMax -= CurrentLength; - TargetPathA.Buffer += TargetPathA.Length; - TargetPathU.Buffer += TargetPathU.Length / sizeof(WCHAR); + /* Initialize input string that will be converted */ + TargetPathU.Length = CurrentLength * sizeof(WCHAR); + TargetPathU.MaximumLength = CurrentLength * sizeof(WCHAR) + sizeof(UNICODE_NULL); + TargetPathU.Buffer = &TargetPathBuffer[CurrentPosition]; + + /* Convert to ANSI */ + Status = RtlUnicodeStringToAnsiString(&AnsiString, &TargetPathU, FALSE); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + /* In case of a failure, forget about everything */ + RetLength = 0; + + goto Leave; + } + + /* Move to the next string */ + CurrentPosition += CurrentLength; } }
- RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); - if (lpDeviceName) - { - RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer); - } - return Length; +Leave: + /* Free our intermediate buffer and leave */ + RtlFreeHeap(RtlGetProcessHeap(), 0, TargetPathBuffer); + + return RetLength; }