shithub: sl

Download patch

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);
 }