Skip to content

Commit 68cb993

Browse files
gh-149: MOD doesn't overwrite second-operand pointer.
1 parent 0baf340 commit 68cb993

1 file changed

Lines changed: 27 additions & 5 deletions

File tree

src/builtins.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3092,33 +3092,55 @@ static Value builtin_cdiv(Interpreter* interp, Value* args, int argc, Expr** arg
30923092
}
30933093

30943094
static Value builtin_mod(Interpreter* interp, Value* args, int argc, Expr** arg_nodes, Env* env, int line, int col) {
3095-
(void)arg_nodes; (void)env;
3095+
(void)env;
30963096
EXPECT_NUM(args[0], "MOD", interp, line, col);
30973097
EXPECT_NUM(args[1], "MOD", interp, line, col);
3098-
3098+
30993099
if (args[0].type != args[1].type) {
31003100
RUNTIME_ERROR(interp, "MOD cannot mix INT and FLT", line, col);
31013101
}
3102-
3102+
31033103
int out_base = result_base_from_values(args[0], args[1]);
31043104
if (args[0].type == VAL_INT) {
31053105
if (args[1].as.i == 0) {
31063106
RUNTIME_ERROR(interp, "Division by zero", line, col);
31073107
}
31083108
int64_t b = args[1].as.i < 0 ? -args[1].as.i : args[1].as.i;
31093109
Value result = value_int_base(args[0].as.i % b, out_base);
3110-
if (!writeback_ptr_range(interp, arg_nodes, env, 0, 2, result, "MOD", line, col)) {
3110+
3111+
bool ok = true;
3112+
if (arg_nodes && arg_nodes[0] && arg_nodes[0]->type == EXPR_PTR) {
3113+
if (!writeback_ptr_node(interp, arg_nodes[0], env, result, "MOD", line, col)) ok = false;
3114+
}
3115+
/* Only write back into the divisor (arg_nodes[1]) when the dividend
3116+
(arg_nodes[0]) is also a pointer literal — matching the spec and
3117+
tests that expect MOD(a2, @b2) to NOT overwrite b2. */
3118+
if (ok && arg_nodes && arg_nodes[1] && arg_nodes[1]->type == EXPR_PTR && arg_nodes[0] && arg_nodes[0]->type == EXPR_PTR) {
3119+
if (!writeback_ptr_node(interp, arg_nodes[1], env, result, "MOD", line, col)) ok = false;
3120+
}
3121+
3122+
if (!ok) {
31113123
value_free(result);
31123124
return value_null();
31133125
}
31143126
return result;
31153127
}
3128+
31163129
if (args[1].as.f == 0.0) {
31173130
RUNTIME_ERROR(interp, "Division by zero", line, col);
31183131
}
31193132
double b = args[1].as.f < 0 ? -args[1].as.f : args[1].as.f;
31203133
Value result = value_flt_base(fmod(args[0].as.f, b), out_base);
3121-
if (!writeback_ptr_range(interp, arg_nodes, env, 0, 2, result, "MOD", line, col)) {
3134+
3135+
bool ok = true;
3136+
if (arg_nodes && arg_nodes[0] && arg_nodes[0]->type == EXPR_PTR) {
3137+
if (!writeback_ptr_node(interp, arg_nodes[0], env, result, "MOD", line, col)) ok = false;
3138+
}
3139+
if (ok && arg_nodes && arg_nodes[1] && arg_nodes[1]->type == EXPR_PTR && arg_nodes[0] && arg_nodes[0]->type == EXPR_PTR) {
3140+
if (!writeback_ptr_node(interp, arg_nodes[1], env, result, "MOD", line, col)) ok = false;
3141+
}
3142+
3143+
if (!ok) {
31223144
value_free(result);
31233145
return value_null();
31243146
}

0 commit comments

Comments
 (0)