diff --git a/src/compile.c b/src/compile.c index f0be1a5f..5e64946b 100644 --- a/src/compile.c +++ b/src/compile.c @@ -1241,6 +1241,13 @@ static int compile(struct bytecode* bc, block b, struct locfile* lf, jv args, jv if (curr->op == CLOSURE_CREATE) { assert(curr->bound_by == curr); + // Prevent subfunction index from overflowing into ARG_NEWCLOSURE flag + if (bc->nsubfunctions >= ARG_NEWCLOSURE) { + locfile_locate(lf, curr->source, + "too many function parameters or local function definitions (max %d)", ARG_NEWCLOSURE - 1); + errors++; + break; + } curr->imm.intval = bc->nsubfunctions++; } if (curr->op == CLOSURE_CREATE_C) { @@ -1274,6 +1281,13 @@ static int compile(struct bytecode* bc, block b, struct locfile* lf, jv args, jv for (inst* param = curr->arglist.first; param; param = param->next) { assert(param->op == CLOSURE_PARAM); assert(param->bound_by == param); + // Prevent closure index from overflowing into ARG_NEWCLOSURE flag + if (subfn->nclosures >= ARG_NEWCLOSURE) { + locfile_locate(lf, curr->source, + "function has too many parameters (max %d)", ARG_NEWCLOSURE - 1); + errors++; + break; + } param->imm.intval = subfn->nclosures++; param->compiled = subfn; params = jv_array_append(params, jv_string(param->symbol)); diff --git a/tests/shtest b/tests/shtest index e241d4a5..90a96eaf 100755 --- a/tests/shtest +++ b/tests/shtest @@ -844,4 +844,31 @@ if ! $msys && ! $mingw; then fi fi +# Test ARG_NEWCLOSURE overflow protection (issue #3458) +# Test 1: Too many function parameters (4097 params triggers the limit) +echo "Testing function parameter limit..." +cat > $d/expected < $d/prog.jq +$JQ -nf $d/prog.jq 2> $d/out && { + echo "Expected compile error for too many parameters" + exit 1 +} +diff $d/out $d/expected + +# Test 2: Too many local functions (4097 functions triggers the limit) +echo "Testing local function limit..." +cat > $d/expected < $d/prog.jq +$JQ -nf $d/prog.jq 2> $d/out && { + echo "Expected compile error for too many local functions" + exit 1 +} +diff $d/out $d/expected + exit 0