Commit Graph

5339 Commits

Author SHA1 Message Date
Yukihiro "Matz" Matsumoto 2336534552 mruby-benchmark: add comprehensive test suite
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>
2025-12-02 23:12:37 +09:00
Yukihiro "Matz" Matsumoto 13e2ce4249 mruby-benchmark: fix implementation for mruby environment
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>
2025-12-02 23:12:36 +09:00
Yukihiro "Matz" Matsumoto 2f40f3d170 mruby-benchmark: add benchmarking gem
add initial implementation of mruby-benchmark gem providing:
- Benchmark.measure for detailed timing with Tms results
- Benchmark.realtime for simple wall-clock measurements
- Benchmark.bm for formatted comparison reports
- optional memory tracking via ObjectSpace integration

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 23:12:36 +09:00
Yukihiro "Matz" Matsumoto 29b3405283 bigint.c: handle in-place operation in mpz_mod_2exp()
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>
2025-12-01 18:20:44 +09:00
Yukihiro "Matz" Matsumoto a5e25393b8 mruby-bigint: fix memory leak in mpz_mod_2exp by clearing before reinit
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>
2025-12-01 18:20:44 +09:00
Yukihiro "Matz" Matsumoto 5ed0cd4ecb bigint.c: increase karatsuba scratch allocation safety margin
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>
2025-12-01 18:20:44 +09:00
Yukihiro "Matz" Matsumoto 857de45036 mruby-time: normalize microseconds before converting to nanoseconds
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>
2025-12-01 18:20:44 +09:00
Yukihiro "Matz" Matsumoto db3d754261 mruby-array-ext: use mrb_ensure() instead of direct throw.h calls
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>
2025-12-01 18:20:42 +09:00
John Bampton 8558ad40ec Adjust broken license links; clean up Markdown 2025-11-29 01:46:54 +10:00
Yukihiro "Matz" Matsumoto 82180d040b codegen.c: fix regexp literal with encoding to pass nil for options; fix #6666
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>
2025-11-20 14:08:21 +09:00
Yukihiro "Matz" Matsumoto 2da01c607f mruby-pack: avoid integer overflow in pack_hex buffer calculation
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>
2025-11-19 15:34:32 +09:00
Yukihiro "Matz" Matsumoto 3f2611ebcd bigint.c: fix buffer overflow in uadd with mismatched operand sizes
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>
2025-11-19 08:54:30 +09:00
Yukihiro "Matz" Matsumoto 2993302b8a mruby-pack: fix buffer overflow in pack_uu encoding
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>
2025-11-18 21:50:34 +09:00
Yukihiro "Matz" Matsumoto 281b38c0b6 bigint.c: add missing mrb_as_bint calls in mod and rem
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>
2025-11-18 10:14:13 +09:00
Yukihiro "Matz" Matsumoto 8113c0d24a bigint.c: fix division by zero in udiv normalization
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>
2025-11-18 09:33:24 +09:00
Yukihiro "Matz" Matsumoto a6b55e741e mruby-set: fix use-after-free by adding write barriers
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>
2025-11-17 20:08:57 +09:00
Yukihiro "Matz" Matsumoto 431d4bb51d mruby-array-ext: add type check in __product_group to prevent crash
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>
2025-11-17 08:50:40 +09:00
Yukihiro "Matz" Matsumoto 40b0cb98f7 mruby.h: add MRB_OPEN_FAILURE() macro and refactor MRB_OPEN_SUCCESS()
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>
2025-11-16 06:53:02 +09:00
Yukihiro "Matz" Matsumoto 74c0769319 mruby-bigint: fix memory leak in mpz_mod() when reusing initialized mpz_t
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>
2025-11-15 22:40:29 +09:00
Yukihiro "Matz" Matsumoto 9133124bef mruby-bigint: add safety margin to karatsuba scratch allocation
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>
2025-11-15 22:40:21 +09:00
Yukihiro "Matz" Matsumoto 8e50a45f3e mrb_print_error: handle NULL gracefully to simplify error checking
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>
2025-11-14 00:49:55 +09:00
Yukihiro "Matz" Matsumoto 05ffe0c441 mrb_open: return mrb_state with exc set on init failure
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>
2025-11-13 19:10:46 +09:00
Yukihiro "Matz" Matsumoto 153f915d5f mruby-set: fix memory leak in flatten when exceptions raised; fix #6664
set_do_flatten allocated temporary kset_t* via kset_init(). when
exceptions were raised during flattening (e.g., from hash function),
temporary kset was never freed. refactored to pass result set directly
and fill in-place. result set object is GC-protected, so exceptions
are handled cleanly without leaks.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-13 15:43:19 +09:00
Yukihiro "Matz" Matsumoto 9207af8ede mruby-set: use kh_is_end() for safe iteration; ref #6664
kh_is_end() safely checks if an iterator is at the end position,
preventing issues when the hash table is modified during iteration.
replaced direct kset_end() comparisons with kset_is_end() calls
throughout set operations.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-13 15:43:12 +09:00
Yukihiro "Matz" Matsumoto 729b84cf26 mruby-array-ext: fix use-after-free in array set operations; fix #6662
during eql? callbacks, array modifications can cause elements in khash to
be freed by GC, leading to use-after-free. create temporary shared copies
of arrays before populating khash to protect elements during callbacks.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-13 11:51:53 +09:00
Yukihiro "Matz" Matsumoto b56293c41d mruby-array-ext: fix memory leak in array set operations; ref #6662
add exception handling with MRB_TRY/MRB_CATCH to ensure khash cleanup
when eql? or hash methods raise exceptions. use kh_is_end macro for safe
khash iteration.

