Commit Graph

6279 Commits

Author SHA1 Message Date
HASUMI Hitoshi 0a21eef938 Fix mruby-task for PicoRuby Integration
With this PR, I can remove the original task.c in picoruby/picoruby and future development will be much easier.

## Add

### General

- C API functions exported with MRB_API for external integration:
  - mrb_execute_proc_synchronously() for synchronous proc execution
  - Task control APIs (mrb_create_task, mrb_suspend_task, mrb_resume_task, mrb_terminate_task, mrb_stop_task, mrb_task_value, mrb_task_status)
  - Task context management APIs for picoruby-sandbox (mrb_task_init_context, mrb_task_reset_context, mrb_task_proc_set)
  - Task.tick class method to get current tick count
- Comprehensive C API documentation with WASM integration examples

### For PicoRuby.wasm

- WASM/Emscripten support: Disable SIGALRM timer when __EMSCRIPTEN__ is defined, as JavaScript handles tick calls via setInterval
- Scheduler lock mechanism to prevent asynchronous task operations during synchronous execution (scheduler_lock counter in mrb_task_state)
- mrb_task_run_once() for single-step execution (event loop integration)

## Fix

### task.c
- Replace MRB_FIBER_TERMINATED with MRB_TASK_STOPPED just for clarity
- Allow suspending DORMANT and WAITING tasks in mrb_task_suspend (See comment in the source)
- Task context initialization by removing dummy callinfo push/pop

*NOTE*

With the dummy callinfo code that I deleted, IRB in PicoRuby ended SEGV.
If that code is mandatory, we need to discuss how to solve my problem.

### vm.c
- Handle MRB_TASK_CREATED status in VM's NORMAL_RETURN phase to properly stop tasks

----

These changes are necessary to make PicoRuby work.
Nevertheless, even with this patch, MicroRuby for Raspberry Pi Pico 2 is still unstable.
I would like to merge this PR anyway to make development easier by involving the PicoRuby community.
2026-01-11 17:07:04 +09:00
Yukihiro "Matz" Matsumoto 7fe5c2e260 gc.c: rename mrb_alloca() to mrb_temp_alloc() and fix memory leaks
rename mrb_alloca() to mrb_temp_alloc() for clearer naming - the new name
better describes its purpose as GC-managed temporary allocation. keep
mrb_alloca() as a macro alias for backward compatibility.

apply mrb_temp_alloc() to fix potential memory leaks in:
- mruby-strftime: if mrb_str_cat() raises, allocated buffers now cleaned by GC
- mruby-io File.readlink: if mrb_str_new() raises, buffer now cleaned by GC

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-08 08:23:51 +09:00
Yukihiro "Matz" Matsumoto ee06bbb417 vm.c: replace type assertions with runtime checks
Replace mrb_assert with mrb_ensure_*_type for VM opcodes that require
specific types:

- OP_ARYCAT: mrb_ensure_array_type
- OP_ARYPUSH: mrb_ensure_array_type
- OP_ASET: mrb_ensure_array_type (also fixed: was checking wrong register)
- OP_INTERN: mrb_ensure_string_type
- OP_HASHCAT: mrb_ensure_hash_type

These checks catch codegen bugs with clear error messages in both
debug and release builds.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-04 15:16:03 +09:00
Yukihiro "Matz" Matsumoto 6b482ee3f8 vm.c: add runtime type check for OP_STRCAT
Replace mrb_assert with mrb_ensure_string_type to catch codegen bugs
even in release builds. This prevents null-dereference crashes when
OP_STRCAT receives a non-string first operand due to compiler bugs.

Consistent with OP_HASH which uses mrb_ensure_hash_type for similar
type safety.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-04 14:09:57 +09:00
Yukihiro "Matz" Matsumoto 099d2c4771 array.c: fix heap-use-after-free in insertion_sort
The key variable in insertion_sort temporarily holds an array element
that's been removed from its slot during the sorting process. When
sort_cmp yields to a block that triggers GC, key wasn't protected
and could be collected.

Use arena save/restore around the loop to avoid arena overflow for
large arrays.

