简体   繁体   中英

Why does order matter when using GetTempPath/GetTempFileName?

I am troubleshooting some code that is crashing one application. The crash is happening later in application after his code. Maybe memory leak or something similar? I trace it back to the following function:

function GetTempFileName: String;
const
  DOC_REGISTER_PREFIX = 'DR';
var
  NameBuffer: array[0..MAX_PATH] of char;
  PathBuffer: array[0..MAX_PATH] of char;
begin
   FillChar(NameBuffer, MAX_PATH, 0);
   FillChar(PathBuffer, MAX_PATH, 0);
   GetTempPath(SizeOf(PathBuffer), PathBuffer);
   Windows.GetTempFileName(PathBuffer, DOC_REGISTER_PREFIX, 0, NameBuffer);
   Result := NameBuffer;
end;

The functions works and it gets back a temporary filename but it makes the application to crash for some reason after going up to the caller functions. After some testing and comparing with other similar functions online, I found out that if I change the order between PathBuffer and NameBuffer when using GetTempPath and GetTempFileName, everything works as expected.

function GetTempFileName: String;
const
  DOC_REGISTER_PREFIX = 'DR';
var
  NameBuffer: array[0..MAX_PATH] of char;
  PathBuffer: array[0..MAX_PATH] of char;
begin
   FillChar(NameBuffer, MAX_PATH, 0);
   FillChar(PathBuffer, MAX_PATH, 0);
   GetTempPath(SizeOf(NameBuffer), NameBuffer);
   Windows.GetTempFileName(NameBuffer, DOC_REGISTER_PREFIX, 0, PathBuffer);
   Result := PathBuffer;
end;

Is there any explanation for this?

Most likely a buffer overflow. If you are using Delphi 2009+, char is 2-byte WideChar , not 1-byte AnsiChar , in which case FillChar() fills only 1/2 of the buffer (it fills bytes, not characters, despite its name), but more importantly SizeOf() would pass the wrong size to GetTempPath() , allowing it to write more chars than you have allocated space for. Use Length() instead. GetTempPath() wants the number of chars, not the number of bytes.

You don't need FillChar() at all, and you should pay attention to the return values of the API functions.

Try this:

function GetTempFileName: String;
const
  DOC_REGISTER_PREFIX = 'DR';
var
  NameBuffer: array[0..MAX_PATH-1] of char;
  PathBuffer: array[0..MAX_PATH-1] of char;
  Size: DWORD;
begin
  Result := '';
  Size := Windows.GetTempPath(Length(PathBuffer), PathBuffer);
  if (Size = 0) or (Size > Length(PathBuffer)) then Exit;
  if (Windows.GetTempFileName(PathBuffer, DOC_REGISTER_PREFIX, 0, NameBuffer) = 0) then Exit;
  Result := NameBuffer;
end;

Acording to documentation for GefTempFileName lpPathName string cannot be longer than MAX_PATH-14 characters or GetTempFileName will fail.

But in your example you are passing string that is MAX_PATH long.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM