From a18a251d16f75b166330a595d3add7b151117b6c Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Thu, 10 Oct 2019 22:59:43 -0500 Subject: [PATCH] Address some issues found in lgtm Caught a few potentially issues with overflows, as well as use of unsafe function localtime. --- src/boot/boot.janet | 17 +++- src/core/array.c | 2 +- src/core/buffer.c | 2 +- src/core/os.c | 8 +- src/core/vector.c | 3 +- src/core/vm.c | 6 +- src/mainclient/line.c | 182 ++++++++++++++++++++++-------------------- 7 files changed, 122 insertions(+), 98 deletions(-) diff --git a/src/boot/boot.janet b/src/boot/boot.janet index 021628d5..97d4df2d 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -1668,7 +1668,8 @@ :on-compile-error - callback when compilation fails - default is bad-compile\n\t :compile-only - only compile the source, do not execute it - default is false\n\t :on-status - callback when a value is evaluated - default is debug/stacktrace\n\t - :fiber-flags - what flags to wrap the compilation fiber with. Default is :ia." + :fiber-flags - what flags to wrap the compilation fiber with. Default is :ia.\n\t + :expander - an optional function that is called on each top level form before being compiled." [opts] (def {:env env @@ -1678,7 +1679,8 @@ :on-parse-error on-parse-error :fiber-flags guard :compile-only compile-only - :source where} opts) + :source where + :expander expand} opts) (default env (fiber/getenv (fiber/current))) (default chunks (fn [buf p] (getline "" buf))) (default compile-only false) @@ -1695,6 +1697,7 @@ # Evaluate 1 source form in a protected manner (defn eval1 [source] + (def source (if expand (expand source) source)) (var good true) (def f (fiber/new @@ -1718,6 +1721,7 @@ # Loop (def buf @"") (while going + (if (env :exit) (break)) (buffer/clear buf) (chunks buf p) (var pindex 0) @@ -1740,6 +1744,13 @@ env) +(defn quit + "Tries to exit from the current repl or context. Does not always exit the application. + Works by setting the :exit dynamic binding to true." + [] + (setdyn :exit true) + "Bye!") + (defn eval-string "Evaluates a string in the current environment. If more control over the environment is needed, use run-context." @@ -2005,7 +2016,7 @@ (debug/stacktrace f x) (print ``` -entering debugger - Ctrl-D to exit +entering debugger - (quit) or Ctrl-D to exit _fiber is bound to the suspended fiber ```) diff --git a/src/core/array.c b/src/core/array.c index 39acff80..b560fcae 100644 --- a/src/core/array.c +++ b/src/core/array.c @@ -64,7 +64,7 @@ void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t growth) { Janet *newData; Janet *old = array->data; if (capacity <= array->capacity) return; - int64_t new_capacity = capacity * growth; + int64_t new_capacity = ((int64_t) capacity) * growth; if (new_capacity > INT32_MAX) new_capacity = INT32_MAX; capacity = (int32_t) new_capacity; newData = realloc(old, capacity * sizeof(Janet)); diff --git a/src/core/buffer.c b/src/core/buffer.c index b88326b4..3d70ace2 100644 --- a/src/core/buffer.c +++ b/src/core/buffer.c @@ -59,7 +59,7 @@ void janet_buffer_ensure(JanetBuffer *buffer, int32_t capacity, int32_t growth) uint8_t *new_data; uint8_t *old = buffer->data; if (capacity <= buffer->capacity) return; - int64_t big_capacity = capacity * growth; + int64_t big_capacity = ((int64_t) capacity) * growth; capacity = big_capacity > INT32_MAX ? INT32_MAX : (int32_t) big_capacity; janet_vm_next_collection += capacity - buffer->capacity; new_data = realloc(old, capacity * sizeof(uint8_t)); diff --git a/src/core/os.c b/src/core/os.c index c7530bd5..b92e26d4 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -477,13 +477,19 @@ static Janet os_date(int32_t argc, Janet *argv) { janet_arity(argc, 0, 1); (void) argv; time_t t; + struct tm t_infos; struct tm *t_info; if (argc) { t = (time_t) janet_getinteger64(argv, 0); } else { time(&t); } - t_info = localtime(&t); +#ifdef JANET_WINDOWS + localtime_s(&t_infos, &t); + t_info = &t_infos; +#else + t_info = localtime_r(&t, &t_infos); +#endif JanetKV *st = janet_struct_begin(9); janet_struct_put(st, janet_ckeywordv("seconds"), janet_wrap_number(t_info->tm_sec)); janet_struct_put(st, janet_ckeywordv("minutes"), janet_wrap_number(t_info->tm_min)); diff --git a/src/core/vector.c b/src/core/vector.c index e6469960..031ebc2a 100644 --- a/src/core/vector.c +++ b/src/core/vector.c @@ -30,7 +30,8 @@ void *janet_v_grow(void *v, int32_t increment, int32_t itemsize) { int32_t dbl_cur = (NULL != v) ? 2 * janet_v__cap(v) : 0; int32_t min_needed = janet_v_count(v) + increment; int32_t m = dbl_cur > min_needed ? dbl_cur : min_needed; - int32_t *p = (int32_t *) janet_srealloc(v ? janet_v__raw(v) : 0, itemsize * m + sizeof(int32_t) * 2); + size_t newsize = ((size_t) itemsize) * m + sizeof(int32_t) * 2; + int32_t *p = (int32_t *) janet_srealloc(v ? janet_v__raw(v) : 0, newsize); if (!v) p[1] = 0; p[0] = m; return p + 2; diff --git a/src/core/vm.c b/src/core/vm.c index 0080d014..d04ac5ff 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -892,12 +892,12 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in, JanetFiberStatus status) Janet fv = stack[C]; vm_assert_type(fv, JANET_FIBER); JanetFiber *f = janet_unwrap_fiber(fv); - JanetFiberStatus status = janet_fiber_status(f); - if (status > JANET_STATUS_USER9) { + JanetFiberStatus sub_status = janet_fiber_status(f); + if (sub_status > JANET_STATUS_USER9) { vm_throw("cannot propagate from new or alive fiber"); } janet_vm_fiber->child = f; - vm_return((int) status, stack[B]); + vm_return((int) sub_status, stack[B]); } VM_OP(JOP_PUT) diff --git a/src/mainclient/line.c b/src/mainclient/line.c index 85a289ba..600a53dc 100644 --- a/src/mainclient/line.c +++ b/src/mainclient/line.c @@ -87,18 +87,18 @@ https://github.com/antirez/linenoise/blob/master/linenoise.c /* static state */ #define JANET_LINE_MAX 1024 #define JANET_HISTORY_MAX 100 -static int israwmode = 0; -static const char *prompt = "> "; -static int plen = 2; -static char buf[JANET_LINE_MAX]; -static int len = 0; -static int pos = 0; -static int cols = 80; -static char *history[JANET_HISTORY_MAX]; -static int history_count = 0; -static int historyi = 0; -static int sigint_flag = 0; -static struct termios termios_start; +static int gbl_israwmode = 0; +static const char *gbl_prompt = "> "; +static int gbl_plen = 2; +static char gbl_buf[JANET_LINE_MAX]; +static int gbl_len = 0; +static int gbl_pos = 0; +static int gbl_cols = 80; +static char *gbl_history[JANET_HISTORY_MAX]; +static int gbl_history_count = 0; +static int gbl_historyi = 0; +static int gbl_sigint_flag = 0; +static struct termios gbl_termios_start; /* Unsupported terminal list from linenoise */ static const char *badterms[] = { @@ -121,8 +121,8 @@ static char *sdup(const char *s) { static int rawmode() { struct termios t; if (!isatty(STDIN_FILENO)) goto fatal; - if (tcgetattr(STDIN_FILENO, &termios_start) == -1) goto fatal; - t = termios_start; + if (tcgetattr(STDIN_FILENO, &gbl_termios_start) == -1) goto fatal; + t = gbl_termios_start; t.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); t.c_oflag &= ~(OPOST); t.c_cflag |= (CS8); @@ -130,7 +130,7 @@ static int rawmode() { t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0; if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) < 0) goto fatal; - israwmode = 1; + gbl_israwmode = 1; return 0; fatal: errno = ENOTTY; @@ -139,8 +139,8 @@ fatal: /* Disable raw mode */ static void norawmode() { - if (israwmode && tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios_start) != -1) - israwmode = 0; + if (gbl_israwmode && tcsetattr(STDIN_FILENO, TCSAFLUSH, &gbl_termios_start) != -1) + gbl_israwmode = 0; } static int curpos() { @@ -171,7 +171,9 @@ static int getcols() { if (cols > start) { char seq[32]; snprintf(seq, 32, "\x1b[%dD", cols - start); - if (write(STDOUT_FILENO, seq, strlen(seq)) == -1) {} + if (write(STDOUT_FILENO, seq, strlen(seq)) == -1) { + exit(1); + } } return cols; } else { @@ -182,7 +184,9 @@ failed: } static void clear() { - if (write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7) <= 0) {} + if (write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7) <= 0) { + exit(1); + } } static void refresh() { @@ -190,38 +194,40 @@ static void refresh() { JanetBuffer b; /* Keep cursor position on screen */ - char *_buf = buf; - int _len = len; - int _pos = pos; - while ((plen + _pos) >= cols) { + char *_buf = gbl_buf; + int _len = gbl_len; + int _pos = gbl_pos; + while ((gbl_plen + _pos) >= gbl_cols) { _buf++; _len--; _pos--; } - while ((plen + _len) > cols) { + while ((gbl_plen + _len) > gbl_cols) { _len--; } janet_buffer_init(&b, 0); - /* Cursor to left edge, prompt and buffer */ + /* Cursor to left edge, gbl_prompt and buffer */ janet_buffer_push_u8(&b, '\r'); - janet_buffer_push_cstring(&b, prompt); + janet_buffer_push_cstring(&b, gbl_prompt); janet_buffer_push_bytes(&b, (uint8_t *) _buf, _len); /* Erase to right */ janet_buffer_push_cstring(&b, "\x1b[0K"); /* Move cursor to original position. */ - snprintf(seq, 64, "\r\x1b[%dC", (int)(_pos + plen)); + snprintf(seq, 64, "\r\x1b[%dC", (int)(_pos + gbl_plen)); janet_buffer_push_cstring(&b, seq); - if (write(STDOUT_FILENO, b.data, b.count) == -1) {} + if (write(STDOUT_FILENO, b.data, b.count) == -1) { + exit(1); + } janet_buffer_deinit(&b); } static int insert(char c) { - if (len < JANET_LINE_MAX - 1) { - if (len == pos) { - buf[pos++] = c; - buf[++len] = '\0'; - if (plen + len < cols) { + if (gbl_len < JANET_LINE_MAX - 1) { + if (gbl_len == gbl_pos) { + gbl_buf[gbl_pos++] = c; + gbl_buf[++gbl_len] = '\0'; + if (gbl_plen + gbl_len < gbl_cols) { /* Avoid a full update of the line in the * trivial case. */ if (write(STDOUT_FILENO, &c, 1) == -1) return -1; @@ -229,9 +235,9 @@ static int insert(char c) { refresh(); } } else { - memmove(buf + pos + 1, buf + pos, len - pos); - buf[pos++] = c; - buf[++len] = '\0'; + memmove(gbl_buf + gbl_pos + 1, gbl_buf + gbl_pos, gbl_len - gbl_pos); + gbl_buf[gbl_pos++] = c; + gbl_buf[++gbl_len] = '\0'; refresh(); } } @@ -239,21 +245,21 @@ static int insert(char c) { } static void historymove(int delta) { - if (history_count > 1) { - free(history[historyi]); - history[historyi] = sdup(buf); + if (gbl_history_count > 1) { + free(gbl_history[gbl_historyi]); + gbl_history[gbl_historyi] = sdup(gbl_buf); - historyi += delta; - if (historyi < 0) { - historyi = 0; + gbl_historyi += delta; + if (gbl_historyi < 0) { + gbl_historyi = 0; return; - } else if (historyi >= history_count) { - historyi = history_count - 1; + } else if (gbl_historyi >= gbl_history_count) { + gbl_historyi = gbl_history_count - 1; return; } - strncpy(buf, history[historyi], JANET_LINE_MAX - 1); - pos = len = strlen(buf); - buf[len] = '\0'; + strncpy(gbl_buf, gbl_history[gbl_historyi], JANET_LINE_MAX - 1); + gbl_pos = gbl_len = strlen(gbl_buf); + gbl_buf[gbl_len] = '\0'; refresh(); } @@ -261,62 +267,62 @@ static void historymove(int delta) { static void addhistory() { int i, len; - char *newline = sdup(buf); + char *newline = sdup(gbl_buf); if (!newline) return; - len = history_count; + len = gbl_history_count; if (len < JANET_HISTORY_MAX) { - history[history_count++] = newline; + gbl_history[gbl_history_count++] = newline; len++; } else { - free(history[JANET_HISTORY_MAX - 1]); + free(gbl_history[JANET_HISTORY_MAX - 1]); } for (i = len - 1; i > 0; i--) { - history[i] = history[i - 1]; + gbl_history[i] = gbl_history[i - 1]; } - history[0] = newline; + gbl_history[0] = newline; } static void replacehistory() { - char *newline = sdup(buf); + char *newline = sdup(gbl_buf); if (!newline) return; - free(history[0]); - history[0] = newline; + free(gbl_history[0]); + gbl_history[0] = newline; } static void kleft() { - if (pos > 0) { - pos--; + if (gbl_pos > 0) { + gbl_pos--; refresh(); } } static void kright() { - if (pos != len) { - pos++; + if (gbl_pos != gbl_len) { + gbl_pos++; refresh(); } } static void kbackspace() { - if (pos > 0) { - memmove(buf + pos - 1, buf + pos, len - pos); - pos--; - buf[--len] = '\0'; + if (gbl_pos > 0) { + memmove(gbl_buf + gbl_pos - 1, gbl_buf + gbl_pos, gbl_len - gbl_pos); + gbl_pos--; + gbl_buf[--gbl_len] = '\0'; refresh(); } } static int line() { - cols = getcols(); - plen = 0; - len = 0; - pos = 0; - while (prompt[plen]) plen++; - buf[0] = '\0'; + gbl_cols = getcols(); + gbl_plen = 0; + gbl_len = 0; + gbl_pos = 0; + while (gbl_prompt[gbl_plen]) gbl_plen++; + gbl_buf[0] = '\0'; addhistory(); - if (write(STDOUT_FILENO, prompt, plen) == -1) return -1; + if (write(STDOUT_FILENO, gbl_prompt, gbl_plen) == -1) return -1; for (;;) { char c; int nread; @@ -337,7 +343,7 @@ static int line() { return 0; case 3: /* ctrl-c */ errno = EAGAIN; - sigint_flag = 1; + gbl_sigint_flag = 1; return -1; case 127: /* backspace */ case 8: /* ctrl-h */ @@ -352,8 +358,8 @@ static int line() { kright(); break; case 21: - buf[0] = '\0'; - pos = len = 0; + gbl_buf[0] = '\0'; + gbl_pos = gbl_len = 0; refresh(); break; case 26: /* ctrl-z */ @@ -399,11 +405,11 @@ static int line() { kleft(); break; case 'H': - pos = 0; + gbl_pos = 0; refresh(); break; case 'F': - pos = len; + gbl_pos = gbl_len; refresh(); break; } @@ -413,11 +419,11 @@ static int line() { default: break; case 'H': - pos = 0; + gbl_pos = 0; refresh(); break; case 'F': - pos = len; + gbl_pos = gbl_len; refresh(); break; } @@ -435,9 +441,9 @@ void janet_line_init() { void janet_line_deinit() { int i; norawmode(); - for (i = 0; i < history_count; i++) - free(history[i]); - historyi = 0; + for (i = 0; i < gbl_history_count; i++) + free(gbl_history[i]); + gbl_historyi = 0; } static int checktermsupport() { @@ -450,9 +456,9 @@ static int checktermsupport() { } void janet_line_get(const char *p, JanetBuffer *buffer) { - prompt = p; + gbl_prompt = p; buffer->count = 0; - historyi = 0; + gbl_historyi = 0; FILE *out = janet_dynfile("out", stdout); if (!isatty(STDIN_FILENO) || !checktermsupport()) { simpleline(buffer); @@ -464,7 +470,7 @@ void janet_line_get(const char *p, JanetBuffer *buffer) { } if (line()) { norawmode(); - if (sigint_flag) { + if (gbl_sigint_flag) { raise(SIGINT); } else { fputc('\n', out); @@ -473,10 +479,10 @@ void janet_line_get(const char *p, JanetBuffer *buffer) { } norawmode(); fputc('\n', out); - janet_buffer_ensure(buffer, len + 1, 2); - memcpy(buffer->data, buf, len); - buffer->data[len] = '\n'; - buffer->count = len + 1; + janet_buffer_ensure(buffer, gbl_len + 1, 2); + memcpy(buffer->data, gbl_buf, gbl_len); + buffer->data[gbl_len] = '\n'; + buffer->count = gbl_len + 1; replacehistory(); }