提交 25756b37 编写于 作者: U uta

8016579: (process) IOException thrown by ProcessBuilder.start() method is incorrectly encoded

Reviewed-by: martin, dxu
上级 75203d52
...@@ -211,7 +211,11 @@ throwFileNotFoundException(JNIEnv *env, jstring path) ...@@ -211,7 +211,11 @@ throwFileNotFoundException(JNIEnv *env, jstring path)
n = getLastErrorString(buf, sizeof(buf)); n = getLastErrorString(buf, sizeof(buf));
if (n > 0) { if (n > 0) {
#ifdef WIN32
why = (*env)->NewStringUTF(env, buf);
#else
why = JNU_NewStringPlatform(env, buf); why = JNU_NewStringPlatform(env, buf);
#endif
} }
x = JNU_NewObjectByName(env, x = JNU_NewObjectByName(env,
"java/io/FileNotFoundException", "java/io/FileNotFoundException",
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "io_util.h" #include "io_util.h"
#include "io_util_md.h" #include "io_util_md.h"
#include <stdio.h> #include <stdio.h>
#include <windows.h>
#include <wchar.h> #include <wchar.h>
#include <io.h> #include <io.h>
...@@ -40,6 +41,7 @@ ...@@ -40,6 +41,7 @@
#include <limits.h> #include <limits.h>
#include <wincon.h> #include <wincon.h>
static DWORD MAX_INPUT_EVENTS = 2000; static DWORD MAX_INPUT_EVENTS = 2000;
/* If this returns NULL then an exception is pending */ /* If this returns NULL then an exception is pending */
...@@ -569,42 +571,75 @@ handleLseek(FD fd, jlong offset, jint whence) ...@@ -569,42 +571,75 @@ handleLseek(FD fd, jlong offset, jint whence)
} }
size_t size_t
getLastErrorString(char *buf, size_t len) getLastErrorString(char *utf8_jvmErrorMsg, size_t cbErrorMsg)
{ {
DWORD errval; size_t n = 0;
if (len > 0) { if (cbErrorMsg > 0) {
if ((errval = GetLastError()) != 0) { BOOLEAN noError = FALSE;
// DOS error WCHAR *utf16_osErrorMsg = (WCHAR *)malloc(cbErrorMsg*sizeof(WCHAR));
size_t n = (size_t)FormatMessage( if (utf16_osErrorMsg == NULL) {
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, // OOM accident
NULL, strncpy(utf8_jvmErrorMsg, "Out of memory", cbErrorMsg);
errval, // truncate if too long
0, utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0';
buf, n = strlen(utf8_jvmErrorMsg);
(DWORD)len, } else {
NULL); DWORD errval = GetLastError();
if (n > 3) { if (errval != 0) {
// Drop final '.', CR, LF // WIN32 error
if (buf[n - 1] == '\n') n--; n = (size_t)FormatMessageW(
if (buf[n - 1] == '\r') n--; FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
if (buf[n - 1] == '.') n--; NULL,
buf[n] = '\0'; errval,
} 0,
return n; utf16_osErrorMsg,
} (DWORD)cbErrorMsg,
NULL);
if (errno != 0) { if (n > 3) {
// C runtime error that has no corresponding DOS error code // Drop final '.', CR, LF
const char *err = strerror(errno); if (utf16_osErrorMsg[n - 1] == L'\n') --n;
size_t n = strlen(err); if (utf16_osErrorMsg[n - 1] == L'\r') --n;
if (n >= len) if (utf16_osErrorMsg[n - 1] == L'.') --n;
n = len - 1; utf16_osErrorMsg[n] = L'\0';
}
} else if (errno != 0) {
// C runtime error that has no corresponding WIN32 error code
const WCHAR *rtError = _wcserror(errno);
if (rtError != NULL) {
wcsncpy(utf16_osErrorMsg, rtError, cbErrorMsg);
// truncate if too long
utf16_osErrorMsg[cbErrorMsg - 1] = L'\0';
n = wcslen(utf16_osErrorMsg);
}
} else
noError = TRUE; //OS has no error to report
if (!noError) {
if (n > 0) {
n = WideCharToMultiByte(
CP_UTF8,
0,
utf16_osErrorMsg,
n,
utf8_jvmErrorMsg,
cbErrorMsg,
NULL,
NULL);
// no way to die
if (n > 0)
utf8_jvmErrorMsg[min(cbErrorMsg - 1, n)] = '\0';
}
strncpy(buf, err, n); if (n <= 0) {
buf[n] = '\0'; strncpy(utf8_jvmErrorMsg, "Secondary error while OS message extraction", cbErrorMsg);
return n; // truncate if too long
utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0';
n = strlen(utf8_jvmErrorMsg);
}
}
free(utf16_osErrorMsg);
} }
} }
return n;
return 0;
} }
...@@ -40,20 +40,70 @@ ...@@ -40,20 +40,70 @@
*/ */
#define PIPE_SIZE (4096+24) #define PIPE_SIZE (4096+24)
/* We have THREE locales in action:
* 1. Thread default locale - dictates UNICODE-to-8bit conversion
* 2. System locale that defines the message localization
* 3. The file name locale
* Each locale could be an extended locale, that means that text cannot be
* mapped to 8bit sequence without multibyte encoding.
* VM is ready for that, if text is UTF-8.
* Here we make the work right from the beginning.
*/
size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {
size_t n = (size_t)FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
(DWORD)errnum,
0,
utf16_OSErrorMsg,
(DWORD)maxMsgLength,
NULL);
if (n > 3) {
// Drop final '.', CR, LF
if (utf16_OSErrorMsg[n - 1] == L'\n') --n;
if (utf16_OSErrorMsg[n - 1] == L'\r') --n;
if (utf16_OSErrorMsg[n - 1] == L'.') --n;
utf16_OSErrorMsg[n] = L'\0';
}
return n;
}
#define MESSAGE_LENGTH (256 + 100)
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
static void static void
win32Error(JNIEnv *env, const char *functionName) win32Error(JNIEnv *env, const WCHAR *functionName)
{ {
static const char * const format = "%s error=%d, %s"; WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];
static const char * const fallbackFormat = "%s failed, error=%d"; WCHAR utf16_javaMessage[MESSAGE_LENGTH];
char buf[256]; /*Good suggestion about 2-bytes-per-symbol in localized error reports*/
char errmsg[sizeof(buf) + 100]; char utf8_javaMessage[MESSAGE_LENGTH*2];
const int errnum = GetLastError(); const int errnum = (int)GetLastError();
const int n = JVM_GetLastErrorString(buf, sizeof(buf)); int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
if (n > 0) n = (n > 0)
sprintf(errmsg, format, functionName, errnum, buf); ? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)
else : swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);
sprintf(errmsg, fallbackFormat, functionName, errnum);
JNU_ThrowIOException(env, errmsg); if (n > 0) /*terminate '\0' is not a part of conversion procedure*/
n = WideCharToMultiByte(
CP_UTF8,
0,
utf16_javaMessage,
n, /*by creation n <= MESSAGE_LENGTH*/
utf8_javaMessage,
MESSAGE_LENGTH*2,
NULL,
NULL);
/*no way to die*/
{
const char *errorMessage = "Secondary error while OS message extraction";
if (n > 0) {
utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';
errorMessage = utf8_javaMessage;
}
JNU_ThrowIOException(env, errorMessage);
}
} }
static void static void
...@@ -116,7 +166,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, ...@@ -116,7 +166,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
handles[0] = (jlong) -1; handles[0] = (jlong) -1;
} else { } else {
if (! CreatePipe(&inRead, &inWrite, &sa, PIPE_SIZE)) { if (! CreatePipe(&inRead, &inWrite, &sa, PIPE_SIZE)) {
win32Error(env, "CreatePipe"); win32Error(env, L"CreatePipe");
goto Catch; goto Catch;
} }
si.hStdInput = inRead; si.hStdInput = inRead;
...@@ -132,7 +182,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, ...@@ -132,7 +182,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
handles[1] = (jlong) -1; handles[1] = (jlong) -1;
} else { } else {
if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) { if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) {
win32Error(env, "CreatePipe"); win32Error(env, L"CreatePipe");
goto Catch; goto Catch;
} }
si.hStdOutput = outWrite; si.hStdOutput = outWrite;
...@@ -151,7 +201,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, ...@@ -151,7 +201,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
handles[2] = (jlong) -1; handles[2] = (jlong) -1;
} else { } else {
if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) { if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) {
win32Error(env, "CreatePipe"); win32Error(env, L"CreatePipe");
goto Catch; goto Catch;
} }
si.hStdError = errWrite; si.hStdError = errWrite;
...@@ -174,7 +224,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, ...@@ -174,7 +224,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
&si, /* (in) startup information */ &si, /* (in) startup information */
&pi); /* (out) process information */ &pi); /* (out) process information */
if (!ret) { if (!ret) {
win32Error(env, "CreateProcess"); win32Error(env, L"CreateProcess");
goto Catch; goto Catch;
} }
...@@ -210,7 +260,7 @@ Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong ...@@ -210,7 +260,7 @@ Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong
{ {
DWORD exit_code; DWORD exit_code;
if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0) if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
win32Error(env, "GetExitCodeProcess"); win32Error(env, L"GetExitCodeProcess");
return exit_code; return exit_code;
} }
...@@ -231,7 +281,7 @@ Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlo ...@@ -231,7 +281,7 @@ Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlo
FALSE, /* Wait for ANY event */ FALSE, /* Wait for ANY event */
INFINITE) /* Wait forever */ INFINITE) /* Wait forever */
== WAIT_FAILED) == WAIT_FAILED)
win32Error(env, "WaitForMultipleObjects"); win32Error(env, L"WaitForMultipleObjects");
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
...@@ -250,7 +300,7 @@ Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env, ...@@ -250,7 +300,7 @@ Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
dwTimeout); /* Wait for dwTimeout */ dwTimeout); /* Wait for dwTimeout */
if (result == WAIT_FAILED) if (result == WAIT_FAILED)
win32Error(env, "WaitForMultipleObjects"); win32Error(env, L"WaitForMultipleObjects");
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
...@@ -263,7 +313,7 @@ JNIEXPORT jboolean JNICALL ...@@ -263,7 +313,7 @@ JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle) Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
{ {
DWORD dwExitStatus; DWORD dwExitStatus;
GetExitCodeProcess(handle, &dwExitStatus); GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
return dwExitStatus == STILL_ACTIVE; return dwExitStatus == STILL_ACTIVE;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册