Use wide version of Windows APIs (#1531)

* Use wide version of Windows APIs in subprocess functions
* Use `wmain` on Windows to get UTF16 arguments
* Use wide version of APIs in `rz_cons`
* Always try to set console codepage to UTF8

Co-authored-by: Riccardo Schirone <ret2libc@users.noreply.github.com>
This commit is contained in:
GustavoLCR 2021-08-27 04:23:26 -03:00 committed by GitHub
parent 4972af951f
commit d7e7bae79e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 193 additions and 93 deletions

View file

@ -4,13 +4,15 @@
#include <rz_main.h>
#include <rz_util.h>
int main(int argc, char **argv) {
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int rc = 1;
const char *prog_name = rz_file_basename(argv[0]);
const char *prog_name = rz_file_basename(utf8_argv[0]);
RzMain *m = rz_main_new(prog_name);
if (m) {
rc = rz_main_run(m, argc, argv);
rc = rz_main_run(m, argc, (const char **)utf8_argv);
rz_main_free(m);
}
UTF8_ARGV_FREE(argc, utf8_argv);
return rc;
}

View file

@ -48,9 +48,14 @@ static int rz_main_rzpipe(int argc, const char **argv) {
return rc;
}
int main(int argc, const char **argv) {
if (argc > 0 && strstr(argv[0], "rzp")) {
return rz_main_rzpipe(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret;
if (argc > 0 && strstr(utf8_argv[0], "rzp")) {
ret = rz_main_rzpipe(argc, (const char **)utf8_argv);
} else {
ret = rz_main_rizin(argc, (const char **)utf8_argv);
}
return rz_main_rizin(argc, argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char **argv) {
return rz_main_rz_agent(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_agent(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char *argv[]) {
return rz_main_rz_asm(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_asm(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char *argv[]) {
return rz_main_rz_ax(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_ax(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char **argv) {
return rz_main_rz_bin(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_bin(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char *argv[]) {
return rz_main_rz_diff(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_diff(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char **argv) {
return rz_main_rz_find(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_find(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char **argv) {
return rz_main_rz_gg(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_gg(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char **argv) {
return rz_main_rz_hash(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_hash(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char **argv) {
return rz_main_rz_run(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_run(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -3,6 +3,9 @@
#include <rz_main.h>
int main(int argc, const char **argv) {
return rz_main_rz_sign(argc, argv);
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_main_rz_sign(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -4,6 +4,7 @@
#include "rz_test.h"
#include <assert.h>
#include <rz_cons.h>
#include <rz_main.h>
#define Color_INSERT Color_BGREEN
#define Color_DELETE Color_BRED
@ -169,7 +170,7 @@ static bool rz_test_chdir_fromtest(const char *test_path) {
return found;
}
int main(int argc, char **argv) {
int rz_test_main(int argc, const char **argv) {
int workers_count = WORKERS_DEFAULT;
bool verbose = false;
bool nothing = false;
@ -1082,3 +1083,10 @@ static void interact_commands(RzTestResultInfo *result, RzPVector *fixup_results
free(name);
free(newcmds);
}
int MAIN_NAME(int argc, const ARGV_TYPE **argv) {
char **utf8_argv = ARGV_TYPE_TO_UTF8(argc, argv);
int ret = rz_test_main(argc, (const char **)utf8_argv);
FREE_UTF8_ARGV(argc, utf8_argv);
return ret;
}

View file

@ -528,6 +528,30 @@ RZ_API bool rz_cons_enable_mouse(const bool enable) {
#endif
}
#if __WINDOWS__
static void set_console_codepage_to_utf8(void) {
if (IsValidCodePage(CP_UTF8)) {
if (!SetConsoleOutputCP(CP_UTF8)) {
rz_sys_perror("SetConsoleCP");
}
if (!SetConsoleCP(CP_UTF8)) {
rz_sys_perror("SetConsoleCP");
}
} else {
RZ_LOG_INFO("UTF-8 Codepage not installed.\n");
}
}
static void restore_console_codepage(void) {
if (!SetConsoleCP(I.old_cp)) {
rz_sys_perror("SetConsoleCP");
}
if (!SetConsoleOutputCP(I.old_ocp)) {
rz_sys_perror("SetConsoleOutputCP");
}
}
#endif
// Stub function that cb_main_output gets pointed to in util/log.c by rz_cons_new
// This allows Cutter to set per-task logging redirection
RZ_API RzCons *rz_cons_new(void) {
@ -563,8 +587,10 @@ RZ_API RzCons *rz_cons_new(void) {
I.num = NULL;
I.null = 0;
#if __WINDOWS__
I.old_cp = GetConsoleOutputCP();
I.old_cp = GetConsoleCP();
I.old_ocp = GetConsoleOutputCP();
I.vtmode = rz_cons_is_vtcompat();
set_console_codepage_to_utf8();
#else
I.vtmode = 2;
#endif
@ -601,11 +627,7 @@ RZ_API RzCons *rz_cons_new(void) {
RZ_API RzCons *rz_cons_free(void) {
#if __WINDOWS__
rz_cons_enable_mouse(false);
if (I.old_cp) {
(void)SetConsoleOutputCP(I.old_cp);
// chcp doesn't pick up the code page switch for some reason
(void)rz_sys_cmdf("chcp %u > NUL", I.old_cp);
}
restore_console_codepage();
#endif
I.refcnt--;
if (I.refcnt != 0) {
@ -1600,30 +1622,6 @@ RZ_API void rz_cons_set_raw(bool is_raw) {
RZ_API void rz_cons_set_utf8(bool b) {
I.use_utf8 = b;
#if __WINDOWS__
if (b) {
if (IsValidCodePage(CP_UTF8)) {
if (!SetConsoleOutputCP(CP_UTF8)) {
rz_sys_perror("rz_cons_set_utf8");
}
#if UNICODE
UINT inCP = CP_UTF8;
#else
UINT inCP = GetACP();
#endif
if (!SetConsoleCP(inCP)) {
rz_sys_perror("rz_cons_set_utf8");
}
} else {
RZ_LOG_WARN("UTF-8 Codepage not installed.\n");
}
} else {
UINT acp = GetACP();
if (!SetConsoleCP(acp) || !SetConsoleOutputCP(acp)) {
rz_sys_perror("rz_cons_set_utf8");
}
}
#endif
}
RZ_API void rz_cons_invert(int set, int color) {

View file

@ -243,7 +243,7 @@ do_it_again:
if (rz_cons_singleton()->term_xterm) {
ret = ReadFile(h, buf, 1, &out, NULL);
} else {
ret = ReadConsoleInput(h, &irInBuf, 1, &out);
ret = ReadConsoleInputW(h, &irInBuf, 1, &out);
}
rz_cons_sleep_end(bed);
if (ret < 1) {
@ -252,7 +252,7 @@ do_it_again:
if (irInBuf.EventType == KEY_EVENT) {
if (irInBuf.Event.KeyEvent.bKeyDown) {
if (irInBuf.Event.KeyEvent.uChar.UnicodeChar) {
char *tmp = rz_sys_conv_win_to_utf8_l((PTCHAR)&irInBuf.Event.KeyEvent.uChar, 1);
char *tmp = rz_utf16_to_utf8_l(&irInBuf.Event.KeyEvent.uChar.UnicodeChar, 1);
if (!tmp) {
return 0;
}
@ -1531,15 +1531,11 @@ RZ_API const char *rz_line_readline_cb(RzLineReadCallback cb, void *user) {
HANDLE hClipBoard;
PTCHAR clipText;
if (OpenClipboard(NULL)) {
#if UNICODE
hClipBoard = GetClipboardData(CF_UNICODETEXT);
#else
hClipBoard = GetClipboardData(CF_TEXT);
#endif
if (hClipBoard) {
clipText = GlobalLock(hClipBoard);
if (clipText) {
char *txt = rz_sys_conv_win_to_utf8(clipText);
char *txt = rz_utf16_to_utf8(clipText);
if (!txt) {
RZ_LOG_ERROR("Failed to allocate memory\n");
break;

View file

@ -462,7 +462,7 @@ static int __cons_readchar_w32(ut32 usec) {
return ch;
}
} else {
ret = ReadConsoleInput(h, &irInBuf, 1, &out);
ret = ReadConsoleInputW(h, &irInBuf, 1, &out);
}
rz_cons_sleep_end(bed);
if (ret) {
@ -504,9 +504,15 @@ static int __cons_readchar_w32(ut32 usec) {
if (irInBuf.EventType == KEY_EVENT) {
if (irInBuf.Event.KeyEvent.bKeyDown) {
ch = irInBuf.Event.KeyEvent.uChar.AsciiChar;
bCtrl = irInBuf.Event.KeyEvent.dwControlKeyState & 8;
if (irInBuf.Event.KeyEvent.uChar.AsciiChar == 0) {
if (irInBuf.Event.KeyEvent.uChar.UnicodeChar) {
char *tmp = rz_utf16_to_utf8_l(&irInBuf.Event.KeyEvent.uChar.UnicodeChar, 1);
if (tmp) {
int len = strlen(tmp);
memcpy(&ch, tmp, R_MIN(len, sizeof(ch)));
free(tmp);
}
} else {
switch (irInBuf.Event.KeyEvent.wVirtualKeyCode) {
case VK_DOWN: // key down
case VK_RIGHT: // key right

View file

@ -17,6 +17,7 @@ extern "C" {
#include <rz_util/rz_str.h>
#include <rz_util/rz_str_constpool.h>
#include <rz_util/rz_sys.h>
#include <rz_util/rz_utf8.h>
#include <rz_util/rz_file.h>
#include <rz_vector.h>
#include <sdb.h>
@ -520,6 +521,7 @@ typedef struct rz_cons_t {
#elif __WINDOWS__
DWORD term_raw, term_buf, term_xterm;
UINT old_cp;
UINT old_ocp;
#endif
RNum *num;
/* Pager (like more or less) to use if the output doesn't fit on the

View file

@ -15,6 +15,18 @@ typedef struct rz_main_t {
// stdin/stdout
} RzMain;
#if __WINDOWS__
#define MAIN_NAME wmain
#define ARGV_TYPE wchar_t
#define ARGV_TYPE_TO_UTF8(argc, argv) rz_sys_utf8_argv_new(argc, argv)
#define FREE_UTF8_ARGV(argc, utf8_argv) rz_sys_utf8_argv_free(argc, utf8_argv)
#else
#define MAIN_NAME main
#define ARGV_TYPE char
#define ARGV_TYPE_TO_UTF8(argc, argv) (char **)argv
#define FREE_UTF8_ARGV(argc, utf8_argv)
#endif
typedef int (*RzMainCallback)(int argc, const char **argv);
RZ_API RzMain *rz_main_new(const char *name);

View file

@ -126,6 +126,8 @@ RZ_API int rz_sys_cmd_str_full(const char *cmd, const char *input, char **output
RZ_API char *rz_sys_get_src_dir_w32(void);
RZ_API bool rz_sys_cmd_str_full_w32(const char *cmd, const char *input, char **output, int *outlen, char **sterr);
RZ_API bool rz_sys_create_child_proc_w32(const char *cmdline, HANDLE in, HANDLE out, HANDLE err);
RZ_API char **rz_sys_utf8_argv_new(int argc, const wchar_t **argv);
RZ_API void rz_sys_utf8_argv_free(int argc, char **utf8_argv);
#endif
RZ_API int rz_sys_open_perms(int rizin_perms);
RZ_API int rz_sys_open(const char *path, int perm, int mode);

View file

@ -25,19 +25,19 @@ static bool create_pipe_overlap(HANDLE *pipe_read, HANDLE *pipe_write, LPSECURIT
if (!sz) {
sz = 4096;
}
char name[MAX_PATH];
snprintf(name, sizeof(name), "\\\\.\\pipe\\rz-pipe-subproc.%d.%ld", (int)GetCurrentProcessId(), (long)InterlockedIncrement(&pipe_id));
*pipe_read = CreateNamedPipeA(name, PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, sz, sz, 120 * 1000, attrs);
WCHAR name[MAX_PATH];
_snwprintf_s(name, _countof(name), sizeof(name), L"\\\\.\\pipe\\rz-pipe-subproc.%d.%ld", (int)GetCurrentProcessId(), (long)InterlockedIncrement(&pipe_id));
*pipe_read = CreateNamedPipeW(name, PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, sz, sz, 120 * 1000, attrs);
if (!*pipe_read) {
return FALSE;
}
*pipe_write = CreateFileA(name, GENERIC_WRITE, 0, attrs, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | write_mode, NULL);
*pipe_write = CreateFileW(name, GENERIC_WRITE, 0, attrs, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | write_mode, NULL);
if (*pipe_write == INVALID_HANDLE_VALUE) {
CloseHandle(*pipe_read);
return FALSE;
}
SetEnvironmentVariable(TEXT("RZ_PIPE_PATH"), name);
SetEnvironmentVariableW(L"RZ_PIPE_PATH", name);
return true;
}
@ -45,7 +45,7 @@ RZ_API bool rz_subprocess_init(void) {
return true;
}
RZ_API void rz_subprocess_fini(void) {
SetEnvironmentVariable(TEXT("RZ_PIPE_PATH"), NULL);
SetEnvironmentVariableW(L"RZ_PIPE_PATH", NULL);
}
// Create an env block that inherits the current vars but overrides the given ones
@ -141,18 +141,31 @@ RZ_API RzSubprocess *rz_subprocess_start_opt(RzSubprocessOpt *opt) {
HANDLE stdin_read = GetStdHandle(STD_INPUT_HANDLE);
HANDLE stdout_write = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE stderr_write = GetStdHandle(STD_ERROR_HANDLE);
LPSTR lpFilePart;
char cmd_exe[MAX_PATH];
LPWSTR lpFilePart;
WCHAR cmd_exe[MAX_PATH];
if (!rz_file_exists(opt->file) && NeedCurrentDirectoryForExePathA(opt->file)) {
PWCHAR file = rz_utf8_to_utf16(opt->file);
if (!file) {
return NULL;
}
if (!rz_file_exists(opt->file) && NeedCurrentDirectoryForExePathW(file)) {
DWORD len;
if ((len = SearchPath(NULL, opt->file, ".exe", sizeof(cmd_exe), cmd_exe, &lpFilePart)) < 1) {
if ((len = SearchPathW(NULL, file, L".exe", _countof(cmd_exe), cmd_exe, &lpFilePart)) < 1) {
RZ_LOG_DEBUG("SearchPath failed for %s\n", opt->file);
free(file);
return NULL;
}
} else {
snprintf(cmd_exe, sizeof(cmd_exe), "%s", opt->file);
WCHAR *tmp = rz_utf8_to_utf16(opt->file);
if (!tmp) {
free(file);
return NULL;
}
_snwprintf_s(cmd_exe, _countof(cmd_exe), sizeof(cmd_exe), L"%s", tmp);
free(tmp);
}
free(file);
char **argv = calloc(opt->args_size + 1, sizeof(char *));
if (!argv) {
@ -162,11 +175,23 @@ RZ_API RzSubprocess *rz_subprocess_start_opt(RzSubprocessOpt *opt) {
if (opt->args_size) {
memcpy(argv + 1, opt->args, sizeof(char *) * opt->args_size);
}
char *cmdline = rz_str_format_msvc_argv(opt->args_size + 1, argv);
char *cmd = rz_str_format_msvc_argv(opt->args_size + 1, argv);
free(argv);
if (!cmdline) {
if (!cmd) {
return NULL;
}
PWCHAR cmdline = rz_utf8_to_utf16(cmd);
if (!cmdline) {
goto error;
}
{
char *log_executable = rz_utf16_to_utf8(cmd_exe);
if (log_executable) {
RZ_LOG_DEBUG("%s%s\n", log_executable, cmd);
free(log_executable);
}
}
proc = RZ_NEW0(RzSubprocess);
if (!proc) {
@ -215,7 +240,7 @@ RZ_API RzSubprocess *rz_subprocess_start_opt(RzSubprocessOpt *opt) {
}
PROCESS_INFORMATION proc_info = { 0 };
STARTUPINFOA start_info = { 0 };
STARTUPINFOW start_info = { 0 };
start_info.cb = sizeof(start_info);
start_info.hStdError = stderr_write;
start_info.hStdOutput = stdout_write;
@ -223,8 +248,7 @@ RZ_API RzSubprocess *rz_subprocess_start_opt(RzSubprocessOpt *opt) {
start_info.dwFlags = STARTF_USESTDHANDLES;
LPWSTR env = override_env(opt->envvars, opt->envvals, opt->env_size);
RZ_LOG_DEBUG("%s%s\n", cmd_exe, cmdline);
if (!CreateProcessA(
if (!CreateProcessW(
cmd_exe, // exe
cmdline, // command line
NULL, // process security attributes
@ -236,12 +260,7 @@ RZ_API RzSubprocess *rz_subprocess_start_opt(RzSubprocessOpt *opt) {
&start_info, // STARTUPINFO pointer
&proc_info)) { // receives PROCESS_INFORMATION
free(env);
char err_msg[256];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
err_msg, sizeof(err_msg), NULL);
RZ_LOG_ERROR("CreateProcess failed: %#x %s\n", (int)GetLastError(), err_msg);
rz_sys_perror("CreateProcess");
goto error;
}
free(env);
@ -251,13 +270,13 @@ RZ_API RzSubprocess *rz_subprocess_start_opt(RzSubprocessOpt *opt) {
beach:
if (stdin_read != GetStdHandle(STD_INPUT_HANDLE)) {
if (stdin_read && stdin_read != GetStdHandle(STD_INPUT_HANDLE)) {
CloseHandle(stdin_read);
}
if (stderr_write != GetStdHandle(STD_ERROR_HANDLE) && stderr_write != stdout_write) {
if (stderr_write && stderr_write != GetStdHandle(STD_ERROR_HANDLE) && stderr_write != stdout_write) {
CloseHandle(stderr_write);
}
if (stdout_write != GetStdHandle(STD_OUTPUT_HANDLE)) {
if (stdout_write && stdout_write != GetStdHandle(STD_OUTPUT_HANDLE)) {
CloseHandle(stdout_write);
}
free(cmdline);

View file

@ -200,4 +200,24 @@ char *ReadFromPipe(HANDLE fh, int *outlen) {
}
return str;
}
RZ_API char **rz_sys_utf8_argv_new(int argc, const wchar_t **argv) {
char **utf8_argv = calloc(argc + 1, sizeof(wchar_t *));
if (!utf8_argv) {
return NULL;
}
int i;
for (i = 0; i < argc; i++) {
utf8_argv[i] = rz_utf16_to_utf8(argv[i]);
}
return utf8_argv;
}
RZ_API void rz_sys_utf8_argv_free(int argc, char **utf8_argv) {
int i;
for (i = 0; i < argc; i++) {
free(utf8_argv[i]);
}
free(utf8_argv);
}
#endif