authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-02-09 08:10:20-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-10 17:22:16-08:00
log5433e0438ce464adea53e4849a80d3854b2a036d
tree4eca082f73367f4fb6ea53a9ec8bdb7fce3b38ee
parent8d078f1ba255eb2a60a7fdef4d73c35a33d24802

cbe: fix ub triggered by mulw overflowing the promoted type

Closes #21914

2 files changed, 94 insertions(+), 6 deletions(-)

lib/zig.h+38-6
......@@ -650,7 +650,7 @@ typedef ptrdiff_t intptr_t;
650650 zig_operator(Type, Type, operation, operator)
651651#define zig_shift_operator(Type, operation, operator) \
652652 zig_operator(Type, uint8_t, operation, operator)
653#define zig_int_helpers(w) \
653#define zig_int_helpers(w, PromotedUnsigned) \
654654 zig_basic_operator(uint##w##_t, and_u##w, &) \
655655 zig_basic_operator( int##w##_t, and_i##w, &) \
656656 zig_basic_operator(uint##w##_t, or_u##w, |) \
......@@ -726,16 +726,48 @@ typedef ptrdiff_t intptr_t;
726726 } \
727727\
728728 static inline uint##w##_t zig_mulw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \
729 return zig_wrap_u##w(lhs * rhs, bits); \
729 return zig_wrap_u##w((PromotedUnsigned)lhs * rhs, bits); \
730730 } \
731731\
732732 static inline int##w##_t zig_mulw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
733733 return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs * (uint##w##_t)rhs), bits); \
734734 }
735zig_int_helpers(8)
736zig_int_helpers(16)
737zig_int_helpers(32)
738zig_int_helpers(64)
735#if UINT8_MAX <= UINT_MAX
736zig_int_helpers(8, unsigned int)
737#elif UINT8_MAX <= ULONG_MAX
738zig_int_helpers(8, unsigned long)
739#elif UINT8_MAX <= ULLONG_MAX
740zig_int_helpers(8, unsigned long long)
741#else
742zig_int_helpers(8, uint8_t)
743#endif
744#if UINT16_MAX <= UINT_MAX
745zig_int_helpers(16, unsigned int)
746#elif UINT16_MAX <= ULONG_MAX
747zig_int_helpers(16, unsigned long)
748#elif UINT16_MAX <= ULLONG_MAX
749zig_int_helpers(16, unsigned long long)
750#else
751zig_int_helpers(16, uint16_t)
752#endif
753#if UINT32_MAX <= UINT_MAX
754zig_int_helpers(32, unsigned int)
755#elif UINT32_MAX <= ULONG_MAX
756zig_int_helpers(32, unsigned long)
757#elif UINT32_MAX <= ULLONG_MAX
758zig_int_helpers(32, unsigned long long)
759#else
760zig_int_helpers(32, uint32_t)
761#endif
762#if UINT64_MAX <= UINT_MAX
763zig_int_helpers(64, unsigned int)
764#elif UINT64_MAX <= ULONG_MAX
765zig_int_helpers(64, unsigned long)
766#elif UINT64_MAX <= ULLONG_MAX
767zig_int_helpers(64, unsigned long long)
768#else
769zig_int_helpers(64, uint64_t)
770#endif
739771
740772static inline bool zig_addo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) {
741773#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
test/behavior/math.zig+56
......@@ -778,6 +778,62 @@ fn should_not_be_zero(x: f128) !void {
778778 try expect(x != 0.0);
779779}
780780
781test "umax wrapped squaring" {
782 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
783 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
784
785 {
786 var x: u4 = maxInt(u4);
787 x *%= x;
788 try expect(x == 1);
789 }
790 {
791 var x: u8 = maxInt(u8);
792 x *%= x;
793 try expect(x == 1);
794 }
795 {
796 var x: u12 = maxInt(u12);
797 x *%= x;
798 try expect(x == 1);
799 }
800 {
801 var x: u16 = maxInt(u16);
802 x *%= x;
803 try expect(x == 1);
804 }
805 {
806 var x: u24 = maxInt(u24);
807 x *%= x;
808 try expect(x == 1);
809 }
810 {
811 var x: u32 = maxInt(u32);
812 x *%= x;
813 try expect(x == 1);
814 }
815 {
816 var x: u48 = maxInt(u48);
817 x *%= x;
818 try expect(x == 1);
819 }
820 {
821 var x: u64 = maxInt(u64);
822 x *%= x;
823 try expect(x == 1);
824 }
825 {
826 var x: u96 = maxInt(u96);
827 x *%= x;
828 try expect(x == 1);
829 }
830 {
831 var x: u128 = maxInt(u128);
832 x *%= x;
833 try expect(x == 1);
834 }
835}
836
781837test "128-bit multiplication" {
782838 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
783839 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO