4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
authorsherman
Sat, 03 Apr 2010 18:29:11 -0700
changeset 5168 41e46b5d9b15
parent 5167 dbd299f8fdae
child 5198 6e8fc7a85bf2
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win) Summary: to use CreateProcessW on Windowns platform Reviewed-by: martin
jdk/src/share/native/java/lang/System.c
jdk/src/share/native/java/lang/java_props.h
jdk/src/solaris/native/java/lang/java_props_md.c
jdk/src/windows/native/java/lang/ProcessImpl_md.c
jdk/src/windows/native/java/lang/java_props_md.c
jdk/test/java/lang/ProcessBuilder/Basic.java
--- a/jdk/src/share/native/java/lang/System.c	Tue Mar 30 19:10:47 2010 -0700
+++ b/jdk/src/share/native/java/lang/System.c	Sat Apr 03 18:29:11 2010 -0700
@@ -67,10 +67,13 @@
         (*env)->DeleteLocalRef(env, r); \
     } else ((void) 0)
 
-#define PUTPROP_ForPlatformCString(props, key, val) \
+/*  "key" is a char type string with only ASCII character in it.
+    "val" is a nchar (typedefed in java_props.h) type string  */
+
+#define PUTPROP_ForPlatformNString(props, key, val) \
     if (1) { \
-        jstring jkey = JNU_NewStringPlatform(env, key); \
-        jstring jval = JNU_NewStringPlatform(env, val); \
+        jstring jkey = (*env)->NewStringUTF(env, key);  \
+        jstring jval = GetStringPlatform(env, val); \
         jobject r = (*env)->CallObjectMethod(env, props, putID, jkey, jval); \
         if ((*env)->ExceptionOccurred(env)) return NULL; \
         (*env)->DeleteLocalRef(env, jkey); \
@@ -150,7 +153,7 @@
             (sprops->cpu_isalist ? sprops->cpu_isalist : ""));
     PUTPROP(props, "sun.cpu.endian",  sprops->cpu_endian);
 
-    /* !!! DO NOT call PUTPROP_ForPlatformCString before this line !!!
+    /* !!! DO NOT call PUTPROP_ForPlatformNString before this line !!!
      * !!! I18n properties have not been set up yet !!!
      */
 
@@ -195,18 +198,18 @@
      */
     PUTPROP(props, "java.awt.graphicsenv", sprops->graphics_env);
     if (sprops->font_dir != NULL) {
-        PUTPROP_ForPlatformCString(props,
+        PUTPROP_ForPlatformNString(props,
                                    "sun.java2d.fontpath", sprops->font_dir);
     }
 
-    PUTPROP_ForPlatformCString(props, "java.io.tmpdir", sprops->tmp_dir);
+    PUTPROP_ForPlatformNString(props, "java.io.tmpdir", sprops->tmp_dir);
 
-    PUTPROP_ForPlatformCString(props, "user.name", sprops->user_name);
-    PUTPROP_ForPlatformCString(props, "user.home", sprops->user_home);
+    PUTPROP_ForPlatformNString(props, "user.name", sprops->user_name);
+    PUTPROP_ForPlatformNString(props, "user.home", sprops->user_home);
 
     PUTPROP(props, "user.timezone", sprops->timezone);
 
-    PUTPROP_ForPlatformCString(props, "user.dir", sprops->user_dir);
+    PUTPROP_ForPlatformNString(props, "user.dir", sprops->user_dir);
 
     /* This is a sun. property as it is currently only set for Gnome and
      * Windows desktops.
--- a/jdk/src/share/native/java/lang/java_props.h	Tue Mar 30 19:10:47 2010 -0700
+++ b/jdk/src/share/native/java/lang/java_props.h	Sat Apr 03 18:29:11 2010 -0700
@@ -28,21 +28,29 @@
 
 #include <jni_util.h>
 
+/* The preferred native type for storing text on the current OS */
+#ifdef WIN32
+#include <tchar.h>
+typedef WCHAR nchar;
+#else
+typedef char nchar;
+#endif
+
 typedef struct {
     char *os_name;
     char *os_version;
     char *os_arch;
 
-    char *tmp_dir;
-    char *font_dir;
-    char *user_dir;
+    nchar *tmp_dir;
+    nchar *font_dir;
+    nchar *user_dir;
 
     char *file_separator;
     char *path_separator;
     char *line_separator;
 
-    char *user_name;
-    char *user_home;
+    nchar *user_name;
+    nchar *user_home;
 
     char *language;
     char *country;
@@ -71,5 +79,6 @@
 } java_props_t;
 
 java_props_t *GetJavaProperties(JNIEnv *env);
+jstring GetStringPlatform(JNIEnv *env, nchar* str);
 
 #endif /* _JAVA_PROPS_H */
--- a/jdk/src/solaris/native/java/lang/java_props_md.c	Tue Mar 30 19:10:47 2010 -0700
+++ b/jdk/src/solaris/native/java/lang/java_props_md.c	Sat Apr 03 18:29:11 2010 -0700
@@ -416,3 +416,9 @@
 
     return &sprops;
 }
