It was recently pointed out to me that a simple “hello world” style application built with Open Watcom C/C++ 1.9 does not run on Win32s version 1.30, even though the same executable runs just fine on Windows NT 3.51, Windows 95, or Windows 10.
More specifically, the program crashes rather early on Win32s. With the help of map files and source code, I established that the crash occurs in an internal function called __setenvp
, which tries to dereference a null pointer stored in an internal variable _RWD_Envptr
.
The _RWD_Envptr
variable is filled in by the GetEnvironmentStrings
API in the C runtime startup code. The GetEnvironmentStrings
API call ends up importing GetEnvironmentStringsA
from KERNEL32.DLL. And clearly GetEnvironmentStringsA
is failing on Win32s, although it works just fine on NT and Win9x.
Further probing revealed that the GetEnvironmentStrings
API has curious history. On Windows NT 3.1, there was only GetEnvironmentStrings
(no A or W suffix). On all later Win32 implementations, starting with NT 3.5, there’s GetEnvironmentStringsA
and GetEnvironmentStringsW
, as well as FreeEnvironmentStringsA
and FreeEnvironmentStringsW
.
On NT 3.1, there was no FreeEnvironmentStrings
, presumably because GetEnvironmentStrings
returned a pointer to existing memory that couldn’t be freed (and would be freed at process termination anyway). On NT 3.5, GetEnvironmentStringsA
converts the strings provided by GetEnvironmentStringsW
and allocates memory for the converted strings, so there is something to free.
A quick experiment with Microsoft Visual Studio 4.0 showed that a test application does run on Win32s; reading MSVC 4.0 runtime source code also revealed that Microsoft calls GetEnvironmentStringsA
and immediately terminates the process if GetEnvironmentStringsA
fails. So… how can that work on Win32s?
Continue reading →