JDK-7117893 : Runtime.exec(String[]) fails to handle the empty string and quotes correctly
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_7
  • CPU: x86
  • Submitted: 2011-12-04
  • Updated: 2012-03-20
  • Resolved: 2011-12-08
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_01"
Java(TM) SE Runtime Environment (build 1.7.0_01-b08)
Java HotSpot(TM) Client VM (build 21.1-b02, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
Unlike on Unix, where the command line is an array of string, a windows program sees the command line as one one string and must manually parse it. This can be done using the CommandLineToArgvW function for example.
The command line parsing implemented by java.exe seems to be compatible with the one implemented by CommandLineToArgvW.

Now this means that before executing a program on Windows, the Runtime.exec(Strring[]) method must assemble one large command line string. During that process, it should escape the provided arguments, so that the result of the CommandLineToArgvW  function resembles the original array that was passed to Runtime.exec(String[]). However, currently the Runtime.exec() function seems to fail when it comes to the empty string "" and quotes inside the string. Backslashes may be affected as well.

Funny enough, somebody has added detection of string that contain white spaces. As my examples show, the " " is treated correctly, but the empty string is not.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the test class foo.Bar and observe the output.



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The java class provided executes itself 3 times. Each time, the output should be
argc: 4
arg0: 'arg0'
arg1: ''
arg2: 'arg"2'
arg3: ' '

Open a DOS shell and execute the follow command and observe the output: >java -cp bin foo.Bar arg0 "" "arg\"2" " "
argc: 4
arg0: 'arg0'
arg1: ''
arg2: arg"2
arg3: ' '

As you can see, it is perfectly possible to escape the provided strings in an appropriate way.
ACTUAL -
In the first two cases, the output is
argc: 3
arg0: 'arg0'
arg1: 'arg2 '
arg2: ''

Only in the third case (where I manually escaped the command line), the arguments are passed on correctly.

ProcessBuilder is affected as well.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package foo;

import java.io.IOException;
import java.io.InputStream;

public class Bar {
	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		System.out.println("argc: "+args.length);
		for (int i=0; i<args.length; i++)
		{
			System.out.println("arg"+i+": '"+args[i]+"'");
		}
		System.out.println();
		
		if (args.length <= 0) {
			String[] cmd = { "java", "-cp", "bin", "foo.Bar", "arg0", "", "arg\"2", " "};
			test(new ProcessBuilder(cmd).start());
			test(Runtime.getRuntime().exec(cmd));
			test(Runtime.getRuntime().exec("java -cp bin foo.Bar arg0 \"\" \"arg\\\"2\" \" \""));
		}
	}

	private static void test(Process p) throws IOException {
		InputStream in = p.getInputStream();
		byte[] b = new byte[4096];
		while (true)
		{
			int l = in.read(b);
			if (l < 0)
				break;
			
			System.out.write(b, 0, l);
		}
	}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
On Windows, Runtime.exec(String) seems to use the String as a command line without processing the String in any way. Hence, manually converting the argument array to a String and escaping the tokens appropriately seems to be possible.