JDK-4921267 : (process) Win32Process passes incorrect environment block for empty env
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 5.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_2.6
  • CPU: generic
  • Submitted: 2003-09-11
  • Updated: 2003-10-14
  • Resolved: 2003-10-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
5.0 b24Fixed
Related Reports
Relates :  
Description
When the environment block is empty, the Java_java_lang_Win32Process_create() calls CreateProcess() with one zero "\0", but should call with two zeros "\0\0"

This was caught by running Rational Purify on an instance of the 1.4.2 hotspot VM and Borland's application server.

Purify generates the following warning:

[W] UMR: Uninitialized memory read in CreateProcessA {37 occurrences}
       Reading 1 byte from 0x0d45a9b9 (1 byte at 0x0d45a9b9
uninitialized)
       Address 0x0d45a9b9 is argument #7 of CreateProcessA
       Address 0x0d45a9b9 is 1 byte into a 4 byte block at 0x0d45a9b8
       Address 0x0d45a9b9 points to a malloc'd block in heap 0x003b0000
       Thread ID: 0xc3c
       Error location
           CreateProcessA [KERNEL32.dll]
           Java_java_lang_Win32Process_create [java.dll]
           ???            [ip=0x02aa7fdd]
           ???            [ip=0x02aa2c54]
           ???            [ip=0x02aa00ee]
           ???            [jvm.dll ip=0x6d3ae143]
           JVM_FindSignal [jvm.dll]
           ???            [jvm.dll ip=0x6d3ae057]
           ???            [jvm.dll ip=0x6d3b1d0a]
           JNU_NewObjectByName [java.dll]
       Allocation location
           malloc         [MSVCRT.dll]
           JNU_GetStringPlatformChars [java.dll]
           JNU_GetStringPlatformChars [java.dll]
           Java_java_lang_Win32Process_create [java.dll]
           ???            [ip=0x02aa7fdd]
           ???            [ip=0x02aa2c54]
           ???            [ip=0x02aa00ee]
           ???            [jvm.dll ip=0x6d3ae143]
           JVM_FindSignal [jvm.dll]
           ???            [jvm.dll ip=0x6d3ae057]

This shows that the second byte in argument #7 is read by CreateProcess but never initialized.

A logical hypothesis is that an empty envcmd '\0' is passed to CreateProcess:

Win32Process.java:

.....

       String envstr = null;
       if (env != null) {
           StringBuffer envbuf = new StringBuffer(256);
           for (int i = 0; i < env.length; i++) {
               envbuf.append(env[i]).append('\0');
           }
           envstr = envbuf.toString();
       }

This code doesn't append '\0' if env.length == 0

Needs to be smth like:

       String envstr = null;
       if (env != null) {
           StringBuffer envbuf = new StringBuffer(256);
           for (int i = 0; i < env.length; i++) {
               envbuf.append(env[i]).append('\0');
           }
           if (env.length == 0) envbuf.append(env[i]).append('\0');
           envstr = envbuf.toString();
       }

In the current version of Win32Process.java, an empty envstr is generated. 

Later, empty envstr is appended with one '\0' in JNU_GetStringPlatformChars()

As a result Java_java_lang_Win32Process_create() passes "\0" instead of "\0\0"
to CreateProcess

Due, to this CreateProcess tries to read beyond the *envcmd argument and if there's not a '\0' there by chance, it results in reading and processing wrong memory

In fact this situation might be real when CreateProcess is called multiple times and memory contains non-zeros left after previous operations.

Borland is observing a crash inside CreateProcess exactly in the scenario when CreateProcess is called frequently. This bug might be the cause of problems that Borland is seeing. Unfortunately, Borland's Enterprise Server is huge and it's too much work to try to create a small test case.
This bug needs to be fixed regardless.

To support the argument that two '\0' are needed for an empty environment, here's Win32 API documentation:

BOOL CreateProcess(...)

lpEnvironment 
[in] Pointer to an environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process. 
An environment block consists of a null-terminated block of null-terminated strings. Each string is in the form:

name=value
......
Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block.

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger tiger-beta FIXED IN: tiger tiger-beta INTEGRATED IN: tiger-b24 tiger-beta
14-06-2004

EVALUATION The Windows documentation is ambiguous about the number of trailing NULs required if the environment is empty. A high-quality OS implementation would only require one. But it is clearly safer to ensure that we always provide two trailing NULs, and this is easy to do. A possibly superfluous trailing NUL is clearly harmless. ###@###.### 2003-09-11 As well as generating two trailing NULs whenever creating an environment block on Windows, we should also accept an empty environment consisting of a single NUL. Be strict in what you generate, lenient in what you accept. We were getting both of these wrong. ###@###.### 2003-09-16
16-09-2003

WORK AROUND When calling Runtime.exec, never pass in an empty environment. If necessary, pass in a dummy environment variable. ###@###.### 2003-09-11
11-09-2003

PUBLIC COMMENTS Java should always provide two trailing NULs in environment blocks, even if the environment is empty. ###@###.### 2003-09-11
11-09-2003