benchmarking tools (mruby-benchmark) have been implemented.
update entry to focus on remaining profiler features:
method call tracing, stack profiling, and detailed memory analysis.
Co-authored-by: Claude <noreply@anthropic.com>
add 24 test cases covering all benchmark functionality:
- Benchmark.measure and Benchmark.realtime
- Benchmark::Tms class and its methods (total, to_s, format)
- Benchmark.bm for formatted comparison reports
- Benchmark::Report class
- memory tracking with ObjectSpace integration
- consistency and realistic usage scenarios
suppress output during tests by temporarily setting $stdout to nil
for tests that call Benchmark.bm or Report#report to avoid printing
garbage during test execution.
all tests pass successfully.
Co-authored-by: Claude <noreply@anthropic.com>
add pattern matching section to limitations.md clarifying that only
rightward assignment (expr => var) is currently supported, while
case/in syntax and other pattern types are not yet implemented.
Co-authored-by: Claude <noreply@anthropic.com>
reduce code duplication by introducing MRB_PROC_RESOLVE_ALIAS macro
to handle alias proc resolution in a consistent way across 5 locations.
Co-authored-by: Claude <noreply@anthropic.com>
fix implementation to work correctly in mruby:
- use String#% instead of sprintf for formatting
- use $stdout directly for output instead of bare print/puts
- add nil check for $stdout to handle test environments
- use Object.const_defined? instead of defined? keyword
- create new Tms instance with label instead of instance_variable_set
- add dependencies: mruby-sprintf and mruby-io
Co-authored-by: Claude <noreply@anthropic.com>
add full pattern matching implementation (case/in syntax, array/hash
patterns, guards, etc.) to the todo list for after mruby 3.4.
Co-authored-by: Claude <noreply@anthropic.com>
follow alias chains in mrb_proc_eql() to compare underlying procs,
making Method#== return true for aliased methods as in CRuby.
also fix typo where p1 was checked instead of p2 in CFUNC comparison.
Co-authored-by: Claude <noreply@anthropic.com>
when mpz_mod_2exp() is called with z == x (in-place operation), the
function was calling mpz_clear(ctx, z) which freed x's memory, then
attempting to access x->p[i] - reading freed memory. this caused
Barrett reduction to produce incorrect results in modular
exponentiation.
the fix checks if z == x and handles in-place modification by
adjusting the size and masking directly, without clearing. this is
similar to the memory leak fix for pool→heap transitions.
Co-authored-by: Claude <noreply@anthropic.com>
mpz_mod_2exp() was reinitializing its output parameter without clearing
existing heap memory. When the parameter contained heap allocations from
pool->heap transitions in mpz_mul()->mpz_realloc(), reinitializing would
overwrite the pointer and leak memory. Added mpz_clear() before each
mpz_init() or mpz_init_heap() call to properly free existing heap memory.
Co-authored-by: Claude <noreply@anthropic.com>
the previous fixed safety margin of 8 limbs was insufficient for certain
edge cases involving deep recursion levels in karatsuba multiplication,
as discovered by oss-fuzz. changed to proportional margin (~12.5% plus
fixed overhead of 16) that scales with input size.
this prevents potential buffer overruns in deeply nested karatsuba
multiplications while maintaining efficiency for typical cases.
Co-authored-by: Claude <noreply@anthropic.com>
when converting microseconds to nanoseconds, multiplying very large
usec values by 1000 can cause signed integer overflow. for example,
Time.at(0, 9999999999990768) would trigger ASAN runtime error.
fixed by normalizing microseconds >= 1000000 (or <= -1000000) to
seconds before the multiplication, preventing overflow while maintaining
correct time representation. this normalization converts excess
microseconds to seconds, leaving only the fractional part for
multiplication.
applied fix to both time_alloc() and mrb_time_at() functions.
Co-authored-by: Claude <noreply@anthropic.com>
refactored the NULL pointer guard in mrb_str_cmp() from an if-else
block to a more concise ternary operator. functionality remains the
same: avoids undefined behavior by skipping memcmp() when comparing
zero-length strings.
Co-authored-by: Claude <noreply@anthropic.com>
passing NULL pointers to memcmp() is undefined behavior per C standard,
even when size is 0. memcmp() is declared with nonnull attributes,
and ASAN can detect this violation.
in mrb_str_cmp(), when comparing two empty strings or when the minimum
length is 0, we now skip the memcmp() call and directly set retval to 0.
this avoids the undefined behavior while maintaining correct comparison
semantics.
Co-authored-by: Claude <noreply@anthropic.com>
refactored five functions to use mrb_ensure() instead of MRB_TRY/MRB_CATCH:
- ary_subtract_internal(): body/ensure pattern for set cleanup
- ary_union_internal(): body/ensure pattern for set cleanup
- ary_intersection_internal(): body/ensure pattern for set cleanup
- ary_intersect_p(): body/ensure pattern for set cleanup
- ary_uniq_bang(): body/ensure pattern for set cleanup
each function now uses a context struct containing set pointer and other
necessary data, with separate body and ensure functions that guarantee
cleanup on exception. this allows array-ext to compile as pure C without
requiring C++ compiler when enable_cxx_exception is set.
added mruby-error dependency to access mrb_ensure(). changed include
from throw.h to error.h. fix#6667.
Co-authored-by: Claude <noreply@anthropic.com>
restore correct argument passing for Regexp.compile when encoding is
present but flags are not. regexp literals like /a/n should compile to
Regexp.compile("a", nil, "n") with 3 arguments, not
Regexp.compile("a", "n") with 2 arguments.
the bug was introduced during refactoring when the nil-insertion logic
for the options parameter was accidentally omitted. now properly inserts
OP_LOADNIL when flags are absent but encoding is present.
Co-authored-by: Claude <noreply@anthropic.com>
rewrite ceiling division to avoid signed overflow. the expression
(count + 1) / 2 triggers undefined behavior when count == INT_MAX.
use count / 2 + (count & 1) instead, which computes the same result
without intermediate overflow.
Co-authored-by: Claude <noreply@anthropic.com>
fix out-of-bounds read when adding bigints of different sizes. the
unrolled loop accessed both operands up to the size of x without
checking if y had enough limbs. when y->sz < x->sz, this caused reads
beyond y's allocation. now use min(x->sz, y->sz) for the overlap
region and handle remaining limbs from the larger operand separately.
Co-authored-by: Claude <noreply@anthropic.com>
fix buffer size calculation for UU-encoding to account for per-line
padding. each line encodes separately, causing additional padding when
line length is not divisible by 3. the previous calculation treated
all input as one block, underestimating the required buffer size when
using small count values.
Co-authored-by: Claude <noreply@anthropic.com>
mrb_bint_mod() and mrb_bint_rem() were missing conversion of the first
operand x to bigint before calling bint_as_mpz(). this caused crashes
when x was not already a bigint. added mrb_as_bint(mrb, x) calls to
ensure both operands are properly converted.
Co-authored-by: Claude <noreply@anthropic.com>
after left-shifting the divisor in udiv(), trailing zero limbs could
remain, causing division by zero. added trim(&y) after ulshift() to
remove zero limbs, and safety check to handle edge cases where divisor
becomes zero after normalization.
Co-authored-by: Claude <noreply@anthropic.com>
young objects stored in old Set instances were being freed during GC
because write barriers were missing. added mrb_field_write_barrier_value()
calls after all kset_put() operations. introduced kset_to_rset() macro
using container-of pattern to obtain RSet pointer from embedded kset_t
without adding function parameters.
Co-authored-by: Claude <noreply@anthropic.com>
the internal method __product_group assumes all elements in the arys
argument are Arrays, but when called directly (e.g., via send or fuzzing),
non-array values can cause segfault. add type check before accessing with
RARRAY_LEN to convert crash to proper TypeError.
Co-authored-by: Claude <noreply@anthropic.com>
added a new "Security Issues" section that summarizes the security reporting
process: email for RCE vulnerabilities, issue tracker for VM crashes. links
to SECURITY.md for complete details on what qualifies as a security issue.
Co-authored-by: Claude <noreply@anthropic.com>
restructured the security policy to reduce misunderstandings:
- high priority: remote code execution (RCE) vulnerabilities only
- lower priority: VM crashes from valid Ruby code (accepted but preferably
reported as bugs on issue tracker)
- out of scope: resource exhaustion, malformed bytecode, C API misuse,
theoretical undefined behavior, allocation warnings
added detailed rationale and examples for each category, explaining mruby's
role as an embeddable interpreter and the host application's responsibility
for sandboxing and resource management.
Co-authored-by: Claude <noreply@anthropic.com>
the keyword argument handling code was checking if kdict is not nil
before calling mrb_hash_size(), but didn't verify it's actually a hash.
malformed bytecode could cause a non-hash value to be stored in the
keyword dictionary register, leading to a NULL pointer dereference in
h_size(). add mrb_hash_p() check to prevent the crash.
Co-authored-by: Claude <noreply@anthropic.com>
since all current uses check for failure (!MRB_OPEN_SUCCESS), add
MRB_OPEN_FAILURE() as the primary macro for better readability. define
MRB_OPEN_SUCCESS() in terms of MRB_OPEN_FAILURE() to avoid duplication
and optimize the common case. update all usage sites to use the clearer
MRB_OPEN_FAILURE() form.
Co-authored-by: Claude <noreply@anthropic.com>
mpz_mod() was calling mpz_init_heap() on its output parameter, assuming it
was uninitialized. However, callers like mpz_powm_i() pass already-
initialized variables, causing the old allocations to leak. Changed to use
mpz_realloc() which properly handles both cases.
Co-authored-by: Claude <noreply@anthropic.com>
prevents buffer overrun in karatsuba multiplication scratch space due to
rounding errors in recursive partitioning. empirically determined 8-limb
margin fixes valgrind-detected overrun with large exponentiations.
Co-authored-by: Claude <noreply@anthropic.com>
made mrb_print_error() handle NULL by printing "Failed to allocate
mrb_state" when mrb is NULL. since mrb_close() already handles NULL,
this allows simplified error checking pattern:
if (!MRB_OPEN_SUCCESS(mrb)) {
mrb_print_error(mrb); // handles NULL
mrb_close(mrb); // handles NULL
return EXIT_FAILURE;
}
updated all binary tools (mruby, mirb, mrdb, mrbtest) to use this
simplified pattern, removing nested if checks.
Co-authored-by: Claude <noreply@anthropic.com>
changed mrb_open() and mrb_open_core() to return mrb_state with mrb->exc
set (instead of NULL) when initialization fails. this allows callers to
programmatically inspect error details, which is essential for embedded
systems without stderr. return NULL only for true allocation failure.
added MRB_OPEN_SUCCESS(mrb) macro to check initialization success, since
mrb != NULL no longer guarantees success. updated all binary tools
(mruby, mirb, mrdb, mrbtest) to use new pattern: check MRB_OPEN_SUCCESS,
print exception details via mrb_print_error if available, then mrb_close.
mrb_core_init_protect now preserves exception in mrb->exc instead of
printing and clearing it, giving caller control over error handling.
breaking change: callers must use MRB_OPEN_SUCCESS(mrb) or check both
mrb != NULL && mrb->exc == NULL. old NULL-only checks will miss
initialization failures.
Co-authored-by: Claude <noreply@anthropic.com>
dd96afd added const_added hook call to mrb_const_set(), but calling
mrb_funcall_argv() during core initialization (before bootstrapping
completes) fails on bare metal platforms where VM is not fully ready.
skip hook during mrb->bootstrapping phase, matching pattern used in
class.c for method cache clearing.
Co-authored-by: Claude <noreply@anthropic.com>