Have win32strerror() return a g_malloc()ated UTF-8 error message.
Use FormatMessageW() to get a UTF-16-encoded Unicode error string, rather than an error string in the local code page, and then convert it from UTF-16 to UTF-8. Make it dynamically-allocated, so it's big enough and so that we are thread-safe. Make the callers free the result. Change-Id: I217aec5a644fa0176a829f181eb05561cb9d10f4 Reviewed-on: https://code.wireshark.org/review/31846 Petri-Dish: Guy Harris <guy@alum.mit.edu> Tested-by: Petri Dish Buildbot Reviewed-by: Guy Harris <guy@alum.mit.edu>
This commit is contained in:
parent
768a746ede
commit
ce6b5dba47
|
@ -206,6 +206,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
char control_id[ARGV_NUMBER_LEN];
|
char control_id[ARGV_NUMBER_LEN];
|
||||||
gchar *signal_pipe_name;
|
gchar *signal_pipe_name;
|
||||||
|
char *errmsg;
|
||||||
#else
|
#else
|
||||||
char errmsg[1024+1];
|
char errmsg[1024+1];
|
||||||
int sync_pipe[2]; /* pipe used to send messages from child to parent */
|
int sync_pipe[2]; /* pipe used to send messages from child to parent */
|
||||||
|
@ -433,8 +434,9 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
|
||||||
/* (increase this value if you have trouble while fast capture file switches) */
|
/* (increase this value if you have trouble while fast capture file switches) */
|
||||||
if (! CreatePipe(&sync_pipe_read, &sync_pipe_write, &sa, 5120)) {
|
if (! CreatePipe(&sync_pipe_read, &sync_pipe_write, &sa, 5120)) {
|
||||||
/* Couldn't create the pipe between parent and child. */
|
/* Couldn't create the pipe between parent and child. */
|
||||||
report_failure("Couldn't create sync pipe: %s",
|
errmsg = win32strerror(GetLastError());
|
||||||
win32strerror(GetLastError()));
|
report_failure("Couldn't create sync pipe: %s", errmsg);
|
||||||
|
g_free(errmsg);
|
||||||
free_argv(argv, argc);
|
free_argv(argv, argc);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -464,8 +466,9 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
|
||||||
|
|
||||||
if (signal_pipe == INVALID_HANDLE_VALUE) {
|
if (signal_pipe == INVALID_HANDLE_VALUE) {
|
||||||
/* Couldn't create the signal pipe between parent and child. */
|
/* Couldn't create the signal pipe between parent and child. */
|
||||||
report_failure("Couldn't create signal pipe: %s",
|
errmsg = win32strerror(GetLastError());
|
||||||
win32strerror(GetLastError()));
|
report_failure("Couldn't create signal pipe: %s", errmsg);
|
||||||
|
g_free(errmsg);
|
||||||
ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
|
ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
|
||||||
CloseHandle(sync_pipe_write);
|
CloseHandle(sync_pipe_write);
|
||||||
free_argv(argv, argc);
|
free_argv(argv, argc);
|
||||||
|
@ -523,8 +526,10 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
|
||||||
/* call dumpcap */
|
/* call dumpcap */
|
||||||
if(!win32_create_process(argv[0], args->str, NULL, NULL, TRUE,
|
if(!win32_create_process(argv[0], args->str, NULL, NULL, TRUE,
|
||||||
CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
|
CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
|
||||||
|
errmsg = win32strerror(GetLastError());
|
||||||
report_failure("Couldn't run %s in child process: %s",
|
report_failure("Couldn't run %s in child process: %s",
|
||||||
args->str, win32strerror(GetLastError()));
|
args->str, errmsg);
|
||||||
|
g_free(errmsg);
|
||||||
ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
|
ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
|
||||||
CloseHandle(sync_pipe_write);
|
CloseHandle(sync_pipe_write);
|
||||||
CloseHandle(signal_pipe);
|
CloseHandle(signal_pipe);
|
||||||
|
@ -647,6 +652,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
|
||||||
STARTUPINFO si;
|
STARTUPINFO si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
int i;
|
int i;
|
||||||
|
char *errmsg;
|
||||||
#else
|
#else
|
||||||
char errmsg[1024+1];
|
char errmsg[1024+1];
|
||||||
int sync_pipe[2]; /* pipe used to send messages from child to parent */
|
int sync_pipe[2]; /* pipe used to send messages from child to parent */
|
||||||
|
@ -675,8 +681,9 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
|
||||||
/* (increase this value if you have trouble while fast capture file switches) */
|
/* (increase this value if you have trouble while fast capture file switches) */
|
||||||
if (! CreatePipe(&sync_pipe[PIPE_READ], &sync_pipe[PIPE_WRITE], &sa, 5120)) {
|
if (! CreatePipe(&sync_pipe[PIPE_READ], &sync_pipe[PIPE_WRITE], &sa, 5120)) {
|
||||||
/* Couldn't create the message pipe between parent and child. */
|
/* Couldn't create the message pipe between parent and child. */
|
||||||
*msg = g_strdup_printf("Couldn't create sync pipe: %s",
|
errmsg = win32strerror(GetLastError());
|
||||||
win32strerror(GetLastError()));
|
*msg = g_strdup_printf("Couldn't create sync pipe: %s", errmsg);
|
||||||
|
g_free(errmsg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,8 +706,9 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
|
||||||
/* (increase this value if you have trouble while fast capture file switches) */
|
/* (increase this value if you have trouble while fast capture file switches) */
|
||||||
if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, 5120)) {
|
if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, 5120)) {
|
||||||
/* Couldn't create the message pipe between parent and child. */
|
/* Couldn't create the message pipe between parent and child. */
|
||||||
*msg = g_strdup_printf("Couldn't create data pipe: %s",
|
errmsg = win32strerror(GetLastError());
|
||||||
win32strerror(GetLastError()));
|
*msg = g_strdup_printf("Couldn't create data pipe: %s", errmsg);
|
||||||
|
g_free(errmsg);
|
||||||
ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
|
ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
|
||||||
CloseHandle(sync_pipe[PIPE_WRITE]);
|
CloseHandle(sync_pipe[PIPE_WRITE]);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -752,8 +760,10 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
|
||||||
/* call dumpcap */
|
/* call dumpcap */
|
||||||
if(!win32_create_process(argv[0], args->str, NULL, NULL, TRUE,
|
if(!win32_create_process(argv[0], args->str, NULL, NULL, TRUE,
|
||||||
CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
|
CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
|
||||||
|
errmsg = win32strerror(GetLastError());
|
||||||
*msg = g_strdup_printf("Couldn't run %s in child process: %s",
|
*msg = g_strdup_printf("Couldn't run %s in child process: %s",
|
||||||
args->str, win32strerror(GetLastError()));
|
args->str, errmsg);
|
||||||
|
g_free(errmsg);
|
||||||
ws_close(*data_read_fd); /* Should close data_pipe[PIPE_READ] */
|
ws_close(*data_read_fd); /* Should close data_pipe[PIPE_READ] */
|
||||||
CloseHandle(data_pipe[PIPE_WRITE]);
|
CloseHandle(data_pipe[PIPE_WRITE]);
|
||||||
ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
|
ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
|
||||||
|
|
|
@ -83,31 +83,58 @@ protect_arg (const gchar *argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate a string for a Win32 error.
|
* Generate a UTF-8 string for a Win32 error.
|
||||||
|
* The string must be freed with g_free().
|
||||||
*/
|
*/
|
||||||
#define ERRBUF_SIZE 1024
|
|
||||||
const char *
|
/*
|
||||||
|
* We make the buffer at least this big, under the assumption that doing
|
||||||
|
* so will reduce the number of reallocations to do. (Otherwise, why
|
||||||
|
* did Microsoft bother supporting a minimum buffer size?)
|
||||||
|
*/
|
||||||
|
#define ERRBUF_SIZE 128
|
||||||
|
char *
|
||||||
win32strerror(DWORD error)
|
win32strerror(DWORD error)
|
||||||
{
|
{
|
||||||
static char errbuf[ERRBUF_SIZE+1];
|
DWORD retval;
|
||||||
size_t errlen;
|
WCHAR *utf16_message;
|
||||||
char *p;
|
char *msg;
|
||||||
|
char *utf8_message;
|
||||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
||||||
NULL, error, 0, errbuf, ERRBUF_SIZE, NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "FormatMessage()" "helpfully" sticks CR/LF at the end of the
|
* XXX - what language ID to use?
|
||||||
* message. Get rid of it.
|
*
|
||||||
|
* For UN*Xes, g_strerror() may or may not return localized strings.
|
||||||
|
*
|
||||||
|
* We currently don't have localized strings, except for GUI items,
|
||||||
|
* but we might want to do so. On the other hand, if most of these
|
||||||
|
* messages are going to be read by Wireshark developers, English
|
||||||
|
* might be a better choice, so the developer doesn't have to get
|
||||||
|
* the message translated if it's in a language they don't happen
|
||||||
|
* to understand. Then again, we're including the error number,
|
||||||
|
* so the developer can just look that up.
|
||||||
*/
|
*/
|
||||||
errlen = strlen(errbuf);
|
retval = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||||
if (errlen >= 2) {
|
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
errbuf[errlen - 1] = '\0';
|
(LPTSTR)&utf16_message, ERRBUF_SIZE, NULL);
|
||||||
errbuf[errlen - 2] = '\0';
|
if (retval == 0) {
|
||||||
|
/* Failed. */
|
||||||
|
msg = g_strdup_printf("Couldn't get error message for error (%lu) (because %lu)",
|
||||||
|
error, GetLastError());
|
||||||
|
return msg;
|
||||||
}
|
}
|
||||||
p = strchr(errbuf, '\0');
|
|
||||||
g_snprintf(p, (gulong)(sizeof errbuf - (p-errbuf)), " (%lu)", error);
|
utf8_message = g_utf16_to_utf8(utf16_message, -1, NULL, NULL, NULL);
|
||||||
return errbuf;
|
LocalFree(utf16_message);
|
||||||
|
if (utf8_message == NULL) {
|
||||||
|
/* Conversion failed. */
|
||||||
|
msg = g_strdup_printf("Couldn't convert error message for error to UTF-8 (%lu) (because %lu)",
|
||||||
|
error, GetLastError());
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
msg = g_strdup_printf("%s (%lu)", utf8_message, error);
|
||||||
|
g_free(utf8_message);
|
||||||
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -162,12 +189,15 @@ win32strexception(DWORD exception)
|
||||||
|
|
||||||
static void win32_kill_child_on_exit(HANDLE child_handle) {
|
static void win32_kill_child_on_exit(HANDLE child_handle) {
|
||||||
static HANDLE cjo_handle = NULL;
|
static HANDLE cjo_handle = NULL;
|
||||||
|
char *errmsg;
|
||||||
if (!cjo_handle) {
|
if (!cjo_handle) {
|
||||||
cjo_handle = CreateJobObject(NULL, _T("Local\\Wireshark child process cleanup"));
|
cjo_handle = CreateJobObject(NULL, _T("Local\\Wireshark child process cleanup"));
|
||||||
|
|
||||||
if (!cjo_handle) {
|
if (!cjo_handle) {
|
||||||
|
errmsg = win32strerror(GetLastError());
|
||||||
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create child cleanup job object: %s",
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create child cleanup job object: %s",
|
||||||
win32strerror(GetLastError()));
|
errmsg);
|
||||||
|
g_free(errmsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,15 +206,19 @@ static void win32_kill_child_on_exit(HANDLE child_handle) {
|
||||||
BOOL sijo_ret = SetInformationJobObject(cjo_handle, JobObjectExtendedLimitInformation,
|
BOOL sijo_ret = SetInformationJobObject(cjo_handle, JobObjectExtendedLimitInformation,
|
||||||
&cjo_jel_info, sizeof(cjo_jel_info));
|
&cjo_jel_info, sizeof(cjo_jel_info));
|
||||||
if (!sijo_ret) {
|
if (!sijo_ret) {
|
||||||
|
errmsg = win32strerror(GetLastError());
|
||||||
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not set child cleanup limits: %s",
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not set child cleanup limits: %s",
|
||||||
win32strerror(GetLastError()));
|
errmsg);
|
||||||
|
g_free(errmsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL aptjo_ret = AssignProcessToJobObject(cjo_handle, child_handle);
|
BOOL aptjo_ret = AssignProcessToJobObject(cjo_handle, child_handle);
|
||||||
if (!aptjo_ret) {
|
if (!aptjo_ret) {
|
||||||
|
errmsg = win32strerror(GetLastError());
|
||||||
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not assign child cleanup process: %s",
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not assign child cleanup process: %s",
|
||||||
win32strerror(GetLastError()));
|
errmsg);
|
||||||
|
g_free(errmsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,13 +48,14 @@ extern "C" {
|
||||||
WS_DLL_PUBLIC
|
WS_DLL_PUBLIC
|
||||||
gchar * protect_arg (const gchar *argv);
|
gchar * protect_arg (const gchar *argv);
|
||||||
|
|
||||||
/** Generate a string for a Win32 error.
|
/** Generate a string for a Windows error.
|
||||||
*
|
*
|
||||||
* @param error The windows error code
|
* @param error The Windows error code
|
||||||
* @return a localized string containing the corresponding error message
|
* @return a localized UTF-8 string containing the corresponding error message;
|
||||||
|
* it must be freed with g_free().
|
||||||
*/
|
*/
|
||||||
WS_DLL_PUBLIC
|
WS_DLL_PUBLIC
|
||||||
const char * win32strerror(DWORD error);
|
char * win32strerror(DWORD error);
|
||||||
|
|
||||||
/** Generate a string for a Win32 exception code.
|
/** Generate a string for a Win32 exception code.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue