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>
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>
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>
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>
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>
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>
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>
add length check to detect array modification during sort. when realloc()
shrinks an array in-place, it may return the same pointer, defeating the
pointer-only check. the new check catches both pointer changes and length
changes, preventing out-of-bounds access.
the fix captures array pointer and length at the start of each comparison,
then validates both after user code executes. this detects modifications
even when realloc() returns the original pointer.
Co-authored-by: Claude <noreply@anthropic.com>
Passing a large integer value as the first argument to `Array#ary_combination_init` could cause an incorrect memory allocation due to integer overflow.
This would result in an invalid write during the subsequent zero-fill of the memory.
To resolve the issue, it has been replaced with `mrb_calloc()`.
However, since the current `mrb_calloc()` returns `NULL` due to overflow, it has been modified to raise an exception as a clear error.
this reverts commit 04af58db89 which caused use-after-free vulnerability.
cached array pointers become invalid when mrb_cmp() executes user's <=>
method that can modify arrays during iteration
Co-authored-by: Claude <noreply@anthropic.com>
Optimizes Array#<=> by hoisting RARRAY_PTR calls outside the loop to
avoid repeated conditional checks. This is a frequently used operation
for array comparisons and sorting.
Before: 2 RARRAY_PTR calls per iteration (checks embed vs heap twice)
After: 2 RARRAY_PTR calls total (pointers cached outside loop)
Co-authored-by: Claude <noreply@anthropic.com>
added forward declaration in gc.c and stub implementation in mrbc stub.c
for mrb_task_mark_all to avoid link errors when mrbc is built without
mruby-task gem.
Co-authored-by: Claude <noreply@anthropic.com>
add pragma to suppress -Wdangling-pointer warning for intentional
stack variable address storage in exception handling. the pointer
is safely managed and cleared before function returns.
Co-authored-by: Claude <noreply@anthropic.com>
Implements dual-mechanism GC protection and optimizes task lookup
using pointer arithmetic based on PicoRuby reference implementation.
GC Protection:
- Add mrb_gc_register/unregister to protect Task objects
- Implement mrb_task_mark_all() to mark task contexts during GC
- Store proc reference in mrb_task to prevent premature collection
- Integrate marking into gc.c root_scan_phase
Performance Optimizations:
- Add MRB2TASK macro for O(1) context-to-task conversion
- Optimize Task.current: O(n) queue search -> O(1) pointer arithmetic
- Optimize Task.pass: simplify to root context check
- Optimize Task.join: use MRB2TASK for current task lookup
Bug Fixes:
- Fix MRB_TASK_CREATED/STOPPED to use MRB_FIBER_TERMINATED
- Add safety check to prevent execution of terminated tasks
- Initialize callinfo PC to bytecode start in task_init_context
Co-authored-by: Claude <noreply@anthropic.com>
this patch fixes several critical issues in the task scheduler:
1. vm integration for computed goto dispatch mode:
- added task switching check in NEXT macro for computed goto
- previous implementation only worked with switch dispatch mode
- now Task.pass properly yields control to other tasks
2. task lifecycle tracking:
- added 'started' flag to mrb_task structure
- fixed first-run detection to avoid popping callinfo multiple times
- vm overwrites context status during execution, making it unreliable
3. removed mrblib/task.rb:
- empty Ruby method stubs were overriding C implementations
- all task methods now properly implemented in C
4. cleaned up task scheduler loop:
- proper task completion detection using switching flag
- round-robin scheduling for tasks at same priority
- clean scheduler exit when all tasks complete
tasks now cooperatively yield with Task.pass and complete cleanly.
Co-authored-by: Claude <noreply@anthropic.com>
modify END_DISPATCH macro to check for context switches after each
bytecode instruction. when switching flag is set or task has stopped,
return from mrb_vm_exec to yield control back to scheduler.
add TASK_STOP macro to mark task completion in OP_STOP instruction.
this allows scheduler to detect when tasks finish execution.
the integration enables cooperative preemption at bytecode granularity
while maintaining compatibility with non-task builds.
Co-authored-by: Claude <noreply@anthropic.com>
Cast RARRAY_LEN result to int in send_method when handling visibility
errors to resolve C4244 warning about potential data loss from
mrb_ssize to int conversion. The cast is safe since n represents
argument count which should fit in int range.
Co-authored-by: Claude <noreply@anthropic.com>
SYMTBL_LITERAL_FLAG was defined as 1UL, which can be smaller
than uintptr_t on some platforms (e.g., Windows 64-bit). This
caused symtbl_get_ptr() to return a corrupted pointer.
Changed the flag to be explicitly cast to uintptr_t to ensure
correct behavior on all platforms.
Co-authored-by: Gemini <gemini@google.com>
This commit simplifies the logic for checking if a symbol is a literal in the
`sym_intern_common` function by using the `lit = lit || mrb_ro_data_p(name);`
idiom.
Co-authored-by: Gemini <gemini@google.com>
This commit refactors the `sym_intern_linear_mode` and
`sym_intern_hash_mode` functions to remove duplicate code. A new
function `sym_intern_common` is created to contain the common code.
Co-authored-by: Gemini <gemini@google.com>
Replace separate symflags array with LSB pointer tagging to store
symbol literal flags directly in string pointers. This eliminates
the need for a separate symflags allocation, saving 1/8 of symbol
table memory overhead (282 bytes measured improvement).
Key changes:
- Add LSB tagging helper functions (symtbl_get_ptr, symtbl_is_literal,
symtbl_tag_literal)
- Store literal flag in LSB of mrb->symtbl[i] pointers (LSB=1 for
literals)
- Remove symflags field from mrb_sym_hash_table struct
- Update all symbol access functions to use proper pointer untagging
- Maintain mrb_ro_data_p() detection for platform compatibility
- Fix potential crashes by ensuring untagged pointers in memory
operations
Works in both linear and hash table modes. All 1717 tests pass.
Memory usage reduced by 282 bytes compared to original implementation.
Co-authored-by: Claude <noreply@anthropic.com>