error.h: fix RBreak size overflow on 32-bit platforms with MRB_NO_BOXING

On 32-bit platforms where alignof(int64_t) == 8 (ARM, MIPS, PowerPC,
RISC-V, MinGW), struct RBreak with MRB_USE_RBREAK_VALUE_UNION was 24
bytes (6 words) due to alignment padding before the union
mrb_value_union field. This exceeds the 5-word RVALUE limit, causing
a static assertion failure.

Replace union mrb_value_union with uint32_t[] storage (alignof == 4)
and use memcpy for value access. This gives exactly 20 bytes on all
32-bit platforms. Ref #6722

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-03-01 23:08:53 +09:00
parent 98bc495fd2
commit 74267ce91e
+8 -3
View File
@@ -8,6 +8,7 @@
#define MRUBY_ERROR_H
#include "common.h"
#include <string.h>
/**
* mruby error handling.
@@ -53,7 +54,11 @@ struct RBreak {
#ifndef MRB_USE_RBREAK_VALUE_UNION
mrb_value val;
#else
union mrb_value_union value;
/* Store value as uint32_t words instead of union mrb_value_union
to avoid 8-byte alignment of int64_t/double on 32-bit platforms
(e.g., ARM, MIPS, PowerPC) which would inflate struct size beyond
the 5-word RVALUE limit due to padding. */
uint32_t value[sizeof(union mrb_value_union) / sizeof(uint32_t)];
#endif
};
@@ -66,14 +71,14 @@ static inline mrb_value
mrb_break_value_get(struct RBreak *brk)
{
mrb_value val;
val.value = brk->value;
memcpy(&val.value, brk->value, sizeof(val.value));
val.tt = (enum mrb_vtype)(brk->flags & RBREAK_VALUE_TT_MASK);
return val;
}
static inline void
mrb_break_value_set(struct RBreak *brk, mrb_value val)
{
brk->value = val.value;
memcpy(brk->value, &val.value, sizeof(val.value));
brk->flags &= ~RBREAK_VALUE_TT_MASK;
brk->flags |= val.tt;
}