affected functions: Array#intersect?, Array#-, Array#|, Array#&, Array#uniq!

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 16:12:41 +09:00
Yukihiro "Matz" Matsumoto f4fb41b528 kernel.c: regression on struct/array/hash == override with super; fix #6660
when overriding struct#==, array#==, or hash#== with super, the recursion
detection incorrectly treated the super call as a circular reference. this
was caused by commit 5ca2d442 which added recursion detection.

the fix introduces mrb_recursive_func_p that starts from ci[-2] instead of
ci[-1], skipping the immediate parent frame which may be a ruby override
calling super. equality methods (==, eql?) now use this function, while
inspect methods keep using mrb_recursive_method_p for immediate circular
reference detection.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 10:25:37 +09:00
Yukihiro "Matz" Matsumoto 4795b7e3ca mruby-kernel-ext: add error helper function to eliminate goto
Add arg_error() helper function to replace goto statements used for
error handling. This function is marked with mrb_noreturn attribute
since it calls mrb_raise which never returns.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 10:25:37 +09:00
Yukihiro "Matz" Matsumoto e0393943f1 mruby-io: add error helper functions to eliminate goto
Add mode_error() and badfd_error() helper functions to replace
goto statements used for error handling. These functions are marked
with mrb_noreturn attribute since they call mrb_raise/mrb_sys_fail
which never return.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 10:25:36 +09:00
Yukihiro "Matz" Matsumoto ac103ac300 mruby-socket: add error helper function to eliminate goto
Add invalid_address_error() helper function to replace goto statements
used for error handling. This function is marked with mrb_noreturn
attribute since it calls mrb_raise() which never returns.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 10:25:36 +09:00
Yukihiro "Matz" Matsumoto d1e8085a1e mruby-binding: add error helper functions to eliminate goto
Add badname_error() and caller_error() helper functions to replace
goto statements used for error handling. These functions are marked
with mrb_noreturn attribute since they call mrb_raise() which never
returns.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 10:25:36 +09:00
Yukihiro "Matz" Matsumoto 150a8db053 mruby-array-ext: avoid goto in ary_slice_bang 2025-11-12 10:25:27 +09:00
Yukihiro "Matz" Matsumoto 704dfa01af mruby-array-ext: fix for some C++ compiler labels 2025-11-08 20:36:57 +09:00
Yukihiro "Matz" Matsumoto cc622f718c mruby-compiler: fix super with keyword arguments; fix #6659
allocate ** keyword dictionary register when methods have keyword
arguments (parse.y new_args_tail), broken in commit 26ea71260 during
cons-list to struct migration. reconstruct keyword hash after KEYEND
from extracted keyword local variables so super can access keyword
values. encode block parameter flag in ainfo bit 13 and generate
LOADNIL for block register in codegen_zsuper when parent has keywords
but no block parameter.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-08 17:37:56 +09:00
Yukihiro "Matz" Matsumoto d8496fc9be mruby-bin-debugger: combine variable declaration with initialization 2025-11-08 14:30:13 +09:00
Yukihiro "Matz" Matsumoto e66c4d53aa mruby-bin-mirb: combine variable declaration with initialization 2025-11-08 14:29:34 +09:00
Yukihiro "Matz" Matsumoto 30c0ef6968 mruby-bin-mrbc: combine variable declaration with initialization 2025-11-08 14:29:06 +09:00
Yukihiro "Matz" Matsumoto 0485ecdb01 mruby-array-ext: combine variable declaration with initialization 2025-11-08 14:28:22 +09:00
Yukihiro "Matz" Matsumoto 00905566ac mruby-dir: combine variable declaration with initialization 2025-11-08 14:27:44 +09:00
Yukihiro "Matz" Matsumoto 4f33c0cc11 mruby-error: combine variable declaration with initialization 2025-11-08 14:26:49 +09:00
Yukihiro "Matz" Matsumoto 688380bec2 mruby-kernel-ext: combine variable declaration with initialization 2025-11-08 14:25:22 +09:00
Yukihiro "Matz" Matsumoto 75a2a59637 mruby-proc-binding: combine variable declaration with initialization 2025-11-08 14:24:40 +09:00
Yukihiro "Matz" Matsumoto e58c838c1d mruby-sprintf: combine variable declaration with initialization 2025-11-08 14:24:12 +09:00
Yukihiro "Matz" Matsumoto 6bcd433214 mruby-string-ext: combine variable declaration with initialization 2025-11-08 14:23:41 +09:00
Yukihiro "Matz" Matsumoto 7e2f20573c mruby-task: combine variable declaration with initialization 2025-11-08 14:14:44 +09:00
dearblue 0e653eb4c2 Fixed use-after-free with Set#join
The `mrb_obj_as_string()` function can call the `#to_s` method.
String addresses and string lengths obtained outside the `KSET_FOREACH()` loop may become invalid.
2025-11-04 22:09:08 +09:00
Yukihiro "Matz" Matsumoto 2c47e84cab Merge pull request #6656 from dearblue/combination_init.2 2025-10-29 11:01:29 +09:00
Yukihiro "Matz" Matsumoto e682b20f1d mruby-compiler: restore exception handling for ||= on class variables; fix #6657
Restore exception handling for `||=` operator on class variables and constants
that was inadvertently removed in commit 0ca48e24f. When reading an undefined
class variable with GETCV opcode raises NameError, the exception handler
catches it and loads false, allowing the assignment to proceed.

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-28 09:46:51 +09:00
Yukihiro "Matz" Matsumoto ec58dca22f mruby-array-ext: use Data_Make_Struct() in ary_combination_init
refactor to use the standard Data_Make_Struct() macro instead of manual
RData allocation and linking. the macro provides automatic zero-initialization
and is more idiomatic.

ref #6655

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-27 11:46:22 +09:00
Yukihiro "Matz" Matsumoto 16efbd5c91 Merge pull request #6655 from dearblue/combination_init 2025-10-27 11:43:26 +09:00