ref: d8eb8e5e022b06179cfa69c784daed68fdac0ba0
parent: a9541f71c451036fce7df6656b5f04780a34bd55
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri Mar 21 22:19:06 EDT 2025
ash: bug fixes to avoid UBs and use bignums References: https://todo.sr.ht/~ft/sl/11
--- a/src/cvalues.c
+++ b/src/cvalues.c
@@ -1238,6 +1238,12 @@
type_error("int", a);
}
+#define sash_overflow_64(a, b, c) ( \
+ ((a)<0 || (a)>(INT64_MAX>>(b))) \
+ ? 1 \
+ : ((*(c)=(a)<<(b)), 0) \
+)
+
BUILTIN("ash", ash)
{
sl_fx n;
@@ -1250,11 +1256,16 @@
argcount(nargs, 2);
sl_v a = args[0];
n = tofixnum(args[1]);
+ mp = nil;
if(isfixnum(a)){
- if(n <= 0)
+ accum = numval(a);
+ if(accum >= 0 && n > -64 && n <= 0)
return fixnum(numval(a)>>(-n));
- accum = ((s64int)numval(a))<<n;
- return fits_fixnum(accum) ? fixnum(accum) : return_from_s64(accum);
+ if(n < 0 || n >= 64 || sash_overflow_64(accum, n, &accum)){
+ mp = vtomp(accum, nil);
+ mpleft(mp, n, mp);
+ }else
+ return fits_fixnum(accum) ? fixnum(accum) : return_from_s64(accum);
}
if(iscprim(a)){
if(n == 0)
@@ -1283,11 +1294,16 @@
return a;
aptr = cv_data(ptr(a));
mp = mpnew(0);
- if(n < 0)
- mpright(*(mpint**)aptr, -n, mp);
- else
- mpleft(*(mpint**)aptr, n, mp);
- return mk_mp(mp);
+ mpleft(*(mpint**)aptr, n, mp);
+ }
+ if(mp != nil){
+ n = mpsignif(mp);
+ if(n >= FIXNUM_BITS)
+ return mk_mp(mp);
+ accum = mptov(mp);
+ mpfree(mp);
+ assert(fits_fixnum(accum));
+ return fixnum((sl_fx)accum);
}
type_error("int", a);
}