Test case from oss-fuzz: sort! with block containing rescue.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 20:41:47 +09:00
Yukihiro "Matz" Matsumoto 94e831cc70 init.c, mruby-io: undef DONE macro
Add #undef DONE after last usage to prevent macro redefinition
warnings in amalgamation builds.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-01 13:18:33 +09:00
Yukihiro "Matz" Matsumoto a263c43adb vm.c, codedump.c: undef CASE macro
Add #undef CASE at end of files to prevent macro redefinition
warnings in amalgamation builds.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-01 12:35:09 +09:00
Yukihiro "Matz" Matsumoto d1178ec8eb hash.c, symbol.c, string.c, mruby-string-ext: undef lesser macro
Add #undef lesser after last usage to prevent macro redefinition
warnings when files are amalgamated into a single translation unit.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-01 10:23:21 +09:00
Yukihiro "Matz" Matsumoto 8a29ab591e vm.c: use mrb_obj_ptr()->c for faster class check in GETIDX/SETIDX
Replace mrb_obj_class() with direct mrb_obj_ptr(va)->c access:

- Skips unnecessary mrb_immediate_p() check (these types are never immediate)
- Skips mrb_class_real() traversal for singleton classes
- Objects with singleton methods now fall back to method dispatch
  (correct behavior since they might have overridden []/[]=)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-25 18:01:44 +09:00
Yukihiro "Matz" Matsumoto 115438aa1e vm.c: optimize OP_SETIDX for Array and Hash; ref #6675
Add inline optimizations for Array#[]= and Hash#[]= in OP_SETIDX,
matching the pattern established for OP_GETIDX:

- Array class: use mrb_ary_set() directly (integer index only)
- Hash class: use mrb_hash_set() directly
- Subclasses: fall back to method dispatch (can override []=)
- String: unchanged (complex 2-3 argument signature)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-25 18:01:44 +09:00
Yukihiro "Matz" Matsumoto 5102ef8022 vm.c: allow String subclasses to override []; ref #6675
Apply the same pattern as the Array/Hash fix: the OP_GETIDX optimization
now only applies to instances of the String class itself. Subclasses
fall back to method dispatch, allowing them to override the [] method.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-25 18:01:44 +09:00
Yukihiro "Matz" Matsumoto d65fb765ef vm.c: allow Array subclasses to override []; ref #6675
Apply the same pattern as the Hash fix: the OP_GETIDX optimization
now only applies to instances of the Array class itself. Subclasses
fall back to method dispatch, allowing them to override the [] method.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-25 18:01:43 +09:00
Yukihiro "Matz" Matsumoto 35af869d7d vm.c: allow Hash subclasses to override []; close #6675
The OP_GETIDX optimization now only applies to instances of the Hash
class itself. Subclasses fall back to method dispatch, allowing them
to override the [] method. This fixes compatibility with libraries
like mruby-hashie that rely on aliasing/overriding [] in subclasses.

Trade-off: Hash#[] cannot be overridden on the Hash class itself
(only on subclasses). This is a reasonable semantic for mruby since
subclassing is the proper pattern for customization.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-25 18:01:43 +09:00
Yukihiro "Matz" Matsumoto 768a1f7752 string.c: add mrb_strcasecmp_p for case-insensitive comparison
Move casecmp_p from mruby-string-ext and mruby-encoding to core as
mrb_strcasecmp_p (predicate function returning mrb_bool). Add
MRB_STR_CASECMP_P macro to internal.h for comparing mrb_value strings
with literal strings.

This eliminates code duplication and avoids static function name
collision for future amalgamation support.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-23 10:41:21 +09:00
Yukihiro "Matz" Matsumoto d5c93fc724 class.c, variable.c: rename bsearch_idx to avoid name collision
Rename static bsearch_idx functions to disambiguate:
- class.c: mt_bsearch_idx (method table)
- variable.c: iv_bsearch_idx (instance variable table)

This prepares for future amalgamation support.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-23 08:32:23 +09:00
Yukihiro "Matz" Matsumoto 7e28e68dca string.c: add mrb_utf8_to_buf() to consolidate UTF-8 encoding
Extract duplicated UTF-8 codepoint-to-bytes encoding into a shared
function in src/string.c. Update all gems to use it:

- mruby-sprintf: %c specifier
- mruby-io: putc
- mruby-string-ext: Integer#chr
- mruby-pack: pack("U")
- mruby-compiler: Unicode escapes in parser

Also use existing mrb_utf8len() in io.c for character length detection.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-18 16:30:03 +09:00
Yukihiro "Matz" Matsumoto e76ce24860 mruby-compiler: add one-line pattern matching
add support for one-line pattern matching syntax:
- 'expr in pattern' returns true/false
- 'expr => pattern' raises NoMatchingPatternError on mismatch

