Avoid array underflow in marsh.c

This commit is contained in:
Calvin Rose
2026-08-26 18:55:02 -05:00
parent b5f40c5f73
commit 9d14e34596
2 changed files with 15 additions and 9 deletions
+1
View File
@@ -2,6 +2,7 @@
All notable changes to this project will be documented in this file.
## Unreleased - ???
- Add `:locale` option to `sandbox` to mask calling `os/setlocale`.
- JANET_PATH will now be searched strictly left-to-right for modules.
- Add `-t` (`--tool`) flag for using installed libraries as command line tools
- Numerous documentation improvements and fixes
+14 -9
View File
@@ -30,7 +30,6 @@
#include "util.h"
#endif
typedef struct {
JanetBuffer *buf;
JanetTable seen;
@@ -80,6 +79,13 @@ enum {
LB_ARRAY_WEAK, /* 232 */
} LeadBytes;
/* Avoid overflow and underflow, especially on 32-bit systems */
static void *array_allocate(size_t element_size, int32_t count) {
if (count < 0) return NULL;
if ((size_t) count > (SIZE_MAX / element_size)) return NULL;
return janet_malloc(element_size * count);
}
/* Helper to look inside an entry in an environment */
static Janet entry_getval(Janet env_entry) {
if (janet_checktype(env_entry, JANET_TABLE)) {
@@ -862,7 +868,7 @@ static const uint8_t *unmarshal_one_env(
if (length == 0) {
janet_panic("invalid funcenv length");
}
env->as.values = janet_malloc(sizeof(Janet) * (size_t) length);
env->as.values = array_allocate(sizeof(Janet), length);
if (!env->as.values) {
JANET_OUT_OF_MEMORY;
}
@@ -966,7 +972,7 @@ static const uint8_t *unmarshal_one_def(
/* Unmarshal constants */
if (constants_length) {
def->constants = janet_malloc(sizeof(Janet) * constants_length);
def->constants = array_allocate(sizeof(Janet), constants_length);
if (!def->constants) {
JANET_OUT_OF_MEMORY;
}
@@ -979,8 +985,7 @@ static const uint8_t *unmarshal_one_def(
/* Unmarshal symbol map, if needed */
if (def->flags & JANET_FUNCDEF_FLAG_HASSYMBOLMAP) {
size_t size = sizeof(JanetSymbolMap) * symbolmap_length;
def->symbolmap = janet_malloc(size);
def->symbolmap = array_allocate(sizeof(JanetSymbolMap), symbolmap_length);
if (def->symbolmap == NULL) {
JANET_OUT_OF_MEMORY;
}
@@ -999,7 +1004,7 @@ static const uint8_t *unmarshal_one_def(
}
/* Unmarshal bytecode */
def->bytecode = janet_malloc(sizeof(uint32_t) * bytecode_length);
def->bytecode = array_allocate(sizeof(uint32_t), bytecode_length);
if (!def->bytecode) {
JANET_OUT_OF_MEMORY;
}
@@ -1037,7 +1042,7 @@ static const uint8_t *unmarshal_one_def(
/* Unmarshal source maps if needed */
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCEMAP) {
int32_t current = 0;
def->sourcemap = janet_malloc(sizeof(JanetSourceMapping) * (size_t) bytecode_length);
def->sourcemap = array_allocate(sizeof(JanetSourceMapping), bytecode_length);
if (!def->sourcemap) {
JANET_OUT_OF_MEMORY;
}
@@ -1053,7 +1058,7 @@ static const uint8_t *unmarshal_one_def(
/* Unmarshal closure bitset if needed */
if (def->flags & JANET_FUNCDEF_FLAG_HASCLOBITSET) {
int32_t n = (def->slotcount + 31) >> 5;
def->closure_bitset = janet_malloc(sizeof(uint32_t) * (size_t) n);
def->closure_bitset = array_allocate(sizeof(uint32_t), n);
if (NULL == def->closure_bitset) {
JANET_OUT_OF_MEMORY;
}
@@ -1122,7 +1127,7 @@ static const uint8_t *unmarshal_one_fiber(
/* Extra capacity is usually nice to avoid immediately reallocing on pushed arguments, but not needed */
fiber->capacity = INT32_MAX;
}
fiber->data = janet_malloc(sizeof(Janet) * fiber->capacity);
fiber->data = array_allocate(sizeof(Janet), fiber->capacity);
if (!fiber->data) {
JANET_OUT_OF_MEMORY;
}