summaryrefslogtreecommitdiff
path: root/include/ruby/internal
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2024-12-24 17:46:43 -0500
committerPeter Zhu <peter@peterzhu.ca>2025-01-02 11:03:04 -0500
commit99ff0224a564b59df3ba8fbd7911dd41a7fdde34 (patch)
tree50119e2d938e21080f7950ab9f067a0f63b78ce3 /include/ruby/internal
parentb8c4af24f920a973cfa1f7b671825e8a5421368c (diff)
Move rbimpl_size_add_overflow from gc.c to memory.h
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/12459
Diffstat (limited to 'include/ruby/internal')
-rw-r--r--include/ruby/internal/memory.h87
1 files changed, 87 insertions, 0 deletions
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.