Why does GetCommandLine give me a corrupted command line?

We're calling GetCommandLine to retrieve the command line, and the documentation says that it returns a single null-terminated string. However, when we call it in our application, we find that it is actually a double-null-terminated string. The buffer returned consists of a series of null-terminated strings, one string per word on the command line, all stored one after the other, and with two null terminators at the end. How do I get the original string?

What is most likely happening is that somebody is taking the raw command line returned by GetCommandLine and writing to it. The customer can confirm this by dumping the command line just as the process starts, even before any DLLs get to run their DllMains, and then setting a write breakpoint on the command line to see who is writing to it.

And in fact, the customer did find the culprit.

It turns out it was some other part of the code (not written by me!) which was parsing the command line and writing into it in the process.

I don’t know if it’s strtok()’s fault. If you don’t want there to be any surprises where buffers get modified out from under you, you should use the "const" keyword responsibly. Callers of strtok() and similar functions should duplicate the buffer if they’re passed something that’s const.

It’s likely that it was modified by a strtok-style parsing, but note that this function, while not reentrant (strtok_r() is, as well as its port foolishly named strtok_s()) *is* const-correct, as it explicitly takes a non-const parameter.

So I’d rather blame the non-const-correct C functions like strchr() and strtol()…

What I meant is that all buffers that you don’t want modified should be marked const, and you should mark things const liberally and defensively. GetCommandLine() (and typically argv and similar) aren’t marked with const, but the broader point stands, and I don’t think this is a weakness of strtok()’s interface.

(Also, strtok() may not be reentrant, but at least if the CRT declares the state pointer as __declspec(thread) it can be used by multiple threads, though still not in a recursive function…)

Joe: Are you saying that WMI manages to give you a non-corrupted command line? If so, it does it by making a copy when the process starts, because Windows doesn’t keep a copy anywhere.

Honestly, though, it should. It would be nice if somebody (kernel or CSRSS) kept a copy of the original command line (possibly retrieved with GetOriginalCommandLine) so that DLLs can write proper debug logs.