Skip to content

Commit e225d4c

Browse files
gh-177: IADD fails on NaN/INF.
1 parent 981ae56 commit e225d4c

1 file changed

Lines changed: 106 additions & 15 deletions

File tree

src/builtins.c

Lines changed: 106 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,30 @@ static bool writeback_ptr_range(Interpreter* interp, Expr** arg_nodes, Env* env,
186186
return true;
187187
}
188188

189+
// Checked FLT -> INT coercion helper.
190+
// Returns true and sets *out on success. On failure, sets interp->error
191+
// and returns false (caller should return value_null()).
192+
static bool coerce_flt_to_int_checked(Interpreter* interp, double f, int64_t* out, const char* opname, int line, int col) {
193+
if (isnan(f) || isinf(f)) {
194+
char buf[128];
195+
snprintf(buf, sizeof(buf), "%s cannot coerce FLT to INT", opname);
196+
interp->error = strdup(buf);
197+
interp->error_line = line;
198+
interp->error_col = col;
199+
return false;
200+
}
201+
if (f > (double)INT64_MAX || f < (double)INT64_MIN) {
202+
char buf[128];
203+
snprintf(buf, sizeof(buf), "%s cannot coerce FLT to INT (out of range)", opname);
204+
interp->error = strdup(buf);
205+
interp->error_line = line;
206+
interp->error_col = col;
207+
return false;
208+
}
209+
*out = (int64_t)f;
210+
return true;
211+
}
212+
189213
// --- Encoding helpers ---
190214
static char* dec_latin1_to_utf8(const unsigned char* buf, size_t sz) {
191215
size_t outcap = sz * 2 + 1;
@@ -3492,8 +3516,18 @@ static Value builtin_iadd(Interpreter* interp, Value* args, int argc, Expr** arg
34923516
EXPECT_NUM(args[0], "IADD", interp, line, col);
34933517
EXPECT_NUM(args[1], "IADD", interp, line, col);
34943518

3495-
int64_t a = args[0].type == VAL_INT ? args[0].as.i : (int64_t)args[0].as.f;
3496-
int64_t b = args[1].type == VAL_INT ? args[1].as.i : (int64_t)args[1].as.f;
3519+
int64_t a;
3520+
if (args[0].type == VAL_INT) {
3521+
a = args[0].as.i;
3522+
} else {
3523+
if (!coerce_flt_to_int_checked(interp, args[0].as.f, &a, "IADD", line, col)) return value_null();
3524+
}
3525+
int64_t b;
3526+
if (args[1].type == VAL_INT) {
3527+
b = args[1].as.i;
3528+
} else {
3529+
if (!coerce_flt_to_int_checked(interp, args[1].as.f, &b, "IADD", line, col)) return value_null();
3530+
}
34973531
Value result = value_int_base(a + b, result_base_from_values(args[0], args[1]));
34983532
if (!writeback_ptr_range(interp, arg_nodes, env, 0, 2, result, "IADD", line, col)) {
34993533
value_free(result);
@@ -3507,8 +3541,18 @@ static Value builtin_isub(Interpreter* interp, Value* args, int argc, Expr** arg
35073541
EXPECT_NUM(args[0], "ISUB", interp, line, col);
35083542
EXPECT_NUM(args[1], "ISUB", interp, line, col);
35093543

3510-
int64_t a = args[0].type == VAL_INT ? args[0].as.i : (int64_t)args[0].as.f;
3511-
int64_t b = args[1].type == VAL_INT ? args[1].as.i : (int64_t)args[1].as.f;
3544+
int64_t a;
3545+
if (args[0].type == VAL_INT) {
3546+
a = args[0].as.i;
3547+
} else {
3548+
if (!coerce_flt_to_int_checked(interp, args[0].as.f, &a, "ISUB", line, col)) return value_null();
3549+
}
3550+
int64_t b;
3551+
if (args[1].type == VAL_INT) {
3552+
b = args[1].as.i;
3553+
} else {
3554+
if (!coerce_flt_to_int_checked(interp, args[1].as.f, &b, "ISUB", line, col)) return value_null();
3555+
}
35123556
Value result = value_int_base(a - b, result_base_from_values(args[0], args[1]));
35133557
if (!writeback_ptr_range(interp, arg_nodes, env, 0, 2, result, "ISUB", line, col)) {
35143558
value_free(result);
@@ -3522,8 +3566,18 @@ static Value builtin_imul(Interpreter* interp, Value* args, int argc, Expr** arg
35223566
EXPECT_NUM(args[0], "IMUL", interp, line, col);
35233567
EXPECT_NUM(args[1], "IMUL", interp, line, col);
35243568

3525-
int64_t a = args[0].type == VAL_INT ? args[0].as.i : (int64_t)args[0].as.f;
3526-
int64_t b = args[1].type == VAL_INT ? args[1].as.i : (int64_t)args[1].as.f;
3569+
int64_t a;
3570+
if (args[0].type == VAL_INT) {
3571+
a = args[0].as.i;
3572+
} else {
3573+
if (!coerce_flt_to_int_checked(interp, args[0].as.f, &a, "IMUL", line, col)) return value_null();
3574+
}
3575+
int64_t b;
3576+
if (args[1].type == VAL_INT) {
3577+
b = args[1].as.i;
3578+
} else {
3579+
if (!coerce_flt_to_int_checked(interp, args[1].as.f, &b, "IMUL", line, col)) return value_null();
3580+
}
35273581
Value result = value_int_base(a * b, result_base_from_values(args[0], args[1]));
35283582
if (!writeback_ptr_range(interp, arg_nodes, env, 0, 2, result, "IMUL", line, col)) {
35293583
value_free(result);
@@ -3537,8 +3591,18 @@ static Value builtin_idiv(Interpreter* interp, Value* args, int argc, Expr** arg
35373591
EXPECT_NUM(args[0], "IDIV", interp, line, col);
35383592
EXPECT_NUM(args[1], "IDIV", interp, line, col);
35393593

3540-
int64_t a = args[0].type == VAL_INT ? args[0].as.i : (int64_t)args[0].as.f;
3541-
int64_t b = args[1].type == VAL_INT ? args[1].as.i : (int64_t)args[1].as.f;
3594+
int64_t a;
3595+
if (args[0].type == VAL_INT) {
3596+
a = args[0].as.i;
3597+
} else {
3598+
if (!coerce_flt_to_int_checked(interp, args[0].as.f, &a, "IDIV", line, col)) return value_null();
3599+
}
3600+
int64_t b;
3601+
if (args[1].type == VAL_INT) {
3602+
b = args[1].as.i;
3603+
} else {
3604+
if (!coerce_flt_to_int_checked(interp, args[1].as.f, &b, "IDIV", line, col)) return value_null();
3605+
}
35423606
if (b == 0) {
35433607
RUNTIME_ERROR(interp, "Division by zero", line, col);
35443608
}
@@ -3618,8 +3682,18 @@ static Value builtin_ipow(Interpreter* interp, Value* args, int argc, Expr** arg
36183682
EXPECT_NUM(args[0], "IPOW", interp, line, col);
36193683
EXPECT_NUM(args[1], "IPOW", interp, line, col);
36203684

3621-
int64_t base = args[0].type == VAL_INT ? args[0].as.i : (int64_t)args[0].as.f;
3622-
int64_t exp = args[1].type == VAL_INT ? args[1].as.i : (int64_t)args[1].as.f;
3685+
int64_t base;
3686+
if (args[0].type == VAL_INT) {
3687+
base = args[0].as.i;
3688+
} else {
3689+
if (!coerce_flt_to_int_checked(interp, args[0].as.f, &base, "IPOW", line, col)) return value_null();
3690+
}
3691+
int64_t exp;
3692+
if (args[1].type == VAL_INT) {
3693+
exp = args[1].as.i;
3694+
} else {
3695+
if (!coerce_flt_to_int_checked(interp, args[1].as.f, &exp, "IPOW", line, col)) return value_null();
3696+
}
36233697
if (exp < 0) {
36243698
RUNTIME_ERROR(interp, "Negative exponent not supported", line, col);
36253699
}
@@ -3948,8 +4022,11 @@ static Value builtin_conv(Interpreter* interp, Value* args, int argc, Expr** arg
39484022
if (bias_present && bias_t->length > 0) {
39494023
Value bv = bias_t->data[oc];
39504024
if (bv.type == VAL_INT) acc += bv.as.i;
3951-
else if (bv.type == VAL_FLT) acc += (int64_t)bv.as.f;
3952-
else { value_free(out); RUNTIME_ERROR(interp, "CONV bias must be numeric", line, col); }
4025+
else if (bv.type == VAL_FLT) {
4026+
int64_t tmp;
4027+
if (!coerce_flt_to_int_checked(interp, bv.as.f, &tmp, "CONV", line, col)) { value_free(out); return value_null(); }
4028+
acc += tmp;
4029+
} else { value_free(out); RUNTIME_ERROR(interp, "CONV bias must be numeric", line, col); }
39534030
}
39544031
ot->data[ow * ot->strides[0] + oh * ot->strides[1] + oc * ot->strides[2]] = value_int(acc);
39554032
} else {
@@ -5009,7 +5086,9 @@ static Value builtin_int(Interpreter* interp, Value* args, int argc, Expr** arg_
50095086
if (args[0].type == VAL_FLT) {
50105087
int b = numeric_base_of(args[0]);
50115088
if (b <= 0) b = 2;
5012-
return value_int_base((int64_t)args[0].as.f, b);
5089+
int64_t tmp;
5090+
if (!coerce_flt_to_int_checked(interp, args[0].as.f, &tmp, "INT", line, col)) return value_null();
5091+
return value_int_base(tmp, b);
50135092
}
50145093
if (args[0].type == VAL_STR) {
50155094
int64_t val = 0;
@@ -7148,7 +7227,13 @@ static Value builtin_isum(Interpreter* interp, Value* args, int argc, Expr** arg
71487227
int64_t sum = 0;
71497228
for (int i = 0; i < argc; i++) {
71507229
EXPECT_NUM(args[i], "ISUM", interp, line, col);
7151-
sum += args[i].type == VAL_INT ? args[i].as.i : (int64_t)args[i].as.f;
7230+
if (args[i].type == VAL_INT) {
7231+
sum += args[i].as.i;
7232+
} else {
7233+
int64_t tmp;
7234+
if (!coerce_flt_to_int_checked(interp, args[i].as.f, &tmp, "ISUM", line, col)) return value_null();
7235+
sum += tmp;
7236+
}
71527237
}
71537238
return value_int(sum);
71547239
}
@@ -7178,7 +7263,13 @@ static Value builtin_iprod(Interpreter* interp, Value* args, int argc, Expr** ar
71787263
int64_t prod = 1;
71797264
for (int i = 0; i < argc; i++) {
71807265
EXPECT_NUM(args[i], "IPROD", interp, line, col);
7181-
prod *= args[i].type == VAL_INT ? args[i].as.i : (int64_t)args[i].as.f;
7266+
if (args[i].type == VAL_INT) {
7267+
prod *= args[i].as.i;
7268+
} else {
7269+
int64_t tmp;
7270+
if (!coerce_flt_to_int_checked(interp, args[i].as.f, &tmp, "IPROD", line, col)) return value_null();
7271+
prod *= tmp;
7272+
}
71827273
}
71837274
return value_int(prod);
71847275
}

0 commit comments

Comments
 (0)