1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 19:19:53 +00:00

Work to replace os.execute command with something safe.

This commit is contained in:
Calvin Rose 2018-07-06 21:50:59 -04:00
parent bfd0c08c8f
commit f63d08efbd
2 changed files with 137 additions and 23 deletions

View File

@ -343,9 +343,13 @@ static void dst_quick_asm(
dst_env_def(env, name, dst_wrap_function(dst_thunk(def))); 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 SSS(op, a, b, c) (op | (a << 8) | (b << 16) | (c << 24))
#define SS(op, a, b) SSS(op, a, b, 0) #define SS(op, a, b) (op | (a << 8) | (b << 16))
#define S(op, a) SSS(op, a, 0, 0) #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. */ /* Variadic operator assembly. Must be templatized for each different opcode. */
/* Reg 0: Argument tuple (args) */ /* Reg 0: Argument tuple (args) */
/* Reg 1: Argument count (argn) */ /* Reg 1: Argument count (argn) */
@ -354,36 +358,37 @@ static void dst_quick_asm(
/* Reg 4: Next operand (operand) */ /* Reg 4: Next operand (operand) */
/* Reg 5: Loop iterator (i) */ /* Reg 5: Loop iterator (i) */
static DST_THREAD_LOCAL uint32_t varop_asm[] = { 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 */ /* Check nullary */
DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (0 << 24), /* Check if numargs equal to 0 */ SSS(DOP_EQUALS_IMMEDIATE, 2, 1, 0), /* Check if numargs equal to 0 */
DOP_JUMP_IF_NOT | (2 << 8) | (3 << 16), /* If not 0, jump to next check */ SI(DOP_JUMP_IF_NOT, 2, 3), /* If not 0, jump to next check */
/* Nullary */ /* Nullary */
DOP_LOAD_INTEGER | (3 << 8), /* accum = nullary value */ SI(DOP_LOAD_INTEGER, 3, 0), /* accum = nullary value */
DOP_RETURN | (3 << 8), /* return accum */ S(DOP_RETURN, 3), /* return accum */
/* Check unary */ /* Check unary */
DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (1 << 24), /* Check if numargs equal to 1 */ SSI(DOP_EQUALS_IMMEDIATE, 2, 1, 1), /* Check if numargs equal to 1 */
DOP_JUMP_IF_NOT | (2 << 8) | (5 << 16), /* If not 1, jump to next check */ SI(DOP_JUMP_IF_NOT, 2, 5), /* If not 1, jump to next check */
/* Unary */ /* Unary */
DOP_LOAD_INTEGER | (3 << 8), /* accum = unary value */ S(DOP_LOAD_INTEGER, 3), /* accum = unary value */
DOP_GET_INDEX | (4 << 8) | (0 << 16) | (0 << 24), /* operand = args[0] */ SSI(DOP_GET_INDEX, 4, 0, 0), /* operand = args[0] */
DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */ SSS(DOP_NOOP, 3, 3, 4), /* accum = accum op operand */
DOP_RETURN | (3 << 8), /* return accum */ S(DOP_RETURN, 3), /* return accum */
/* Mutli (2 or more) arity */ /* Mutli (2 or more) arity */
/* Prime loop */ /* Prime loop */
DOP_GET_INDEX | (3 << 8) | (0 << 16) | (0 << 24), /* accum = args[0] */ SSI(DOP_GET_INDEX, 3, 0, 0), /* accum = args[0] */
DOP_LOAD_INTEGER | (5 << 8) | (1 << 16), /* i = 1 */ SI(DOP_LOAD_INTEGER, 5, 1), /* i = 1 */
/* Main loop */ /* Main loop */
DOP_GET | (4 << 8) | (0 << 16) | (5 << 24), /* operand = args[i] */ SSS(DOP_GET, 4, 0, 5), /* operand = args[i] */
DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */ SSS(DOP_NOOP, 3, 3, 4), /* accum = accum op operand */
DOP_ADD_IMMEDIATE | (5 << 8) | (5 << 16) | (1 << 24), /* i++ */ SSI(DOP_ADD_IMMEDIATE, 5, 5, 1), /* i++ */
DOP_EQUALS_INTEGER | (2 << 8) | (5 << 16) | (1 << 24), /* jump? = (i == argn) */ SSI(DOP_EQUALS_INTEGER, 2, 5, 1), /* jump? = (i == argn) */
DOP_JUMP_IF_NOT | (2 << 8) | ((uint32_t)(-4) << 16), /* if not jump? go back 4 */ SI(DOP_JUMP_IF_NOT, 2, -4), /* if not jump? go back 4 */
/* Done, do last and return accumulator */ /* Done, do last and return accumulator */
DOP_RETURN | (3 << 8) /* return accum */ S(DOP_RETURN, 3) /* return accum */
}; };
#define VAROP_NULLARY_LOC 3 #define VAROP_NULLARY_LOC 3

View File

@ -29,9 +29,112 @@
#include <direct.h> #include <direct.h>
#else #else
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#endif #endif
#ifdef DST_WINDOWS
static int os_execute(DstArgs args) { 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)); int nofirstarg = (args.n < 1 || !dst_checktype(args.v[0], DST_STRING));
const char *cmd = nofirstarg const char *cmd = nofirstarg
? NULL ? NULL
@ -107,7 +210,12 @@ static int os_sleep(DstArgs args) {
#ifdef DST_WINDOWS #ifdef DST_WINDOWS
Sleep((DWORD) (delay * 1000)); Sleep((DWORD) (delay * 1000));
#else #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 #endif
return 0; return 0;
} }
@ -129,6 +237,7 @@ static int os_cwd(DstArgs args) {
static const DstReg cfuns[] = { static const DstReg cfuns[] = {
{"os.execute", os_execute}, {"os.execute", os_execute},
{"os.shell", os_shell},
{"os.exit", os_exit}, {"os.exit", os_exit},
{"os.getenv", os_getenv}, {"os.getenv", os_getenv},
{"os.setenv", os_setenv}, {"os.setenv", os_setenv},