[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.
This commit is contained in:
Pierre Schweitzer 2019-05-05 10:12:59 +02:00
parent 1ed7f27466
commit 8d128aa441
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B

View file

@ -261,62 +261,112 @@ QueryDosDeviceA(
DWORD ucchMax DWORD ucchMax
) )
{ {
UNICODE_STRING DeviceNameU; NTSTATUS Status;
USHORT CurrentPosition;
ANSI_STRING AnsiString;
UNICODE_STRING TargetPathU; UNICODE_STRING TargetPathU;
ANSI_STRING TargetPathA; PUNICODE_STRING DeviceNameU;
DWORD Length; DWORD RetLength, CurrentLength, Length;
DWORD CurrentLength; PWSTR DeviceNameBuffer, TargetPathBuffer;
PWCHAR Buffer;
if (lpDeviceName) /* If we want a specific device name, convert it */
if (lpDeviceName != NULL)
{ {
if (!RtlCreateUnicodeStringFromAsciiz(&DeviceNameU, /* Convert DeviceName using static unicode string */
(LPSTR)lpDeviceName)) 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;
} }
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR)); else
if (Buffer == NULL) {
DeviceNameBuffer = 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); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0; return 0;
} }
Length = QueryDosDeviceW(lpDeviceName ? DeviceNameU.Buffer : NULL, /* Call W */
Buffer, ucchMax); 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)
{
/* This will be our work length (but not the one we return) */
--Length;
/* Already 0 the last char */
lpTargetPath[Length] = ANSI_NULL;
}
/* If we had an output, start the convert loop */
if (Length != 0) if (Length != 0)
{ {
TargetPathA.Buffer = lpTargetPath; /*
TargetPathU.Buffer = Buffer; * We'll have to loop because TargetPathBuffer may contain
ucchMax = Length; * several strings (NULL separated)
* We'll start at position 0
while (ucchMax) */
CurrentPosition = 0;
while (CurrentPosition < Length)
{ {
CurrentLength = min(ucchMax, MAXUSHORT / 2); /* Get the maximum length */
TargetPathU.MaximumLength = TargetPathU.Length = (USHORT)CurrentLength * sizeof(WCHAR); CurrentLength = min(Length - CurrentPosition, MAXUSHORT / 2);
TargetPathA.Length = 0; /* Initialize our output string */
TargetPathA.MaximumLength = (USHORT)CurrentLength; AnsiString.Length = 0;
AnsiString.MaximumLength = CurrentLength + sizeof(ANSI_NULL);
AnsiString.Buffer = &lpTargetPath[CurrentPosition];
RtlUnicodeStringToAnsiString(&TargetPathA, &TargetPathU, FALSE); /* Initialize input string that will be converted */
ucchMax -= CurrentLength; TargetPathU.Length = CurrentLength * sizeof(WCHAR);
TargetPathA.Buffer += TargetPathA.Length; TargetPathU.MaximumLength = CurrentLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
TargetPathU.Buffer += TargetPathU.Length / sizeof(WCHAR); 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); Leave:
if (lpDeviceName) /* Free our intermediate buffer and leave */
{ RtlFreeHeap(RtlGetProcessHeap(), 0, TargetPathBuffer);
RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer);
} return RetLength;
return Length;
} }