From 8dbe828504c9fd9c075fedb3620c8f082cf2860e Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Sat, 27 Jun 2026 14:24:37 -0500 Subject: [PATCH] Add casts to u32 before left shifts to address ubsan edge cases. Common idiom that wasn't always applied, especially in emit.c and cfuns.c --- src/core/cfuns.c | 4 ++-- src/core/compile.c | 6 +++++- src/core/corelib.c | 17 ++++++++++------- src/core/emit.c | 34 +++++++++++++++++----------------- src/core/specials.c | 14 +++++++------- test/suite-compile.janet | 2 ++ test/suite-corelib.janet | 2 ++ 7 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/core/cfuns.c b/src/core/cfuns.c index 2c09ead4..571b3622 100644 --- a/src/core/cfuns.c +++ b/src/core/cfuns.c @@ -188,7 +188,7 @@ static JanetSlot do_get(JanetFopts opts, JanetSlot *args) { janetc_copy(c, t, dflt_slot); if (target_is_default) janetc_freeslot(c, dflt_slot); int32_t current = janet_v_count(c->buffer); - c->buffer[label] |= (current - label) << 16; + c->buffer[label] |= (uint32_t)(current - label) << 16; return t; } else { return opreduce(opts, args, JOP_GET, 0, janet_wrap_nil(), janet_wrap_nil()); @@ -345,7 +345,7 @@ static JanetSlot compreduce( int32_t end = janet_v_count(c->buffer); for (i = 0; i < janet_v_count(labels); i++) { int32_t label = labels[i]; - c->buffer[label] |= ((end - label) << 16); + c->buffer[label] |= ((uint32_t)(end - label) << 16); } janet_v_free(labels); return t; diff --git a/src/core/compile.c b/src/core/compile.c index cedffaf2..1ded7d26 100644 --- a/src/core/compile.c +++ b/src/core/compile.c @@ -280,7 +280,11 @@ Shadowing janetc_shadowcheck(JanetCompiler *c, const uint8_t *sym) { for (int32_t i = len - 1; i >= 0; i--) { SymPair *pair = scope->syms + i; if (pair->sym == sym) { - janet_assert(!is_global, "shadowing analysis is incorrect. compiler bug"); + if (is_global) { + /* This can happen in a top level form like (def [x [x y]] [1 [2 3]])` where a symbol is reused in one expression */ + /* janet_assert(!is_global, "shadowing analysis is incorrect. compiler bug"); */ + return JANETC_SHADOW_GLOBAL_HIDES_GLOBAL; + } return JANETC_SHADOW_LOCAL_HIDES_LOCAL; } } diff --git a/src/core/corelib.c b/src/core/corelib.c index 93857b74..bf8401bb 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -441,19 +441,22 @@ JANET_CORE_FN(janet_core_range, start = janet_getnumber(argv, 0); stop = janet_getnumber(argv, 1); step = janet_getnumber(argv, 2); - count = (step > 0) ? (stop - start) / step : - ((step < 0) ? (stop - start) / step : 0); + count = (step > 0.0) ? (stop - start) / step : + ((step < 0.0) ? (stop - start) / step : 0.0); } else if (argc == 2) { - start = janet_getnumber(argv, 0); - stop = janet_getnumber(argv, 1); + start = janet_getnumber(argv, 0.0); + stop = janet_getnumber(argv, 1.0); count = stop - start; } else { - stop = janet_getnumber(argv, 0); + stop = janet_getnumber(argv, 0.0); count = stop; } - count = (count > 0) ? count : 0; + if (isinf(step)) { + janet_panic("infinite step not allowed"); + } + count = (count > 0.0) ? count : 0.0; int32_t int_count; - janet_assert(count >= 0, "bad range code"); + janet_assert(count >= 0.0, "bad range code"); if (count > (double) INT32_MAX) { janet_panicf("range is too large, %f elements", count); } else { diff --git a/src/core/emit.c b/src/core/emit.c index 290a8990..32e20fc9 100644 --- a/src/core/emit.c +++ b/src/core/emit.c @@ -78,10 +78,10 @@ static int32_t janetc_const(JanetCompiler *c, Janet x) { static void janetc_loadconst(JanetCompiler *c, Janet k, int32_t reg) { switch (janet_type(k)) { case JANET_NIL: - janetc_emit(c, (reg << 8) | JOP_LOAD_NIL); + janetc_emit(c, ((uint32_t) reg << 8) | JOP_LOAD_NIL); break; case JANET_BOOLEAN: - janetc_emit(c, (reg << 8) | + janetc_emit(c, ((uint32_t) reg << 8) | (janet_unwrap_boolean(k) ? JOP_LOAD_TRUE : JOP_LOAD_FALSE)); break; case JANET_NUMBER: { @@ -93,8 +93,8 @@ static void janetc_loadconst(JanetCompiler *c, Janet k, int32_t reg) { goto do_constant; uint32_t iu = (uint32_t)i; janetc_emit(c, - (iu << 16) | - (reg << 8) | + ((uint32_t) iu << 16) | + ((uint32_t) reg << 8) | JOP_LOAD_INTEGER); break; } @@ -102,8 +102,8 @@ static void janetc_loadconst(JanetCompiler *c, Janet k, int32_t reg) { do_constant: { int32_t cindex = janetc_const(c, k); janetc_emit(c, - (cindex << 16) | - (reg << 8) | + ((uint32_t) cindex << 16) | + ((uint32_t) reg << 8) | JOP_LOAD_CONSTANT); break; } @@ -120,8 +120,8 @@ static void janetc_movenear(JanetCompiler *c, /* If we also are a reference, deref the one element array */ if (src.flags & JANET_SLOT_REF) { janetc_emit(c, - (dest << 16) | - (dest << 8) | + ((uint32_t) dest << 16) | + ((uint32_t) dest << 8) | JOP_GET_INDEX); } } else if (src.envindex >= 0) { @@ -147,15 +147,15 @@ static void janetc_moveback(JanetCompiler *c, int32_t refreg = janetc_regalloc_temp(&c->scope->ra, JANETC_REGTEMP_5); janetc_loadconst(c, dest.constant, refreg); janetc_emit(c, - (src << 16) | - (refreg << 8) | + ((uint32_t) src << 16) | + ((uint32_t) refreg << 8) | JOP_PUT_INDEX); janetc_regalloc_freetemp(&c->scope->ra, refreg, JANETC_REGTEMP_5); } else if (dest.envindex >= 0) { /* Convert src to near reg */ if (src > 255) { int32_t newsrc = JANETC_REGTEMP_5 + 0xF0; - janetc_emit(c, JOP_MOVE_NEAR | ((uint32_t)(src) << 16) | (newsrc << 8)); + janetc_emit(c, JOP_MOVE_NEAR | ((uint32_t)(src) << 16) | ((uint32_t) newsrc << 8)); src = newsrc; } janetc_emit(c, @@ -199,7 +199,7 @@ static int32_t janetc_regfar(JanetCompiler *c, JanetSlot s, JanetcRegisterTemp t janetc_movenear(c, nearreg, s); if (nearreg >= 0xF0) { reg = janetc_allocfar(c); - janetc_emit(c, JOP_MOVE_FAR | (nearreg << 8) | (reg << 16)); + janetc_emit(c, JOP_MOVE_FAR | ((uint32_t) nearreg << 8) | ((uint32_t) reg << 16)); janetc_regalloc_freetemp(&c->scope->ra, nearreg, tag); } else { reg = nearreg; @@ -268,7 +268,7 @@ void janetc_copy( static int32_t emit1s(JanetCompiler *c, uint8_t op, JanetSlot s, int32_t rest, int wr) { int32_t reg = janetc_regnear(c, s, JANETC_REGTEMP_0); int32_t label = janet_v_count(c->buffer); - janetc_emit(c, op | (reg << 8) | ((uint32_t)rest << 16)); + janetc_emit(c, op | ((uint32_t) reg << 8) | ((uint32_t) rest << 16)); if (wr) janetc_moveback(c, s, reg); janetc_free_regnear(c, s, reg, JANETC_REGTEMP_0); @@ -278,7 +278,7 @@ static int32_t emit1s(JanetCompiler *c, uint8_t op, JanetSlot s, int32_t rest, i int32_t janetc_emit_s(JanetCompiler *c, uint8_t op, JanetSlot s, int wr) { int32_t reg = janetc_regfar(c, s, JANETC_REGTEMP_0); int32_t label = janet_v_count(c->buffer); - janetc_emit(c, op | (reg << 8)); + janetc_emit(c, op | ((uint32_t) reg << 8)); if (wr) janetc_moveback(c, s, reg); janetc_free_regnear(c, s, reg, JANETC_REGTEMP_0); @@ -310,7 +310,7 @@ static int32_t emit2s(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2, int32_t reg1 = janetc_regnear(c, s1, JANETC_REGTEMP_0); int32_t reg2 = janetc_regnear(c, s2, JANETC_REGTEMP_1); int32_t label = janet_v_count(c->buffer); - janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | ((uint32_t)rest << 24)); + janetc_emit(c, op | ((uint32_t) reg1 << 8) | ((uint32_t) reg2 << 16) | ((uint32_t)rest << 24)); janetc_free_regnear(c, s2, reg2, JANETC_REGTEMP_1); if (wr) janetc_moveback(c, s1, reg1); @@ -322,7 +322,7 @@ int32_t janetc_emit_ss(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2, int32_t reg1 = janetc_regnear(c, s1, JANETC_REGTEMP_0); int32_t reg2 = janetc_regfar(c, s2, JANETC_REGTEMP_1); int32_t label = janet_v_count(c->buffer); - janetc_emit(c, op | (reg1 << 8) | (reg2 << 16)); + janetc_emit(c, op | ((uint32_t) reg1 << 8) | ((uint32_t) reg2 << 16)); janetc_free_regnear(c, s2, reg2, JANETC_REGTEMP_1); if (wr) janetc_moveback(c, s1, reg1); @@ -343,7 +343,7 @@ int32_t janetc_emit_sss(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2 int32_t reg2 = janetc_regnear(c, s2, JANETC_REGTEMP_1); int32_t reg3 = janetc_regnear(c, s3, JANETC_REGTEMP_2); int32_t label = janet_v_count(c->buffer); - janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | ((uint32_t)reg3 << 24)); + janetc_emit(c, op | ((uint32_t) reg1 << 8) | ((uint32_t) reg2 << 16) | ((uint32_t) reg3 << 24)); janetc_free_regnear(c, s2, reg2, JANETC_REGTEMP_1); janetc_free_regnear(c, s3, reg3, JANETC_REGTEMP_2); if (wr) diff --git a/src/core/specials.c b/src/core/specials.c index 5f843ac2..646f0ad1 100644 --- a/src/core/specials.c +++ b/src/core/specials.c @@ -723,10 +723,10 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) { labeld = janet_v_count(c->buffer); if (labeljr < labeld) { check_16bit_jump(c, labeljr, labelr); - c->buffer[labeljr] |= (labelr - labeljr) << 16; + c->buffer[labeljr] |= (uint32_t) (labelr - labeljr) << 16; if (!tail && labeljd < labeld) { check_24bit_jump(c, labeljd, labeld); - c->buffer[labeljd] |= (labeld - labeljd) << 8; + c->buffer[labeljd] |= (uint32_t) (labeld - labeljd) << 8; } } @@ -945,8 +945,8 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv) } /* But now add tail recursion */ int32_t tempself = janetc_regalloc_temp(&tempscope.ra, JANETC_REGTEMP_0); - janetc_emit(c, JOP_LOAD_SELF | (tempself << 8)); - janetc_emit(c, JOP_TAILCALL | (tempself << 8)); + janetc_emit(c, JOP_LOAD_SELF | ((uint32_t) tempself << 8)); + janetc_emit(c, JOP_TAILCALL | ((uint32_t) tempself << 8)); janetc_regalloc_freetemp(&c->scope->ra, tempself, JANETC_REGTEMP_0); /* Compile function */ JanetFuncDef *def = janetc_pop_funcdef(c); @@ -955,8 +955,8 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv) int32_t defindex = janetc_addfuncdef(c, def); /* And then load the closure and call it. */ int32_t cloreg = janetc_regalloc_temp(&c->scope->ra, JANETC_REGTEMP_0); - janetc_emit(c, JOP_CLOSURE | (cloreg << 8) | (defindex << 16)); - janetc_emit(c, JOP_CALL | (cloreg << 8) | (cloreg << 16)); + janetc_emit(c, JOP_CLOSURE | ((uint32_t) cloreg << 8) | ((uint32_t) defindex << 16)); + janetc_emit(c, JOP_CALL | ((uint32_t) cloreg << 8) | ((uint32_t) cloreg << 16)); janetc_regalloc_freetemp(&c->scope->ra, cloreg, JANETC_REGTEMP_0); c->scope->flags |= JANET_SCOPE_CLOSURE; return janetc_cslot(janet_wrap_nil()); @@ -980,7 +980,7 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv) for (int32_t i = labelwt; i < labeld; i++) { if (c->buffer[i] == (0x80 | JOP_JUMP)) { check_24bit_jump(c, i, labeld); - c->buffer[i] = JOP_JUMP | ((labeld - i) << 8); + c->buffer[i] = JOP_JUMP | ((uint32_t) (labeld - i) << 8); } } diff --git a/test/suite-compile.janet b/test/suite-compile.janet index 5b0c5d54..bb815ad5 100644 --- a/test/suite-compile.janet +++ b/test/suite-compile.janet @@ -156,4 +156,6 @@ (check-lint-compile '(let [outer1 "b"] outer1) "shadow local-to-global") (check-lint-compile '(do (def x "b") (def x "c")) "shadow local-to-local") +(check-lint-compile '(def [xxx [xxx yyy]] [1 [2 3]]) "shadow global-to-global one form") + (end-suite) diff --git a/test/suite-corelib.janet b/test/suite-corelib.janet index 2454cb85..a8120573 100644 --- a/test/suite-corelib.janet +++ b/test/suite-corelib.janet @@ -207,4 +207,6 @@ '(fn :short-fn [] (set (my-table [2 1]) (quote foo)))) "Macro expand inside set preserves tuple type correctly") +(assert-error "no infinite step range" (range 3 3 math/inf)) + (end-suite)