mirror of
https://github.com/janet-lang/janet
synced 2024-11-25 01:37:19 +00:00
Work to replace os.execute command with something safe.
This commit is contained in:
parent
bfd0c08c8f
commit
f63d08efbd
@ -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
|
||||
|
111
src/core/os.c
111
src/core/os.c
@ -29,9 +29,112 @@
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#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},
|
||||
|
Loading…
Reference in New Issue
Block a user