+
+jstring
+GetStringPlatform(JNIEnv *env, nchar* cstr)
+{
+    return JNU_NewStringPlatform(env, cstr);
+}
--- a/jdk/src/windows/native/java/lang/ProcessImpl_md.c	Tue Mar 30 19:10:47 2010 -0700
+++ b/jdk/src/windows/native/java/lang/ProcessImpl_md.c	Sat Apr 03 18:29:11 2010 -0700
@@ -145,11 +145,11 @@
     HANDLE errWrite = INVALID_HANDLE_VALUE;
     SECURITY_ATTRIBUTES sa;
     PROCESS_INFORMATION pi;
-    STARTUPINFO si;
-    LPTSTR  pcmd      = NULL;
-    LPCTSTR pdir      = NULL;
-    LPVOID  penvBlock = NULL;
-    jlong  *handles   = NULL;
+    STARTUPINFOW si;
+    const jchar*  pcmd = NULL;
+    const jchar*  pdir = NULL;
+    const jchar*  penvBlock = NULL;
+    jlong  *handles = NULL;
     jlong ret = 0;
     OSVERSIONINFO ver;
     jboolean onNT = JNI_FALSE;
@@ -161,22 +161,17 @@
         onNT = JNI_TRUE;
 
     assert(cmd != NULL);
-    pcmd = (LPTSTR) JNU_GetStringPlatformChars(env, cmd, NULL);
+    pcmd = (*env)->GetStringChars(env, cmd, NULL);
     if (pcmd == NULL) goto Catch;
 
     if (dir != 0) {
-        pdir = (LPCTSTR) JNU_GetStringPlatformChars(env, dir, NULL);
+        pdir = (*env)->GetStringChars(env, dir, NULL);
         if (pdir == NULL) goto Catch;
-        pdir = (LPCTSTR) JVM_NativePath((char *)pdir);
     }
-
     if (envBlock != NULL) {
-        penvBlock = onNT
-            ? (LPVOID) ((*env)->GetStringChars(env, envBlock, NULL))
-            : (LPVOID) JNU_GetStringPlatformChars(env, envBlock, NULL);
+        penvBlock = ((*env)->GetStringChars(env, envBlock, NULL));
         if (penvBlock == NULL) goto Catch;
     }
-
     assert(stdHandles != NULL);
     handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
     if (handles == NULL) goto Catch;
@@ -237,30 +232,17 @@
     if (onNT)
         processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
     else
