From f63d08efbd7409670cd546e702bf4ec4048da94d Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Fri, 6 Jul 2018 21:50:59 -0400 Subject: [PATCH] Work to replace os.execute command with something safe. --- src/core/corelib.c | 49 +++++++++++--------- src/core/os.c | 111 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 137 insertions(+), 23 deletions(-) diff --git a/src/core/corelib.c b/src/core/corelib.c index 663eacc7..a9805c53 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -343,9 +343,13 @@ static void dst_quick_asm( dst_env_def(env, name, dst_wrap_function(dst_thunk(def))); } +/* Macros for easier inline dst assembly */ #define SSS(op, a, b, c) (op | (a << 8) | (b << 16) | (c << 24)) -#define SS(op, a, b) SSS(op, a, b, 0) -#define S(op, a) SSS(op, a, 0, 0) +#define SS(op, a, b) (op | (a << 8) | (b << 16)) +#define SSI(op, a, b, I) (op | (a << 8) | (b << 16) | ((uint32_t)(I) << 24)) +#define S(op, a) (op | (a << 8)) +#define SI(op, a, I) (op | (a << 8) | ((uint32_t)(I) << 16)) + /* Variadic operator assembly. Must be templatized for each different opcode. */ /* Reg 0: Argument tuple (args) */ /* Reg 1: Argument count (argn) */ @@ -354,36 +358,37 @@ static void dst_quick_asm( /* Reg 4: Next operand (operand) */ /* Reg 5: Loop iterator (i) */ static DST_THREAD_LOCAL uint32_t varop_asm[] = { - DOP_LENGTH | (1 << 8), /* Put number of arguments in register 1 -> argn = count(args) */ + SS(DOP_LENGTH, 1, 0), /* Put number of arguments in register 1 -> argn = count(args) */ - /* Cheack nullary */ - DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (0 << 24), /* Check if numargs equal to 0 */ - DOP_JUMP_IF_NOT | (2 << 8) | (3 << 16), /* If not 0, jump to next check */ + /* Check nullary */ + SSS(DOP_EQUALS_IMMEDIATE, 2, 1, 0), /* Check if numargs equal to 0 */ + SI(DOP_JUMP_IF_NOT, 2, 3), /* If not 0, jump to next check */ /* Nullary */ - DOP_LOAD_INTEGER | (3 << 8), /* accum = nullary value */ - DOP_RETURN | (3 << 8), /* return accum */ + SI(DOP_LOAD_INTEGER, 3, 0), /* accum = nullary value */ + S(DOP_RETURN, 3), /* return accum */ /* Check unary */ - DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (1 << 24), /* Check if numargs equal to 1 */ - DOP_JUMP_IF_NOT | (2 << 8) | (5 << 16), /* If not 1, jump to next check */ + SSI(DOP_EQUALS_IMMEDIATE, 2, 1, 1), /* Check if numargs equal to 1 */ + SI(DOP_JUMP_IF_NOT, 2, 5), /* If not 1, jump to next check */ /* Unary */ - DOP_LOAD_INTEGER | (3 << 8), /* accum = unary value */ - DOP_GET_INDEX | (4 << 8) | (0 << 16) | (0 << 24), /* operand = args[0] */ - DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */ - DOP_RETURN | (3 << 8), /* return accum */ + S(DOP_LOAD_INTEGER, 3), /* accum = unary value */ + SSI(DOP_GET_INDEX, 4, 0, 0), /* operand = args[0] */ + SSS(DOP_NOOP, 3, 3, 4), /* accum = accum op operand */ + S(DOP_RETURN, 3), /* return accum */ /* Mutli (2 or more) arity */ /* Prime loop */ - DOP_GET_INDEX | (3 << 8) | (0 << 16) | (0 << 24), /* accum = args[0] */ - DOP_LOAD_INTEGER | (5 << 8) | (1 << 16), /* i = 1 */ + SSI(DOP_GET_INDEX, 3, 0, 0), /* accum = args[0] */ + SI(DOP_LOAD_INTEGER, 5, 1), /* i = 1 */ /* Main loop */ - DOP_GET | (4 << 8) | (0 << 16) | (5 << 24), /* operand = args[i] */ - DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */ - DOP_ADD_IMMEDIATE | (5 << 8) | (5 << 16) | (1 << 24), /* i++ */ - DOP_EQUALS_INTEGER | (2 << 8) | (5 << 16) | (1 << 24), /* jump? = (i == argn) */ - DOP_JUMP_IF_NOT | (2 << 8) | ((uint32_t)(-4) << 16), /* if not jump? go back 4 */ + SSS(DOP_GET, 4, 0, 5), /* operand = args[i] */ + SSS(DOP_NOOP, 3, 3, 4), /* accum = accum op operand */ + SSI(DOP_ADD_IMMEDIATE, 5, 5, 1), /* i++ */ + SSI(DOP_EQUALS_INTEGER, 2, 5, 1), /* jump? = (i == argn) */ + SI(DOP_JUMP_IF_NOT, 2, -4), /* if not jump? go back 4 */ + /* Done, do last and return accumulator */ - DOP_RETURN | (3 << 8) /* return accum */ + S(DOP_RETURN, 3) /* return accum */ }; #define VAROP_NULLARY_LOC 3 diff --git a/src/core/os.c b/src/core/os.c index 89cc6ab4..b7582208 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -29,9 +29,112 @@ #include #else #include +#include +#include +#include #endif +#ifdef DST_WINDOWS static int os_execute(DstArgs args) { + DST_MINARITY(args, 1); + DstBuffer *buffer = dst_buffer(10); + for (int32_t i = 0; i < args.n; i++) { + const uint8_t *argstring; + DST_ARG_STRING(argstring, args, i); + dst_buffer_push_bytes(buffer, argstring, dst_string_length(argstring)); + if (i != args.n - 1) { + dst_buffer_push_u8(buffer, ' '); + } + } + dst_buffer_push_u8(buffer, 0); + + /* Convert to wide chars */ + wchar_t *sys_str = malloc(buffer->count * sizeof(wchar_t)); + if (NULL == sys_str) { + DST_OUT_OF_MEMORY; + } + int nwritten = MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + buffer->data, + buffer->count, + sys_str, + buffer->count); + if (nwritten == 0) { + free(sys_str); + DST_THROW(args, "could not create process"); + } + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + // Start the child process. + if(!CreateProcess(NULL, + sys_str, + NULL, + NULL, + FALSE, + 0, + NULL, + NULL, + &si, + &pi)) { + free(sys_str); + DST_THROW(args, "could not create process"); + } + free(sys_str); + + // Wait until child process exits. + WaitForSingleObject(pi.hProcess, INFINITE); + + // Close process and thread handles. + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + DST_RETURN_INTEGER(args, 0); +} +#else +static int os_execute(DstArgs args) { + DST_MINARITY(args, 1); + const uint8_t **argv = malloc(sizeof(uint8_t *) * (args.n + 1)); + if (NULL == argv) { + DST_OUT_OF_MEMORY; + } + for (int32_t i = 0; i < args.n; i++) { + DST_ARG_STRING(argv[i], args, i); + } + argv[args.n] = NULL; + + /* Fork child process */ + pid_t pid; + if (0 == (pid = fork())) { + if (-1 == execve((const char *)argv[0], (char **)argv, NULL)) { + exit(1); + } + } + + /* Wait for child process */ + int status; + struct timespec waiter; + waiter.tv_sec = 0; + waiter.tv_nsec = 200; + while (0 == waitpid(pid, &status, WNOHANG)) { + waiter.tv_nsec = (waiter.tv_nsec * 3) / 2; + /* Keep increasing sleep time by a factor of 3/2 + * until a maximum */ + if (waiter.tv_nsec > 4999999) + waiter.tv_nsec = 5000000; + nanosleep(&waiter, NULL); + } + + DST_RETURN_INTEGER(args, status); +} +#endif + +static int os_shell(DstArgs args) { int nofirstarg = (args.n < 1 || !dst_checktype(args.v[0], DST_STRING)); const char *cmd = nofirstarg ? NULL @@ -107,7 +210,12 @@ static int os_sleep(DstArgs args) { #ifdef DST_WINDOWS Sleep((DWORD) (delay * 1000)); #else - usleep((useconds_t)(delay * 1000000)); + struct timespec ts; + ts.tv_sec = (time_t) delay; + ts.tv_nsec = (delay <= UINT32_MAX) + ? (long)((delay - ((uint32_t)delay)) * 1000000000) + : 0; + nanosleep(&ts, NULL); #endif return 0; } @@ -129,6 +237,7 @@ static int os_cwd(DstArgs args) { static const DstReg cfuns[] = { {"os.execute", os_execute}, + {"os.shell", os_shell}, {"os.exit", os_exit}, {"os.getenv", os_getenv}, {"os.setenv", os_setenv},