From 99ff0224a564b59df3ba8fbd7911dd41a7fdde34 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Tue, 24 Dec 2024 17:46:43 -0500 Subject: [PATCH] Move rbimpl_size_add_overflow from gc.c to memory.h --- gc.c | 40 ++++------------ include/ruby/internal/memory.h | 87 ++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 30 deletions(-) diff --git a/gc.c b/gc.c index 68304d26c5..386d6d0c02 100644 --- a/gc.c +++ b/gc.c @@ -480,39 +480,11 @@ rb_malloc_grow_capa(size_t current, size_t type_size) return new_capacity; } -static inline struct rbimpl_size_mul_overflow_tag -size_add_overflow(size_t x, size_t y) -{ - size_t z; - bool p; -#if 0 - -#elif defined(ckd_add) - p = ckd_add(&z, x, y); - -#elif __has_builtin(__builtin_add_overflow) - p = __builtin_add_overflow(x, y, &z); - -#elif defined(DSIZE_T) - RB_GNUC_EXTENSION DSIZE_T dx = x; - RB_GNUC_EXTENSION DSIZE_T dy = y; - RB_GNUC_EXTENSION DSIZE_T dz = dx + dy; - p = dz > SIZE_MAX; - z = (size_t)dz; - -#else - z = x + y; - p = z < y; - -#endif - return (struct rbimpl_size_mul_overflow_tag) { p, z, }; -} - static inline struct rbimpl_size_mul_overflow_tag size_mul_add_overflow(size_t x, size_t y, size_t z) /* x * y + z */ { struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y); - struct rbimpl_size_mul_overflow_tag u = size_add_overflow(t.right, z); + struct rbimpl_size_mul_overflow_tag u = rbimpl_size_add_overflow(t.right, z); return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left, u.right }; } @@ -521,7 +493,7 @@ size_mul_add_mul_overflow(size_t x, size_t y, size_t z, size_t w) /* x * y + z * { struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y); struct rbimpl_size_mul_overflow_tag u = rbimpl_size_mul_overflow(z, w); - struct rbimpl_size_mul_overflow_tag v = size_add_overflow(t.right, u.right); + struct rbimpl_size_mul_overflow_tag v = rbimpl_size_add_overflow(t.right, u.right); return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left || v.left, v.right }; } @@ -4590,6 +4562,14 @@ ruby_malloc_size_overflow(size_t count, size_t elsize) count, elsize); } +void +ruby_malloc_add_size_overflow(size_t x, size_t y) +{ + rb_raise(rb_eArgError, + "malloc: possible integer overflow (%"PRIuSIZE"+%"PRIuSIZE")", + x, y); +} + static void *ruby_xmalloc2_body(size_t n, size_t size); void * diff --git a/include/ruby/internal/memory.h b/include/ruby/internal/memory.h index d231e62982..9fc6c39efc 100644 --- a/include/ruby/internal/memory.h +++ b/include/ruby/internal/memory.h @@ -488,6 +488,18 @@ RBIMPL_ATTR_NORETURN() */ void ruby_malloc_size_overflow(size_t x, size_t y); +RBIMPL_ATTR_NORETURN() +/** + * @private + * + * This is an implementation detail. People don't use this directly. + * + * @param[in] x Arbitrary value. + * @param[in] y Arbitrary value. + * @exception rb_eArgError `x` + `y` would integer overflow. + */ +void ruby_malloc_add_size_overflow(size_t x, size_t y); + #ifdef HAVE_RB_GC_GUARDED_PTR_VAL volatile VALUE *rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val); #endif @@ -635,6 +647,81 @@ rbimpl_size_mul_or_raise(size_t x, size_t y) } } +#if defined(__DOXYGEN__) +RBIMPL_ATTR_CONSTEXPR(CXX14) +#elif RBIMPL_COMPILER_SINCE(GCC, 7, 0, 0) +RBIMPL_ATTR_CONSTEXPR(CXX14) /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70507 */ +#elif RBIMPL_COMPILER_SINCE(Clang, 7, 0, 0) +RBIMPL_ATTR_CONSTEXPR(CXX14) /* https://bugs.llvm.org/show_bug.cgi?id=37633 */ +#endif +RBIMPL_ATTR_CONST() +/** + * @private + * + * This is an implementation detail. People don't use this directly. + * + * @param[in] x Arbitrary value. + * @param[in] y Arbitrary value. + * @return `{ left, right }`, where `left` is whether there is an integer + * overflow or not, and `right` is a (possibly overflowed) result + * of `x` + `y`. + * + * @internal + */ +static inline struct rbimpl_size_mul_overflow_tag +rbimpl_size_add_overflow(size_t x, size_t y) +{ + struct rbimpl_size_mul_overflow_tag ret = { false, 0, }; + +#if defined(ckd_add) + ret.left = ckd_add(&ret.right, x, y); + +#elif RBIMPL_HAS_BUILTIN(__builtin_add_overflow) + ret.left = __builtin_add_overflow(x, y, &ret.right); + +#elif defined(DSIZE_T) + RB_GNUC_EXTENSION DSIZE_T dx = x; + RB_GNUC_EXTENSION DSIZE_T dy = y; + RB_GNUC_EXTENSION DSIZE_T dz = dx + dy; + ret.left = dz > SIZE_MAX; + ret.right = (size_t)dz; + +#else + ret.right = x + y; + ret.left = ret.right < y; + +#endif + + return ret; +} + +/** + * @private + * + * This is an implementation detail. People don't use this directly. + * + * @param[in] x Arbitrary value. + * @param[in] y Arbitrary value. + * @exception rb_eArgError Multiplication could integer overflow. + * @return `x` + `y`. + * + * @internal + */ +static inline size_t +rbimpl_size_add_or_raise(size_t x, size_t y) +{ + struct rbimpl_size_mul_overflow_tag size = + rbimpl_size_add_overflow(x, y); + + if (RB_LIKELY(!size.left)) { + return size.right; + } + else { + ruby_malloc_add_size_overflow(x, y); + RBIMPL_UNREACHABLE_RETURN(0); + } +} + /** * This is an implementation detail of #RB_ALLOCV_N(). People don't use this * directly.