-        processFlag = selectProcessFlag(env, cmd);
-
-    /* Java and Windows are both pure Unicode systems at heart.
-     * Windows has both a legacy byte-based API and a 16-bit Unicode
-     * "W" API.  The Right Thing here is to call CreateProcessW, since
-     * that will allow all process-related information like command
-     * line arguments to be passed properly to the child.  We don't do
-     * that currently, since we would first have to have "W" versions
-     * of JVM_NativePath and perhaps other functions.  In the
-     * meantime, we can call CreateProcess with the magic flag
-     * CREATE_UNICODE_ENVIRONMENT, which passes only the environment
-     * in "W" mode.  We will fix this later. */
-
-    ret = CreateProcess(0,           /* executable name */
-                        pcmd,        /* command line */
-                        0,           /* process security attribute */
-                        0,           /* thread security attribute */
-                        TRUE,        /* inherits system handles */
-                        processFlag, /* selected based on exe type */
-                        penvBlock,   /* environment block */
-                        pdir,        /* change to the new current directory */
-                        &si,         /* (in)  startup information */
-                        &pi);        /* (out) process information */
-
+        processFlag = selectProcessFlag(env, cmd) | CREATE_UNICODE_ENVIRONMENT;
+    ret = CreateProcessW(0,                /* executable name */
+                         (LPWSTR)pcmd,     /* command line */
+                         0,                /* process security attribute */
+                         0,                /* thread security attribute */
+                         TRUE,             /* inherits system handles */
+                         processFlag,      /* selected based on exe type */
+                         (LPVOID)penvBlock,/* environment block */
+                         (LPCWSTR)pdir,    /* change to the new current directory */
+                         &si,              /* (in)  startup information */
+                         &pi);             /* (out) process information */
     if (!ret) {
         win32Error(env, "CreateProcess");
         goto Catch;
@@ -276,18 +258,13 @@
     closeSafely(errWrite);
 
     if (pcmd != NULL)
-        JNU_ReleaseStringPlatformChars(env, cmd, (char *) pcmd);
+        (*env)->ReleaseStringChars(env, cmd, pcmd);
     if (pdir != NULL)
-        JNU_ReleaseStringPlatformChars(env, dir, (char *) pdir);
-    if (penvBlock != NULL) {
-        if (onNT)
-            (*env)->ReleaseStringChars(env, envBlock, (jchar *) penvBlock);
-        else
-            JNU_ReleaseStringPlatformChars(env, dir, (char *) penvBlock);
-    }
+        (*env)->ReleaseStringChars(env, dir, pdir);
+    if (penvBlock != NULL)
+        (*env)->ReleaseStringChars(env, envBlock, penvBlock);
     if (handles != NULL)
         (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
-
     return ret;
 
  Catch:
--- a/jdk/src/windows/native/java/lang/java_props_md.c	Tue Mar 30 19:10:47 2010 -0700
+++ b/jdk/src/windows/native/java/lang/java_props_md.c	Sat Apr 03 18:29:11 2010 -0700
@@ -513,14 +513,14 @@
 /*
  * Code to figure out the user's home directory using the registry
 */
-static char *
+static WCHAR*
 getHomeFromRegistry()
 {
     HKEY key;
     int rc;
     DWORD type;
-    char *p;
-    char path[MAX_PATH+1];
+    WCHAR *p;
+    WCHAR path[MAX_PATH+1];
     int size = MAX_PATH+1;
 
     rc = RegOpenKeyEx(HKEY_CURRENT_USER, SHELL_KEY, 0, KEY_READ, &key);
@@ -530,18 +530,18 @@
     }
 
     path[0] = 0;
-    rc = RegQueryValueEx(key, "Desktop", 0, &type, path, &size);
+    rc = RegQueryValueExW(key, L"Desktop", 0, &type, (LPBYTE)path, &size);
     if (rc != ERROR_SUCCESS || type != REG_SZ) {
         return NULL;
     }
     RegCloseKey(key);
     /* Get the parent of Desktop directory */
-    p = strrchr(path, '\\');
+    p = wcsrchr(path, L'\\');
     if (p == NULL) {
         return NULL;
     }
-    *p = '\0';
-    return strdup(path);
+    *p = L'\0';
+    return _wcsdup(path);
 }
 
 /*
@@ -550,16 +550,16 @@
 typedef HRESULT (WINAPI *GetSpecialFolderType)(HWND, int, LPITEMIDLIST *);
 typedef BOOL (WINAPI *GetPathFromIDListType)(LPCITEMIDLIST, LPSTR);
 
-char *
+WCHAR*
 getHomeFromShell32()
 {
-    HMODULE lib = LoadLibrary("SHELL32.DLL");
+    HMODULE lib = LoadLibraryW(L"SHELL32.DLL");
     GetSpecialFolderType do_get_folder;
     GetPathFromIDListType do_get_path;
     HRESULT rc;
     LPITEMIDLIST item_list = 0;
-    char *p;
-    char path[MAX_PATH+1];
+    WCHAR *p;
+    WCHAR path[MAX_PATH+1];
     int size = MAX_PATH+1;
 
     if (lib == 0) {
@@ -568,7 +568,7 @@
     }
 
     do_get_folder = (GetSpecialFolderType)GetProcAddress(lib, "SHGetSpecialFolderLocation");
-    do_get_path = (GetPathFromIDListType)GetProcAddress(lib, "SHGetPathFromIDListA");
+    do_get_path = (GetPathFromIDListType)GetProcAddress(lib, "SHGetPathFromIDListW");
 
     if (do_get_folder == 0 || do_get_path == 0) {
         // the library doesn't hold the right functions !!??
@@ -582,10 +582,10 @@
     }
 
     path[0] = 0;
-    (*do_get_path)(item_list, path);
+    (*do_get_path)(item_list, (LPSTR)path);
 
     /* Get the parent of Desktop directory */
-    p = strrchr(path, '\\');
+    p = wcsrchr(path, L'\\');
     if (p) {
         *p = 0;
     }
@@ -598,8 +598,7 @@
      * We also don't unload the SHELL32 DLL.  We've paid the hit for loading
      * it and we may need it again later.
      */
-
-    return strdup(path);
+    return _wcsdup(path);
 }
 
 static boolean