add NODE_MATCH_PAT node type for both forms, distinguished by
raise_on_fail flag. grammar rules placed at expr level to avoid
conflict with rescue clause's exception variable syntax.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-18 16:27:26 +09:00
Yukihiro "Matz" Matsumoto 2494a712dd vm.c: extract alias resolution logic to MRB_PROC_RESOLVE_ALIAS macro
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>
2025-12-02 23:12:36 +09:00
Yukihiro "Matz" Matsumoto ffd3252dd0 proc.c: fix Method#== for aliased methods and comparison bug; fix #6668
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>
2025-12-01 18:20:45 +09:00
Yukihiro "Matz" Matsumoto 78f9b5c52f string.c: simplify memcmp guard with ternary operator
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>
2025-12-01 18:20:43 +09:00
Yukihiro "Matz" Matsumoto 6122fdfee9 string.c: guard memcmp() call to avoid undefined behavior with NULL pointers
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>
2025-12-01 18:20:43 +09:00
dearblue 50ecc1fd2c Arranging VM dispatch macros
Consolidate duplicate common code.
2025-11-23 14:45:22 +09:00
Yukihiro "Matz" Matsumoto 1c7a0d4e96 vm.c: add type check before calling mrb_hash_size() on keyword dict
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>
2025-11-16 19:38:33 +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 92640097ab variable.c: skip const_added hook during bootstrapping; fix #6613
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>
2025-11-13 16:46:50 +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 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 a9ed9190d3 class.c: combine variable declaration with initialization 2025-11-08 14:09:16 +09:00
Yukihiro "Matz" Matsumoto b99233bc45 etc.c: combine variable declaration with initialization 2025-11-08 14:08:23 +09:00
Yukihiro "Matz" Matsumoto b592d02d63 gc.c: combine variable declaration with initialization 2025-11-08 14:07:41 +09:00
Yukihiro "Matz" Matsumoto 33ec660cff kernel.c: combine variable declaration with initialization 2025-11-08 14:07:00 +09:00
Yukihiro "Matz" Matsumoto 9f91d5d1a2 load.c: combine variable declaration with initialization 2025-11-08 14:06:11 +09:00
Yukihiro "Matz" Matsumoto 717ac087ff object.c: combine variable declaration with initialization 2025-11-08 14:05:27 +09:00
Yukihiro "Matz" Matsumoto ed82cea4ca proc.c: combine variable declaration with initialization 2025-11-08 14:04:39 +09:00
Yukihiro "Matz" Matsumoto fa8c460c61 range.c: combine variable declaration with initialization 2025-11-08 14:04:11 +09:00
Yukihiro "Matz" Matsumoto 098812d10c string.c: combine variable declaration with initialization 2025-11-08 13:58:43 +09:00
Yukihiro "Matz" Matsumoto 1d3393caf5 variable.c: combine variable declaration with initialization 2025-11-08 13:57:32 +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 eb398971bf array.c: fix use-after-realloc in Array#sort!; fix #6649
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>
2025-10-27 15:06:14 +09:00
dearblue c28223ac5b Fix integer overflow in allocation size calculation
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.
2025-10-26 21:02:20 +09:00
Yukihiro "Matz" Matsumoto 00e7474cce array.c: combine variable declaration with initialization 2025-10-25 23:27:08 +09:00
Yukihiro "Matz" Matsumoto 7eb6ca686c class.c: combine variable declaration with initialization 2025-10-25 23:14:52 +09:00
Yukihiro "Matz" Matsumoto f432f1772d dump.c: combine variable declaration with initialization 2025-10-25 23:10:24 +09:00
Yukihiro "Matz" Matsumoto 35f2e97d40 kernel.c: combine variable declaration with initialization 2025-10-25 22:37:31 +09:00
Yukihiro "Matz" Matsumoto d33aaecf39 numeric.c: combine variable declaration with initialization 2025-10-25 21:58:39 +09:00
Yukihiro "Matz" Matsumoto b171abade2 range.c: combine variable declaration with initialization 2025-10-25 19:48:14 +09:00
Yukihiro "Matz" Matsumoto 905bb7366b string.c: combine variable declaration with initialization 2025-10-25 15:50:41 +09:00
Yukihiro "Matz" Matsumoto 516d2bcc52 symbol.c: combine variable declaration with initialization 2025-10-25 15:39:32 +09:00
Yukihiro "Matz" Matsumoto 0211004cf2 variable.c: combine variable declaration with initialization 2025-10-25 09:36:48 +09:00