The previous code computed `frac_part * pow10_negative[n]`, where
pow10_negative[n] is already a rounded approximation of 10^-n (since
10^-n is not exactly representable in binary). The multiplication then
adds another rounding step, leaving up to ~1 ulp of error.
Dividing `frac_part` by `pow10_positive[n]` is exact for n <= 22 (the
range where 10^n fits exactly in a double), so the division is the
only rounding and the result is correctly rounded. For example,
"0.3".to_f now matches the 0.3 literal's bit pattern (and libc strtod).
build_config/host-cxx.rb defaulted to MRuby::Build.new (no name),
which is equivalent to MRuby::Build.new('host'), so it shared
build/host/ with build_config/host-debug.rb.
The two configs produce ABI-incompatible object files (C linkage
vs. C++-mangled). Switching between configs without a clean step
silently mixes stale objects, leading to confusing undefined
reference errors at link time.
Name the C++ build 'host-cxx' so it gets its own build/host-cxx/
directory. No external paths reference build/host/ in a way that
this change would break.
Co-authored-by: Claude <noreply@anthropic.com>
MPZ_CTX_INIT used a compound literal with designated initializers:
mpz_ctx_t ctx##_struct = ((mpz_ctx_t){.mrb = ..., .pool = ...});
Both features are C99-only, and are not accepted by legacy C++
compilers (notably gcc 4.x) when mruby is pulled into a C++
translation unit via the -cxx.cxx wrapper.
Replace with plain member assignment so the macro expands to code
that is valid under C89/C++98 as well.
Co-authored-by: Claude <noreply@anthropic.com>
Older C++ compilers (notably gcc 4.x) do not support C99 struct field
designators (.func = ...) even as an extension, which blocks building
mruby when it is included from a C++ translation unit under such
toolchains.
Reorder union mrb_mt_ptr so that mrb_func_t is the first member, and
switch MRB_MT_ENTRY to positional aggregate initialization. Both are
compatible with pre-C99 / pre-C++20 compilers.
Fixes#6789
Co-authored-by: Claude <noreply@anthropic.com>
`mrb_class_get_id()` may call the `#const_missing` method.
Therefore, if the `mesg` string originates from a string object, it may reference an invalid address.
And since `errno` might also change during the call to `#const_missing`, save this as well beforehand.
Also, while `mrb_class_defined_id()` does not currently call the `#const_defined?` method, it is unclear whether this will remain the case in the future.
`mrb_str_dup()` always duplicates string objects in an unfrozen state, and the class is also set.
Therefore, it can be observed and modified from the Ruby side using the `ObjectSpace.each_object` method.
By using `mrb_str_dup_frozen()`, unnecessary duplication can be avoided, and modifications to the string can also be prevented.
Compress the 24-bit aspec into 13 free flag bits on RProc (bits 0-6
and 14-19) when wrapping cfunc methods. Field widths: req/opt 3 bits
(max 7), post/key 2 bits (max 3), rest/kdict/block 1 bit each. Values
exceeding the compressed range are clamped and rest is forced to 1.
This enables Proc#arity and Proc#parameters to return correct results
for cfunc-backed Procs (e.g. from Method#to_proc) with zero memory
overhead -- no struct change needed.
Closes#6764
mrb_str_format captured raw C pointers (p, end) into the format
string's buffer before the main loop. The %s and %p specifiers call
to_s and inspect, which can invoke Ruby code that mutates the format
string via String#replace, freeing or reallocating its buffer. The
loop then continued iterating with dangling pointers, reading freed
memory and potentially leaking adjacent heap contents into the result.
Duplicate the format string with mrb_str_dup() before the loop. This
is O(1) because mrb_str_dup shares the underlying buffer; if the
original is later mutated via String#replace, str_replace decrements
the shared refcount, leaving our duplicate's buffer intact.
Co-authored-by: Claude <noreply@anthropic.com>
String#prepend(s, s) read RSTRING_LEN(argv[i]) in the copy loop after
mrb_str_resize had already updated the receiver's length, causing the
memcpy to write past the allocated buffer.
Detect self-references with mrb_obj_eq() and read from the memmoved
original data at p + total_prepend_len using the captured self_len.
This also handles mixed cases like s.prepend("X", s) where earlier
writes would otherwise corrupt the source of later reads.
Co-authored-by: Claude <noreply@anthropic.com>
The "d" directive in `mrb_get_args()` can be used as an alternative.
Furthermore, NULL checking is unnecessary for the following reasons:
- Incomplete objects from `ary_combination_init()` are not passed to the caller and are garbage collected when `ObjectSpace.each_object` is called, so they are never retrieved
- Even if `state.clone` is called, the `RData::type` of the cloned object is set to NULL, so it is rejected by `mrb_get_args()`
Add entries for language changes (case/in NoMatchingPatternError,
compound statement in tLPAREN_ARG), C API additions (mrb_bigint_p(),
RVALUE union), compiler optimizations (literal chunking), build
fixes (MSYS2), security fixes, and 26 merged pull requests.
Co-authored-by: Claude <noreply@anthropic.com>
The s = self workaround and XXX comment in recvfrom_nonblock date back
to the initial import of mruby-socket. The underlying bug where self
became a SystemcallException inside ensure blocks has since been fixed.
Verified that self correctly refers to the socket object in ensure
blocks after exceptions from recvfrom.