Skip to content

Commit edb1c82

Browse files
committed
Add integer overflow check macros for add/sub as well as mul
1 parent d196947 commit edb1c82

File tree

3 files changed

+114
-24
lines changed

3 files changed

+114
-24
lines changed

configure.ac

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ RUBY_M4_INCLUDE([colorize_result.m4])dnl
2020
RUBY_M4_INCLUDE([ruby_append_option.m4])dnl
2121
RUBY_M4_INCLUDE([ruby_append_options.m4])dnl
2222
RUBY_M4_INCLUDE([ruby_check_builtin_func.m4])dnl
23+
RUBY_M4_INCLUDE([ruby_check_builtin_overflow.m4])dnl
2324
RUBY_M4_INCLUDE([ruby_check_builtin_setjmp.m4])dnl
2425
RUBY_M4_INCLUDE([ruby_check_header.m4])dnl
2526
RUBY_M4_INCLUDE([ruby_check_printf_prefix.m4])dnl
@@ -2297,10 +2298,6 @@ RUBY_CHECK_BUILTIN_FUNC(__builtin_clzl, [__builtin_clzl(0)])
22972298
RUBY_CHECK_BUILTIN_FUNC(__builtin_clzll, [__builtin_clzll(0)])
22982299
RUBY_CHECK_BUILTIN_FUNC(__builtin_ctz, [__builtin_ctz(0)])
22992300
RUBY_CHECK_BUILTIN_FUNC(__builtin_ctzll, [__builtin_ctzll(0)])
2300-
RUBY_CHECK_BUILTIN_FUNC(__builtin_add_overflow, [int x;__builtin_add_overflow(0,0,&x)])
2301-
RUBY_CHECK_BUILTIN_FUNC(__builtin_sub_overflow, [int x;__builtin_sub_overflow(0,0,&x)])
2302-
RUBY_CHECK_BUILTIN_FUNC(__builtin_mul_overflow, [int x;__builtin_mul_overflow(0,0,&x)])
2303-
RUBY_CHECK_BUILTIN_FUNC(__builtin_mul_overflow_p, [__builtin_mul_overflow_p(0,0,(int)0)])
23042301
RUBY_CHECK_BUILTIN_FUNC(__builtin_constant_p, [__builtin_constant_p(0)])
23052302
RUBY_CHECK_BUILTIN_FUNC(__builtin_choose_expr, [
23062303
[int x[__extension__(__builtin_choose_expr(1, 1, -1))]];
@@ -2316,26 +2313,9 @@ RUBY_CHECK_BUILTIN_FUNC(__builtin_types_compatible_p, [__builtin_types_compatibl
23162313
RUBY_CHECK_BUILTIN_FUNC(__builtin_trap, [__builtin_trap()])
23172314
RUBY_CHECK_BUILTIN_FUNC(__builtin_expect, [__builtin_expect(0, 0)])
23182315

2319-
AS_IF([test "$rb_cv_builtin___builtin_mul_overflow" != no], [
2320-
AC_CACHE_CHECK(for __builtin_mul_overflow with long long arguments, rb_cv_use___builtin_mul_overflow_long_long, [
2321-
AC_LINK_IFELSE([AC_LANG_SOURCE([[
2322-
#pragma clang optimize off
2323-
2324-
int
2325-
main(void)
2326-
{
2327-
long long x = 0, y;
2328-
__builtin_mul_overflow(x, x, &y);
2329-
2330-
return 0;
2331-
}
2332-
]])],
2333-
rb_cv_use___builtin_mul_overflow_long_long=yes,
2334-
rb_cv_use___builtin_mul_overflow_long_long=no)])
2335-
])
2336-
AS_IF([test "$rb_cv_use___builtin_mul_overflow_long_long" = yes], [
2337-
AC_DEFINE(USE___BUILTIN_MUL_OVERFLOW_LONG_LONG, 1)
2338-
])
2316+
RUBY_CHECK_BUILTIN_OVERFLOW(add)
2317+
RUBY_CHECK_BUILTIN_OVERFLOW(sub)
2318+
RUBY_CHECK_BUILTIN_OVERFLOW(mul)
23392319

23402320
AS_IF([test "$ac_cv_func_qsort_r" != no], [
23412321
AC_CACHE_CHECK(whether qsort_r is GNU version, rb_cv_gnu_qsort_r,

internal/bits.h

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090

9191
#define UNSIGNED_INTEGER_MAX(T) ((T)~(T)0)
9292

93+
#ifndef MUL_OVERFLOW_SIGNED_INTEGER_P
9394
#if __has_builtin(__builtin_mul_overflow_p)
9495
# define MUL_OVERFLOW_P(a, b) \
9596
__builtin_mul_overflow_p((a), (b), (__typeof__(a * b))0)
@@ -131,6 +132,87 @@
131132
# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
132133
# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
133134
#endif
135+
#endif
136+
137+
#ifndef ADD_OVERFLOW_SIGNED_INTEGER_P
138+
#if __has_builtin(__builtin_add_overflow_p)
139+
# define ADD_OVERFLOW_P(a, b) \
140+
__builtin_add_overflow_p((a), (b), (__typeof__(a * b))0)
141+
#elif __has_builtin(__builtin_add_overflow)
142+
# define ADD_OVERFLOW_P(a, b) \
143+
__extension__ ({ __typeof__(a) c; __builtin_add_overflow((a), (b), &c); })
144+
#endif
145+
146+
#define ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
147+
(a) > 0 ? (b) > (max) - (a) : (b) < (min) - (a))
148+
149+
#if __has_builtin(__builtin_add_overflow_p)
150+
/* __builtin_add_overflow_p can take bitfield */
151+
/* and GCC permits bitfields for integers other than int */
152+
# define ADD_OVERFLOW_FIXNUM_P(a, b) \
153+
__extension__ ({ \
154+
struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \
155+
__builtin_add_overflow_p((a), (b), c.fixnum); \
156+
})
157+
#else
158+
# define ADD_OVERFLOW_FIXNUM_P(a, b) \
159+
ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
160+
#endif
161+
162+
#if defined(ADD_OVERFLOW_P) && defined(USE___BUILTIN_ADD_OVERFLOW_LONG_LONG)
163+
# define ADD_OVERFLOW_LONG_LONG_P(a, b) ADD_OVERFLOW_P(a, b)
164+
#else
165+
# define ADD_OVERFLOW_LONG_LONG_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
166+
#endif
167+
168+
#ifdef ADD_OVERFLOW_P
169+
# define ADD_OVERFLOW_LONG_P(a, b) ADD_OVERFLOW_P(a, b)
170+
# define ADD_OVERFLOW_INT_P(a, b) ADD_OVERFLOW_P(a, b)
171+
#else
172+
# define ADD_OVERFLOW_LONG_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
173+
# define ADD_OVERFLOW_INT_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
174+
#endif
175+
#endif
176+
177+
#ifndef SUB_OVERFLOW_SIGNED_INTEGER_P
178+
#if __has_builtin(__builtin_sub_overflow_p)
179+
# define SUB_OVERFLOW_P(a, b) \
180+
__builtin_sub_overflow_p((a), (b), (__typeof__(a * b))0)
181+
#elif __has_builtin(__builtin_sub_overflow)
182+
# define SUB_OVERFLOW_P(a, b) \
183+
__extension__ ({ __typeof__(a) c; __builtin_sub_overflow((a), (b), &c); })
184+
#endif
185+
186+
#define SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
187+
(b) > 0 ? (a) < (min) + (b) : (a) > (max) + (b))
188+
189+
#if __has_builtin(__builtin_sub_overflow_p)
190+
/* __builtin_sub_overflow_p can take bitfield */
191+
/* and GCC permits bitfields for integers other than int */
192+
# define SUB_OVERFLOW_FIXNUM_P(a, b) \
193+
__extension__ ({ \
194+
struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \
195+
__builtin_sub_overflow_p((a), (b), c.fixnum); \
196+
})
197+
#else
198+
# define SUB_OVERFLOW_FIXNUM_P(a, b) \
199+
SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
200+
#endif
201+
202+
#if defined(SUB_OVERFLOW_P) && defined(USE___BUILTIN_SUB_OVERFLOW_LONG_LONG)
203+
# define SUB_OVERFLOW_LONG_LONG_P(a, b) SUB_OVERFLOW_P(a, b)
204+
#else
205+
# define SUB_OVERFLOW_LONG_LONG_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
206+
#endif
207+
208+
#ifdef SUB_OVERFLOW_P
209+
# define SUB_OVERFLOW_LONG_P(a, b) SUB_OVERFLOW_P(a, b)
210+
# define SUB_OVERFLOW_INT_P(a, b) SUB_OVERFLOW_P(a, b)
211+
#else
212+
# define SUB_OVERFLOW_LONG_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
213+
# define SUB_OVERFLOW_INT_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
214+
#endif
215+
#endif
134216

135217
#ifdef HAVE_UINT128_T
136218
# define bit_length(x) \
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
dnl -*- Autoconf -*-
2+
AC_DEFUN([RUBY_CHECK_BUILTIN_OVERFLOW], [dnl
3+
{ # $0($1)
4+
RUBY_CHECK_BUILTIN_FUNC(__builtin_[$1]_overflow, [int x;__builtin_[$1]_overflow(0,0,&x)])
5+
RUBY_CHECK_BUILTIN_FUNC(__builtin_[$1]_overflow_p, [__builtin_[$1]_overflow_p(0,0,(int)0)])
6+
7+
AS_IF([test "$rb_cv_builtin___builtin_[$1]_overflow" != no], [
8+
AC_CACHE_CHECK(for __builtin_[$1]_overflow with long long arguments, rb_cv_use___builtin_[$1]_overflow_long_long, [
9+
AC_LINK_IFELSE([AC_LANG_SOURCE([[
10+
@%:@pragma clang optimize off
11+
12+
int
13+
main(void)
14+
{
15+
long long x = 0, y;
16+
__builtin_$1_overflow(x, x, &y);
17+
18+
return 0;
19+
}
20+
]])],
21+
rb_cv_use___builtin_[$1]_overflow_long_long=yes,
22+
rb_cv_use___builtin_[$1]_overflow_long_long=no)])
23+
])
24+
AS_IF([test "$rb_cv_use___builtin_[$1]_overflow_long_long" = yes], [
25+
AC_DEFINE(USE___BUILTIN_[]AS_TR_CPP($1)_OVERFLOW_LONG_LONG, 1)
26+
])
27+
}
28+
])dnl

0 commit comments

Comments
 (0)