Skip to content

Commit 7cf9bd9

Browse files
committed
Add checks for bytecode jumps in compilers.
In the case where we have long jumps, emit a compiler error instead of silently miscompiling.
1 parent ffb8330 commit 7cf9bd9

2 files changed

Lines changed: 42 additions & 2 deletions

File tree

src/core/bytecode.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ void janet_bytecode_remove_noops(JanetFuncDef *def) {
139139
case JOP_JUMP:
140140
/* relative pc is in DS field of instruction */
141141
old_jump_target = i + (((int32_t)instr) >> 8);
142+
janet_assert(old_jump_target >= 0, "bounds");
143+
janet_assert(old_jump_target < def->bytecode_length, "bounds");
142144
new_jump_target = pc_map[old_jump_target];
143145
instr += (uint32_t)(new_jump_target - old_jump_target + (i - j)) << 8;
144146
break;
@@ -148,6 +150,8 @@ void janet_bytecode_remove_noops(JanetFuncDef *def) {
148150
case JOP_JUMP_IF_NOT_NIL:
149151
/* relative pc is in ES field of instruction */
150152
old_jump_target = i + (((int32_t)instr) >> 16);
153+
janet_assert(old_jump_target >= 0, "bounds");
154+
janet_assert(old_jump_target < def->bytecode_length, "bounds");
151155
new_jump_target = pc_map[old_jump_target];
152156
instr += (uint32_t)(new_jump_target - old_jump_target + (i - j)) << 16;
153157
break;

src/core/specials.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,30 @@
2929
#include "emit.h"
3030
#endif
3131

32+
static int bad_16bit_jump(int32_t lab1, int32_t lab2) {
33+
if (lab2 - lab1 > INT16_MAX) return 1;
34+
if (lab2 - lab1 < INT16_MIN) return 1;
35+
return 0;
36+
}
37+
38+
static void check_16bit_jump(JanetCompiler *c, int32_t lab1, int32_t lab2) {
39+
if (bad_16bit_jump(lab1, lab2)) {
40+
janetc_cerror(c, "bad 16-bit jump, too large");
41+
}
42+
}
43+
44+
static int bad_24bit_jump(int32_t lab1, int32_t lab2) {
45+
if (lab2 - lab1 > 0xFFFFFF) return 1;
46+
if (lab2 - lab1 < -0x1000000) return 1;
47+
return 0;
48+
}
49+
50+
static void check_24bit_jump(JanetCompiler *c, int32_t lab1, int32_t lab2) {
51+
if (bad_24bit_jump(lab1, lab2)) {
52+
janetc_cerror(c, "bad 24-bit jump, too large");
53+
}
54+
}
55+
3256
static JanetSlot janetc_quote(JanetFopts opts, int32_t argn, const Janet *argv) {
3357
if (argn != 1) {
3458
janetc_cerror(opts.compiler, "expected 1 argument to quote");
@@ -209,6 +233,8 @@ static int destructure(JanetCompiler *c,
209233
int32_t label_loop_exit = janet_v_count(c->buffer);
210234

211235
/* avoid shifting negative numbers */
236+
check_16bit_jump(c, label_loop_cond_jump, label_loop_exit);
237+
check_24bit_jump(c, label_loop_start, label_loop_loop);
212238
c->buffer[label_loop_cond_jump] |= (uint32_t)(label_loop_exit - label_loop_cond_jump) << 16;
213239
c->buffer[label_loop_loop] |= (uint32_t)(label_loop_start - label_loop_loop) << 8;
214240

@@ -696,8 +722,12 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
696722
/* Write jumps - only add jump lengths if jump actually emitted */
697723
labeld = janet_v_count(c->buffer);
698724
if (labeljr < labeld) {
725+
check_16bit_jump(c, labeljr, labelr);
699726
c->buffer[labeljr] |= (labelr - labeljr) << 16;
700-
if (!tail && labeljd < labeld) c->buffer[labeljd] |= (labeld - labeljd) << 8;
727+
if (!tail && labeljd < labeld) {
728+
check_24bit_jump(c, labeljd, labeld);
729+
c->buffer[labeljd] |= (labeld - labeljd) << 8;
730+
}
701731
}
702732

703733
if (tail) target.flags |= JANET_SLOT_RETURNED;
@@ -938,12 +968,18 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
938968

939969
/* Calculate jumps */
940970
labeld = janet_v_count(c->buffer);
941-
if (!infinite) c->buffer[labelc] |= (uint32_t)(labeld - labelc) << 16;
971+
if (!infinite) {
972+
check_16bit_jump(c, labelc, labeld);
973+
c->buffer[labelc] |= (uint32_t)(labeld - labelc) << 16;
974+
}
975+
976+
check_24bit_jump(c, labeljt, labelwt);
942977
c->buffer[labeljt] |= (uint32_t)(labelwt - labeljt) << 8;
943978

944979
/* Calculate breaks */
945980
for (int32_t i = labelwt; i < labeld; i++) {
946981
if (c->buffer[i] == (0x80 | JOP_JUMP)) {
982+
check_24bit_jump(c, i, labeld);
947983
c->buffer[i] = JOP_JUMP | ((labeld - i) << 8);
948984
}
949985
}

0 commit comments

Comments
 (0)