2

I am using the following code to create a file, but it always failed with error code 123 (the path syntax is not valid).

The strange thing is: path_ok is always ok, but path_err always failed with 123. And after the failure, the buffer that path_err points to is cleared.

Could anyone shed some light on me? I have checked the memory of the 2 pointers, and their contents seems to be identical.

Many thanks.

 WCHAR *pDumpFileName = ComposeDumpFileName();
 WCHAR *path_ok = _T("d:\\myapp_Utopia_2010-11-15_04-22-05.dmp");
 WCHAR *path_err = pDumpFileName;
 ::wprintf(pDumpFileName);
 HANDLE hFile = ::CreateFileW( pDumpFileName, GENERIC_READ | GENERIC_WRITE, 
  0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); 

The ComposeDumpFileName() function is like this:

WCHAR* ComposeDumpFileName(void)
{
 // get the time
    SYSTEMTIME sys_time;
    ::GetSystemTime(&sys_time);

    // get the computer name
    WCHAR computer_name[MAX_COMPUTERNAME_LENGTH + 1];
    DWORD computer_name_len = ARRAYSIZE(computer_name);
 ::GetComputerNameW(computer_name, &computer_name_len);

    // build the filename: APPNAME_COMPUTERNAME_DATE_TIME.DMP
    WCHAR dump_file_path[MAX_PATH];

 ::swprintf_s(dump_file_path, ARRAYSIZE(dump_file_path), 
        _T("d:\\myapp_%s_%04u-%02u-%02u_%02u-%02u-%02u.dmp"), 
        computer_name, sys_time.wYear, sys_time.wMonth, sys_time.wDay,
        sys_time.wHour, sys_time.wMinute, sys_time.wSecond);

 return dump_file_path;
}

Update

In my above code, when I execute the following code:

WCHAR *pDumpFileName = ComposeDumpFileName();

After the ComposeDumpFileName returned, its stack frame is invalid, however, its local variable WCHAR dump_file_path[MAX_PATH] still exists on the stack. So this explains why I can still see its content though the stack space for it is invalid already.

Then I execute the following statement:

     ::wprintf(pDumpFileName);
     HANDLE hFile = ::CreateFileW( pDumpFileName, GENERIC_READ | GENERIC_WRITE, 
      0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); 

The wprintf() and CreateFileW() has their own stack frames. Though in the debugger, I found that wprintf()'s stack frame didn't destroy the memory content pointed by the pDumpFileName, the CreateFileW could have, so it complains about a invalid path syntax.

This is my current understanding, please correct me if I am wrong.

Thanks.

smwikipedia
  • 61,609
  • 92
  • 309
  • 482
  • 2
    To say: "After the ComposeDumpFileName returned, its stack frame is invalid, however, its local variable WCHAR dump_file_path[MAX_PATH] still exists on the stack." is not correct. The dump_file_path variable was defined on the stack of the ComposeDumpFileName function and that stack disappeared as soon the ComposeDumpFileName ended. By trying to explain what is happening, you are trying to define "undefined behaviour", which of course is not possible. – jussij Nov 16 '10 at 03:51
  • I am wondering isn't it kind of a waste of the precious stack space to have an array allocated on stack? What if it is a really big array? But sometimes I do need a big array as a function's local variable. Should I always allocate **big** arrays on heap? Is there some best practices? Thanks. – smwikipedia Nov 18 '10 at 09:44
  • MAX_PATH will probably be defined as 255 in which case this is not a big size object to be placing on the stack. The default stack reservation size used by the linker is 1 MB – jussij Nov 19 '10 at 06:59

1 Answers1

16

One major problem with your code is the buffer you are returning is on the stack and this is a big no no:

 // build the filename: APPNAME_COMPUTERNAME_DATE_TIME.DMP 
 WCHAR dump_file_path[MAX_PATH]; 

Either change it to be a static:

 // build the filename: APPNAME_COMPUTERNAME_DATE_TIME.DMP 
 static WCHAR dump_file_path[MAX_PATH]; 

or pass the buffer into the function.

jussij
  • 10,370
  • 1
  • 33
  • 49
  • 1
    thansk for your concise reply. So the root cause is the array is allocated on a stack frame which is freed after the ComposeDumpFileName() returned. So the pointer is no longer a valid one in the caller. Isn't this bug a tricky one? Now I change to declare that array in the caller and pass it to the function. – smwikipedia Nov 15 '10 at 09:37
  • I think if I use malloc in the ComposeDumpFileName() to create the buffer on the heap, I can safely return the pointer to its caller. Correct me if I am wrong. Thanks. – smwikipedia Nov 15 '10 at 09:41
  • 2
    You can indeed use malloc and just return the pointer to the malloc'ed buffer. But don't forget to free the buffer once you are done with it, otherwise you will end up with a memory leak. – jussij Nov 15 '10 at 23:10
  • 2
    "Isn't this bug a tricky one?" - These sort of bugs can be hard to track down but generally they are fairly easy to spot by just reading the code. The secret is to use the { } as a guide. The simple rule is any thing declared after the { will be undeclared after the matching }. These brace characters define the 'scope' for which the variable is defined. – jussij Nov 24 '10 at 23:25
  • Thanks jussij. I appreciate your answer and comments. – smwikipedia Nov 25 '10 at 02:29