However, CreateProcess partially enforces this silly, unnecessary special case! If an environment block begins with a null terminator, the next character must be in a mapped memory region because it will read this character.
I don’t think it’s a special case. The block ends with two NULLs. Requiring only one NULL if - and only if - it’s the first character, would be a special case.
That seems to indicate it’s virtually always wrong to call CreateProcess without [CREATE_UNICODE_ENVIRONMENT]
It kind of is. The backstory is the very first release - NT 3.1 - used an ANSI environment block. Normal Win32 APIs have an ANSI form (ending in A) and a Unicode form (ending in W) and the W form is expected to have Unicode parameters. But due to NT 3.1, CreateProcessW defaults to expecting an ANSI block, which necessitated CREATE_UNICODE_ENVIRONMENT.
While I’d agree with the authors conclusion here, the point is it’s safe to omit the flag if NULL is passed as an environment block to CreateProcessW. If anything else is passed, the flag must be set, or the child process may end up with a mangled environment.
I don’t think it’s a special case. The block ends with two NULLs. Requiring only one NULL if - and only if - it’s the first character, would be a special case.
It kind of is. The backstory is the very first release - NT 3.1 - used an ANSI environment block. Normal Win32 APIs have an ANSI form (ending in A) and a Unicode form (ending in W) and the W form is expected to have Unicode parameters. But due to NT 3.1, CreateProcessW defaults to expecting an ANSI block, which necessitated CREATE_UNICODE_ENVIRONMENT.
While I’d agree with the authors conclusion here, the point is it’s safe to omit the flag if NULL is passed as an environment block to CreateProcessW. If anything else is passed, the flag must be set, or the child process may end up with a mangled environment.