@@ -661,10 +660,10 @@
 
     /* tmp dir */
     {
-        char tmpdir[MAX_PATH + 1];
+        WCHAR tmpdir[MAX_PATH + 1];
         /* we might want to check that this succeed */
-        GetTempPath(MAX_PATH + 1, tmpdir);
-        sprops.tmp_dir = strdup(tmpdir);
+        GetTempPathW(MAX_PATH + 1, tmpdir);
+        sprops.tmp_dir = _wcsdup(tmpdir);
     }
 
     /* Printing properties */
@@ -674,11 +673,10 @@
     sprops.graphics_env = "sun.awt.Win32GraphicsEnvironment";
 
     {    /* This is used only for debugging of font problems. */
-        char *path = getenv("JAVA2D_FONTPATH");
-        sprops.font_dir = (path != 0) ? strdup(path) : NULL;
+        WCHAR *path = _wgetenv(L"JAVA2D_FONTPATH");
+        sprops.font_dir = (path != NULL) ? _wcsdup(path) : NULL;
     }
 
-
     /* OS properties */
     {
         char buf[100];
@@ -830,14 +828,14 @@
      * 100 K of footprint.
      */
     {
-        char *uname = getenv("USERNAME");
-        if (uname != NULL && strlen(uname) > 0) {
-            sprops.user_name = strdup(uname);
+        WCHAR *uname = _wgetenv(L"USERNAME");
+        if (uname != NULL && wcslen(uname) > 0) {
+            sprops.user_name = _wcsdup(uname);
         } else {
-            char buf[100];
+            WCHAR buf[100];
             int buflen = sizeof(buf);
             sprops.user_name =
-                GetUserName(buf, &buflen) ? strdup(buf) : "unknown";
+                GetUserNameW(buf, &buflen) ? _wcsdup(buf) : L"unknown";
         }
     }
 
@@ -858,14 +856,13 @@
      *     On single-user Win95, user.home gets set to c:\windows.
      */
     {
-        char *homep = getHomeFromRegistry();
+        WCHAR *homep = getHomeFromRegistry();
         if (homep == NULL) {
             homep = getHomeFromShell32();
-            if (homep == NULL) {
-                homep = "C:\\";
-            }
+            if (homep == NULL)
+                homep = L"C:\\";
         }
-        sprops.user_home = homep;
+        sprops.user_home = _wcsdup(homep);
     }
 
     /*
@@ -963,9 +960,9 @@
 
     /* Current directory */
     {
-        char buf[MAX_PATH];
-        GetCurrentDirectory(sizeof(buf), buf);
-        sprops.user_dir = strdup(buf);
+        WCHAR buf[MAX_PATH];
+        GetCurrentDirectoryW(sizeof(buf), buf);
+        sprops.user_dir = _wcsdup(buf);
     }
 
     sprops.file_separator = "\\";
@@ -974,3 +971,9 @@
 
     return &sprops;
 }
+
+jstring
+GetStringPlatform(JNIEnv *env, nchar* wcstr)
+{
+    return (*env)->NewString(env, wcstr, wcslen(wcstr));
+}
--- a/jdk/test/java/lang/ProcessBuilder/Basic.java	Tue Mar 30 19:10:47 2010 -0700
+++ b/jdk/test/java/lang/ProcessBuilder/Basic.java	Sat Apr 03 18:29:11 2010 -0700
@@ -26,6 +26,7 @@
  * @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
  *      5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
  *      6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958
+ *      4947220
  * @summary Basic tests for Process and Environment Variable code
  * @run main/othervm Basic
  * @author Martin Buchholz
@@ -1456,13 +1457,14 @@
                 new File(System.getProperty("user.dir")).getCanonicalPath();
             String[] sdirs = new String[]
                 {".", "..", "/", "/bin",
-                 "C:", "c:", "C:/", "c:\\", "\\", "\\bin" };
+                 "C:", "c:", "C:/", "c:\\", "\\", "\\bin",
+                 "c:\\windows  ", "c:\\Program Files", "c:\\Program Files\\" };
             for (String sdir : sdirs) {
                 File dir = new File(sdir);
                 if (! (dir.isDirectory() && dir.exists()))
                     continue;
                 out.println("Testing directory " + dir);
-                dir = new File(dir.getCanonicalPath());
+                //dir = new File(dir.getCanonicalPath());
 
                 ProcessBuilder pb = new ProcessBuilder();
                 equal(pb.directory(), null);
@@ -1470,7 +1472,7 @@
 
                 pb.directory(dir);
                 equal(pb.directory(), dir);
-                equal(pwdInChild(pb), dir.toString());
+                equal(pwdInChild(pb), dir.getCanonicalPath());
 
                 pb.directory(null);
                 equal(pb.directory(), null);
@@ -1481,6 +1483,27 @@
         } catch (Throwable t) { unexpected(t); }
 
         //----------------------------------------------------------------
+        // Working directory with Unicode in child
+        //----------------------------------------------------------------
+        try {
+            if (UnicodeOS.is()) {
+                File dir = new File(System.getProperty("test.dir", "."),
+                                    "ProcessBuilderDir\u4e00\u4e02");
+                try {
+                    if (!dir.exists())
+                        dir.mkdir();
+                    out.println("Testing Unicode directory:" + dir);
+                    ProcessBuilder pb = new ProcessBuilder();
+                    pb.directory(dir);
+                    equal(pwdInChild(pb), dir.getCanonicalPath());
+                } finally {
+                    if (dir.exists())
+                        dir.delete();
+                }
+            }
+        } catch (Throwable t) { unexpected(t); }
+
+        //----------------------------------------------------------------
         // OOME in child allocating maximally sized array
         // Test for hotspot/jvmti bug 6850957
         //----------------------------------------------------------------