From 721dccf636f6a74310233aca29c1a587c0ab8bce Mon Sep 17 00:00:00 2001 From: dzaima Date: Sat, 19 Aug 2023 19:47:09 +0300 Subject: [PATCH] fix FFI integer overflow check on ARM clang optimizes a raw f!=(u8)f to like f!=(u32)f on ARM which changes behavior (we're technically using UB here, but there's no reasonable alternative); use q_ functions that know how to work around this --- src/ffi.c | 16 ++++++++-------- src/h.h | 5 +++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/ffi.c b/src/ffi.c index f109736e..899e1421 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -623,14 +623,14 @@ void genObj(B o, B c, bool anyMut, void* ptr) { switch(t) { default: UD; // thrF("FFI: Unimplemented scalar type \"%S\"", sty_names[t]); case sty_a: *(BQNV*)ptr = makeX(inc(c)); break; case sty_ptr: thrM("FFI: \"*\" unimplemented"); break; - case sty_u8: { u8 i = ( u8)f; if(f!=i) thrM("FFI: u8 argument not exact" ); *( u8*)ptr = i; break; } - case sty_i8: { i8 i = ( i8)f; if(f!=i) thrM("FFI: i8 argument not exact" ); *( i8*)ptr = i; break; } - case sty_u16: { u16 i = (u16)f; if(f!=i) thrM("FFI: u16 argument not exact"); *(u16*)ptr = i; break; } - case sty_i16: { i16 i = (i16)f; if(f!=i) thrM("FFI: i16 argument not exact"); *(i16*)ptr = i; break; } - case sty_u32: { u32 i = (u32)f; if(f!=i) thrM("FFI: u32 argument not exact"); *(u32*)ptr = i; break; } - case sty_i32: { i32 i = (i32)f; if(f!=i) thrM("FFI: i32 argument not exact"); *(i32*)ptr = i; break; } - case sty_u64: { u64 i = (u64)f; if(f!=i) thrM("FFI: u64 argument not exact"); if (i>=(1ULL<<53)) thrM("FFI: u64 argument value ≥ 2⋆53"); *(u64*)ptr = i; break; } - case sty_i64: { i64 i = (i64)f; if(f!=i) thrM("FFI: i64 argument not exact"); if (i>=(1LL<<53) || i<=-(1LL<<53)) thrM("FFI: i64 argument absolute value ≥ 2⋆53"); *(i64*)ptr = i; break; } + case sty_u8: { if(!q_fu8 (f)) thrM("FFI: u8 argument not exact" ); *( u8*)ptr = ( u8)f; break; } + case sty_i8: { if(!q_fi8 (f)) thrM("FFI: i8 argument not exact" ); *( i8*)ptr = ( i8)f; break; } + case sty_u16: { if(!q_fu16(f)) thrM("FFI: u16 argument not exact"); *(u16*)ptr = (u16)f; break; } + case sty_i16: { if(!q_fi16(f)) thrM("FFI: i16 argument not exact"); *(i16*)ptr = (i16)f; break; } + case sty_u32: { if(!q_fu32(f)) thrM("FFI: u32 argument not exact"); *(u32*)ptr = (u32)f; break; } + case sty_i32: { if(!q_fi32(f)) thrM("FFI: i32 argument not exact"); *(i32*)ptr = (i32)f; break; } + case sty_u64: { if(!q_fu64(f)) thrM("FFI: u64 argument not exact"); u64 i=(u64)f; if (i>=(1ULL<<53)) thrM("FFI: u64 argument value ≥ 2⋆53"); *(u64*)ptr = i; break; } + case sty_i64: { if(!q_fi64(f)) thrM("FFI: i64 argument not exact"); i64 i=(i64)f; if (i>=(1LL<<53) || i<=-(1LL<<53)) thrM("FFI: i64 argument absolute value ≥ 2⋆53"); *(i64*)ptr = i; break; } case sty_f32: *(float* )ptr = f; break; case sty_f64: *(double*)ptr = f; break; } diff --git a/src/h.h b/src/h.h index 605b32c1..94659756 100644 --- a/src/h.h +++ b/src/h.h @@ -492,6 +492,10 @@ FORCE_INLINE bool q_fi64(f64 x) { return x==(f64)(i64) x; } FORCE_INLINE bo FORCE_INLINE bool q_fu64(f64 x) { return x==(f64)(u64) x; } FORCE_INLINE bool q_u64(B x) { return q_fu64(x.f); } FORCE_INLINE bool q_fusz(f64 x) { return x==(f64)(usz) x; } FORCE_INLINE bool q_usz(B x) { return q_fusz(x.f); } /*no need for a q_ff64*/ FORCE_INLINE bool q_f64(B x) { return isF64(x); } +FORCE_INLINE bool q_fu8 (f64 x) { return x==(f64)(u8 )(u32)x; } +FORCE_INLINE bool q_fu16(f64 x) { return x==(f64)(u16)(u32)x; } +FORCE_INLINE bool q_fu32(f64 x) { return x==(f64)(u32) x; } + FORCE_INLINE bool q_ibit(i64 x) { return x==0 | x==1; } FORCE_INLINE bool q_ubit(u64 x) { return x==0 | x==1; } FORCE_INLINE bool q_c8 (B x) { return x.u>>8 == ((u64)C32_TAG)<<40; } @@ -500,6 +504,7 @@ FORCE_INLINE bool q_c32(B x) { return isC32(x); } FORCE_INLINE bool q_N (B x) { return x.u==bi_N.u; } // is · FORCE_INLINE bool noFill(B x) { return x.u==bi_noFill.u; } + FORCE_INLINE bool o2bG(B x) { return(x.u<<1)!=0;} FORCE_INLINE bool o2b(B x) { i32 t=(i32)x.f; if(t!=x.f || t!=0&t!=1)thrM("Expected boolean"); return o2bG(x); } FORCE_INLINE i32 o2iG(B x) { return (i32)x.f; } FORCE_INLINE i32 o2i(B x) { if (!q_i32(x)) thrM("Expected integer"); return o2iG(x); } FORCE_INLINE u32 o2cG(B x) { return (u32)x.u; } FORCE_INLINE u32 o2c(B x) { if (!isC32(x)) thrM("Expected character"); return o2cG(x); }