1

I have an application which happens to log to the console using winapi's WriteFile on a handle acquired from GetStdHandle. Minimal test case:

#include <Windows.h>

int main(int argc, char** argv) {
  HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
  if(GetFileType(console) == FILE_TYPE_UNKNOWN)
    return;
  WriteFile(console, "abc", 3, 0, 0);
}

built with default options in VS2013. This works without problems when invoked on a standard Windows console and when invoked from python2/python3/Sublime's console using e.g. subprocess.Popen('/path/to/my.exe').

Now I want to run this program as a build system in SublimeText 3. This is the build definition:

{
  "cmd": [ "/path/to/my.exe" ]
}

According to documentation this should sort of be equivalent to using subprocess.Popen. However when I invoke this 'build system' Sublime's output pane displays abc and then the call to WriteFile crashes with

0xC0000005: Access violation writing location 0x00000000.

What happens here? Is this a problem in my code, in Sublime, or in WriteFile? Anything that can be done about it? (I tried using shell_cmd instead of cmd but that makes no difference)

stijn
  • 34,664
  • 13
  • 111
  • 163

1 Answers1

3

You are passing the wrong arguments to WriteFile:

lpNumberOfBytesWritten [out, optional]
This parameter can be NULL only when the lpOverlapped parameter is not NULL.

For a synchronous call to WriteFile, you will have to pass a valid pointer to a DWORD, where the number of bytes written are returned:

#include <Windows.h>

int main(int argc, char** argv) {
  HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
  if(GetFileType(console) == FILE_TYPE_UNKNOWN)
    return;
  DWORD dwBytesWritten{};
  WriteFile(console, "abc", 3, &dwBytesWritten, 0);
}
IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • *bonks head on keyboard* so we were just lucky this application has ran for thousands of hours on tens of different machines printing thousands of lines to the console without any problem? Any idea why especially under Sublime this turns up? – stijn Nov 21 '16 at 11:57
  • 1
    @stijn: I've pondered about this a bit, but couldn't come up with an explanation, why this appears to work reliably under some conditions, but not others. The only thing I could imagine is, that I/O stream redirection plays into this, and when you get lucky, the redirected stream doesn't report the bytes written, and `WriteFile` never tries to write to `*lpNumberOfBytesWritten`. That's speculation, though. – IInspectable Nov 21 '16 at 12:03
  • @stijn - really WriteFile check for `lpNumberOfBytesWritten != 0` and use this pointer only in this case (independent from stream redirection). however by documentation really need use valid and not zero `lpNumberOfBytesWritten` - for understand where exactly bug - the best option - debug code – RbMm Nov 21 '16 at 12:09
  • bug deffinitelly not because lpNumberOfBytesWritten == 0 – RbMm Nov 21 '16 at 12:14
  • @RbMm: Are you saying, that [Raymond Chen is wrong](http://stackoverflow.com/a/8195770/1889329)? – IInspectable Nov 21 '16 at 12:24
  • @IInspectable - i agree that by documentation this is **MUST BE** not 0 if no `lpOverlapped` - but if you make simply test or look under disasm/debugger for function code - you can see that really function not crash when `lpNumberOfBytesWritten == 0` - it correct handle this case. i saying that bug not because ` lpNumberOfBytesWritten == 0` but by some other reason – RbMm Nov 21 '16 at 12:30
  • @IInspectable - but i partially wrong here - on XP - this is really will be bug when `lpNumberOfBytesWritten == 0` in synchronous call. but on win7, win8.1, win10 - already no bug. so dependent from where code is running. only on XP (vista not look) crash will be – RbMm Nov 21 '16 at 12:39
  • @RbMm you say there is another reason, but fact is when I change the code to use non-null lpNumberOfBytesWritten, it actually works and doesn't crash anymore – stijn Nov 21 '16 at 12:54
  • @stijn - in this case i mistaken. – RbMm Nov 21 '16 at 12:54
  • sorry i bad looking - really on win7 also must be crash if `lpNumberOfBytesWritten==0` only begin form win 8.1 this is changed and no already crash – RbMm Nov 21 '16 at 13:08
  • @RbMm why are you keen to reverse engineer specific versions rather than rely on docs – David Heffernan Nov 21 '16 at 13:16
  • @DavidHeffernan - i and rely on docs here, and absolute agree that `lpNumberOfBytesWritten` must be no zero. but i OP write that program not crash always,but only under some condition. so i fast check on win 8.1 and win10 - and view that really no crash when this pointer ==0 - system handle this case . so i guess here can be another reason of bug. however on xp - this really always bug. and on win 7 too(first time i bad look). so i mistake here. sorry again – RbMm Nov 21 '16 at 13:21
  • 1
    On Windows 7 and earlier, console handles are pseudohandles rather than real handles. I believe that means that the write operation goes through a completely different code path, so some differences in behaviour are to be expected. – Harry Johnston Nov 22 '16 at 02:05