io_puts_ary recursed unconditionally on nested arrays. For cyclic
arrays (a = []; a << a; puts a) or pathologically deep arrays,
this caused a C stack overflow.
Add a depth cap (IO_PUTS_MAX_DEPTH = 16); on overflow, write
"[...]\n" and return, matching CRuby's behavior on cycles. The
pattern mirrors mruby-set's MAX_NESTED_DEPTH for the same problem
shape (pure C recursion not dispatched as a Ruby method).
Reported by OSS-Fuzz (clusterfuzz testcase 6233530857488384).
Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit 7dfd560df8)
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 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.
Change the grammar rule for tLPAREN_ARG from accepting only a
single stmt to accepting compstmt. This allows compound
statements with semicolons inside parenthesized arguments when
the parenthesis is preceded by a space, e.g., `p (f1; f2)`.
This matches the behavior of CRuby 3.3+.
Fixes#6766.
Co-authored-by: Claude <noreply@anthropic.com>
When the block passed to Lazy#flat_map returns a non-enumerable value
(e.g. an Integer), mruby raised NoMethodError because it unconditionally
called #each on the result. CRuby yields non-enumerable values directly.
Use respond_to?(:each) to match CRuby behavior: iterate enumerable
results, yield non-enumerable results as-is.
With `rake -m`, the C compiler can start reading a partially-written
gem_test.c before generation completes. Write to a .tmp file first,
then rename to the final path.
Co-authored-by: Claude <noreply@anthropic.com>
Several methods defined in mruby-array-ext are written in C and may call `mrb_vm_exec()`.
If array objects are modified on the Ruby side, problems may arise in subsequent processing.
- Using objects that have been removed from the array and garbage collected
- Using pointers or array lengths that have become invalid due to changes to the array object
- Modifying the contents of a shared array object directly
ref: https://github.com/mruby/mruby/issues/6662
Replace `__product_group` method with `__product_generate` and `__product_next`.
This change eliminates the need for Ruby to perform internal state calculations, allowing it to simply receive the results.
case/in without else clause now raises NoMatchingPatternError
when no pattern matches, matching CRuby behavior. Fixes#6741.
Co-authored-by: Claude <noreply@anthropic.com>
Apply the same chunking strategy used for regular array literals
to %w() and %i() literal arrays in gen_literal_array(). Fixes#6740.
Co-authored-by: Claude <noreply@anthropic.com>
Array literals were being built by loading all elements into registers
before constructing the array, requiring nregs proportional to the array
size (e.g. nregs=99 for 100 elements). This exceeds mruby/c's register
limit. Restore 3.4-era chunking at GEN_LIT_ARY_MAX (64) elements.
fixesmruby/mruby#6731
Co-authored-by: Claude <noreply@anthropic.com>
Since presym is now mandatory, mruby.h includes presym.h so that
MRB_SYM() macros are available everywhere without explicit include.
Remove redundant #include <mruby/presym.h> from all source files.
Co-authored-by: Claude <noreply@anthropic.com>
The old name referred to "truncation" of float precision, which no
longer happens with rotation encoding. The new name describes the
actual behavior: disabling inline float encoding in word boxing.
The old name is kept as an obsolete alias for backward compatibility.
Co-authored-by: Claude <noreply@anthropic.com>
remove snprintf() call that requires <stdio.h>, which is unavailable
with MRB_NO_STDIO; use a static error message consistent with other
codegen_error() calls.
Fixes#6724.
Co-authored-by: Claude <noreply@anthropic.com>
Consolidate the duplicated print_no increment-and-wrap logic
from dbgcmd_print() and dbgcmd_info_local() into a single
next_print_no() function.
Co-authored-by: Claude <noreply@anthropic.com>
Flatten 4-level nested parsing of list command arguments into
a separate parse_file_line_spec() function.
Co-authored-by: Claude <noreply@anthropic.com>
Combine method and line breakpoint checks into a single
check_breakpoint_hit() helper, simplifying the DBG_RUN case.
Co-authored-by: Claude <noreply@anthropic.com>
Extract find_command_by_word1() and find_command_by_words()
from parse_command(), separating command-table lookup from
tokenization logic.
Co-authored-by: Claude <noreply@anthropic.com>
Both dbgcmd_run() and dbgcmd_quit() defined an exception class
and raised it with identical code. Add a shared static inline
helper in mrdb.h.
Co-authored-by: Claude <noreply@anthropic.com>
The three commands shared identical dispatch logic. Extract a
shared dbgcmd_set_breakpoint() that takes function pointers,
reducing each command to a one-line wrapper.
Co-authored-by: Claude <noreply@anthropic.com>
Extract common breakpoint slot allocation logic from
mrb_debug_set_break_line() and mrb_debug_set_break_method()
into a shared alloc_breakpoint() helper.
Co-authored-by: Claude <noreply@anthropic.com>
Remove redundant local ISSPACE/ISALNUM definitions from
mirb_completion.c and unused ctype.h includes from both
mirb_completion.c and mirb.c. The locale-independent macros
from mruby.h are already available via <mruby.h>.
Co-authored-by: Claude <noreply@anthropic.com>
Replace the strncmp() if-else chain for block-opening and closing
keywords with a data-driven indent_table, matching the existing
dedent_table pattern. Also use mirb_is_word_char() for the word
boundary check.
Co-authored-by: Claude <noreply@anthropic.com>
Replace duplicate line-joining logic in mirb_buffer_delete_back()
and mirb_buffer_delete_forward() with a shared helper that appends
a line's content to the previous line, then removes it.
Co-authored-by: Claude <noreply@anthropic.com>
Replace three identical 7-line blocks that grow the lines array
with a single buffer_ensure_line_cap() helper function, matching
the existing line_ensure_cap() naming pattern.
Co-authored-by: Claude <noreply@anthropic.com>
Replace three separate global contexts (g_readline_ctx,
g_linenoise_ctx, g_editor_ctx) with a single g_ctx and shared
init_completion_ctx() helper. Consolidate the three identical
cleanup functions into mirb_cleanup_completion().
Co-authored-by: Claude <noreply@anthropic.com>
Replace the if-else chain with a data table that encodes each
dedent keyword, its valid delimiters, and whether it can appear
at end of line.
Co-authored-by: Claude <noreply@anthropic.com>
Move is_word_char() to mirb_buffer.h as mirb_is_word_char() static
inline, removing duplicate definitions from mirb_buffer.c and
mirb_highlight.c. Move COLOR_RESET to mirb_highlight.h, removing
the duplicate from mirb_editor.c.
Co-authored-by: Claude <noreply@anthropic.com>
Replace the cleanup() function and duplicated end-of-main cleanup
with a single goto cleanup label. This also fixes a minor resource
leak where cxt was not freed when library loading failed.
Co-authored-by: Claude <noreply@anthropic.com>
Move the Ruby keyword array from static definitions in both
mirb_highlight.c and mirb_completion.c to a single shared
mirb_keywords[] defined in mirb_highlight.c and declared in
mirb_highlight.h.
Co-authored-by: Claude <noreply@anthropic.com>
Extract three helpers (calc_expected_indent, adjust_line_indent,
insert_indent_spaces) to eliminate repeated indent computation and
whitespace adjustment code in perform_dedent, reindent_line,
handle_tab_indent, and the Enter key handler.
Co-authored-by: Claude <noreply@anthropic.com>
rand_range_float() incorrectly added +1.0 to span for inclusive
ranges, logic copied from integer range handling. For float ranges,
the span should simply be end-begin without adjustment.
Fixes#6720.
Co-authored-by: Claude <noreply@anthropic.com>
ROM method tables used static mrb_mt_tbl variables shared
across the process. The next pointer in each wrapper was
mutated by mrb_mt_init_rom(), causing cross-state
contamination when multiple mrb_state instances existed.
Allocate mrb_mt_tbl wrappers per-state via mrb_malloc().
The const mrb_mt_entry[] arrays remain static and shared.
Wrappers are tracked in mrb->rom_mt and freed at mrb_close().
Remove MRB_MT_ROM_TAB macro; add MRB_MT_INIT_ROM macro that
auto-computes size and calls the new mrb_mt_init_rom().
Co-authored-by: Claude <noreply@anthropic.com>
Replace check_method_noarg() with check_argument_count() that validates
min <= argc <= max using the full aspec stored in mrb_method_t.flags.
This catches ArgumentError earlier at dispatch time, before entering
the C function.
The old check only handled the special case of aspec==0 (NOARG).
The new check extracts REQ, OPT, REST, POST, KEY, and KDICT from
the aspec and validates accordingly. Keyword hash is counted as
a positional arg only when the method doesn't accept keywords.
Remove MRB_METHOD_NOARG_P macro from proc.h (subsumed by aspec check).
Fix 15 incorrect aspec declarations across the codebase that were
exposed by the stricter enforcement.
Co-authored-by: Claude <noreply@anthropic.com>
Move MRB_METHOD_FUNC_FL to bit 24 and visibility flags to
bits 25-26 so that MRB_ARGS_*() values (bits 0-23) can be
stored directly without shifting. This makes MRB_MT_PRIVATE
and MRB_METHOD_PRIVATE_FL the same value, eliminating the
dual-constant confusion and simplifying the MRB_MT_ENTRY()
macro to a single OR operation.
Co-authored-by: Claude <noreply@anthropic.com>
Restore MRB_ARGS_* argument specs and ISO section comments to all
709 ROM method table entries. The aspec is encoded in bits 4-27 of
the flags field; MRB_MT_NOARG is now auto-derived from aspec==0.
Add MRB_MT_ENTRY_PRIVATE() macro for private methods (53 entries)
and MRB_MT_ASPEC() accessor for extracting aspec from flags.
Co-authored-by: Claude <noreply@anthropic.com>
Move conditional mrb_define_method_id() calls into ROM entry
arrays using #ifdef guards. With linear search, sizeof in
MRB_MT_ROM_TAB() adjusts automatically after preprocessing.
Cross-class ROM tables (methods a gem defines on a class it does
not own) are reverted to mrb_define_method_id(). Multiple gems
should not add ROM table layers to the same class; each layer
costs a 16-byte mrb_mt_tbl struct in RAM and deepens the lookup
chain. Use mrb_define_method_id() for cross-class methods.
Co-authored-by: Claude <noreply@anthropic.com>
Since ROM table entries are always C functions, have the
MRB_MT_ENTRY() macro set MRB_MT_FUNC automatically. This
simplifies entry definitions across all 32 source files.
Co-authored-by: Claude <noreply@anthropic.com>
Replace binary search with linear scan in mt_get(), mt_put(),
mt_del(), mt_chain_has(), and mrb_mt_foreach(). The method cache
makes repeated lookups O(1), so linear scan on cache misses is
acceptable.
This removes the sorting requirement, allowing ROM entry arrays
to be declared const. On embedded systems, const static data
resides in flash/ROM instead of RAM, saving ~8.4KB for ~700
method entries on 32-bit MCUs.
Co-authored-by: Claude <noreply@anthropic.com>