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>
The local flock() function for Windows is now dead code since the
HAL refactoring. The Windows implementation is in hal-win-io which
provides mrb_hal_io_flock().
Fixes warning: 'flock' defined but not used [-Wunused-function]
Co-authored-by: Claude <noreply@anthropic.com>
Remove unused mrb_stat typedef from file.c that conflicted with the
mrb_stat() function in file_test.c when compiled as a single
translation unit.
Fix convert_stat() in hal-posix-io to handle st_atime macro correctly
in both normal and amalgamated builds by extracting time values before
undefining the macros.
Co-authored-by: Claude <noreply@anthropic.com>
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>
IO#putc writes a single character without intermediate string allocation.
- Integer argument: writes byte value (mod 256)
- String argument: writes first character (UTF-8 aware when MRB_UTF8_STRING)
- Returns the argument (IO#putc) or nil (Kernel#putc, matching CRuby)
This provides ~44% memory reduction for character-by-character output
compared to printf "%c" or print ch.chr approaches.
Co-authored-by: Claude <noreply@anthropic.com>
added parentheses to to_enum call where the return value is used,
explicitly specifying :each for readability.
Co-authored-by: Claude <noreply@anthropic.com>
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>
remove redundant visualcpp and mingw checks since for_windows? already
detects all windows builds including visual c++ and mingw.
ref #6653
Co-authored-by: Claude <noreply@anthropic.com>
io_unget_data had two issues that caused crashes with repeated ungetc:
1. Integer underflow in buffer size check: "len > MRB_IO_BUF_SIZE - buf->len"
could underflow when buf->len was large, bypassing reallocation
2. Short overflow: buf->len could exceed SHRT_MAX after multiple ungetc
calls, causing integer overflow when cast to short
Fixed by checking buf->len + len against both MRB_IO_BUF_SIZE and
SHRT_MAX before buffer operations.
Co-authored-by: Claude <noreply@anthropic.com>
io_gets was passing negative limit values to io_buf_cat without
validation, causing negative-size-param in memcpy detected by ASAN.
Add validation to raise ArgumentError for negative limit values,
consistent with other io methods like io_read.
Co-authored-by: Claude <noreply@anthropic.com>
Optimizes IO.select by hoisting RARRAY_PTR calls outside loops to avoid
repeated conditional checks in both setup and result processing phases.
Optimized loops:
- Setup phase: 3 loops for read/write/except arrays
- Result phase: 3 loops for read/write/except arrays
Each loop previously called RARRAY_PTR 1-2 times per iteration. With
hoisting, each array pointer is retrieved once per loop instead of once
per iteration, significantly reducing overhead in I/O multiplexing.
Co-authored-by: Claude <noreply@anthropic.com>
Fixes MSVC warnings on 32-bit builds when converting st_size (int64_t) to
mrb_int. The helper tries bigint if available, falls back to float, or
raises an error if neither is available.
Co-authored-by: Claude <noreply@anthropic.com>
add Windows guard to FileTest.pipe? to raise NotImplementedError,
consistent with symlink? and socket?. Windows anonymous pipes created
by IO.pipe are not UNIX FIFOs and cannot be detected via stat mode
bits. the test suite expects this exception and handles it with skip.
Co-authored-by: Claude <noreply@anthropic.com>
use chomp to strip line endings from backtick command output, making the
test platform-agnostic. remove unused $crlf variable since line ending
checks are now handled by chomp.
Co-authored-by: Claude <noreply@anthropic.com>
make symlink operations raise notimplementederror on Windows since
symlinks require special privileges and differ significantly from posix.
similarly, filetest.socket? and filetest.symlink? now raise
notimplementederror on Windows since these file types don't exist in
the same way. the file.chmod test now restores write permissions before
deletion, which is required on Windows to delete read-only files.
all tests already have rescue notimplementederror clauses that skip
gracefully on unsupported platforms.
Co-authored-by: Claude <noreply@anthropic.com>
mingw provides posix file i/o apis but not unix process management
functions (fork, waitpid) which are required by hal-posix-io. removed
mingw from linux/bsd pattern to let for_windows? predicate select
hal-win-io instead.
Co-authored-by: Claude <noreply@anthropic.com>
when building with MSVC on Windows, RUBY_PLATFORM (from the Ruby
installation running rake) may indicate "mingw" if Ruby was installed
via RubyInstaller, causing incorrect selection of POSIX HALs instead
of Windows HALs.
fixed by checking spec.build.primary_toolchain first:
- if toolchain is "visualcpp", select Windows HALs
- otherwise fall through to existing platform checks
this ensures MSVC builds use hal-win-* gems even when Ruby itself
was installed with MinGW.
affected gems:
- mruby-dir
- mruby-io
- mruby-socket
- mruby-task
Co-authored-by: Claude <noreply@anthropic.com>
add mingw pattern to RUBY_PLATFORM check. native mingw builds were
falling through to windows hal because previous detection only worked
for cross-compilation. now checks RUBY_PLATFORM for mingw along with
linux/darwin/bsd.
Co-authored-by: Claude <noreply@anthropic.com>
only define mrb_lstat when symbolic link macros are available. on
windows/mingw, symlinks are not supported and the function is unused,
causing -Wunused-function warning.
Co-authored-by: Claude <noreply@anthropic.com>
remove const qualifier from variables passed to free functions.
msvc is stricter about const correctness than gcc. variables from
mrb_utf8_from_locale and mrb_locale_from_utf8 are dynamically allocated
and need to be freed, so they should not be const.
Co-authored-by: Claude <noreply@anthropic.com>
mingw provides posix-compatible functions (readlink, symlink, opendir, etc.)
so it should use hal-posix-io/dir instead of hal-win-io/dir. detect mingw by
checking if host_target or compiler command contains "mingw". check posix
platforms first so mingw is caught before for_windows check.
this fixes test failures on mingw where readlink returned absolute paths
instead of relative paths, and symlink/socket tests failed due to api
differences between windows native apis and posix apis.
Co-authored-by: Claude <noreply@anthropic.com>
rename all HAL functions from mrb_<feature>_hal_<name>() to
mrb_hal_<feature>_<name>() for better grouping and clarity. this makes all
HAL functions immediately identifiable with the mrb_hal_* prefix.
affected gems:
- mruby-task: mrb_task_hal_* -> mrb_hal_task_*
- mruby-io: mrb_io_hal_* -> mrb_hal_io_*
- mruby-socket: mrb_socket_hal_* -> mrb_hal_socket_*
- mruby-dir: mrb_dir_hal_* -> mrb_hal_dir_*
Co-authored-by: Claude <noreply@anthropic.com>
changed from angle brackets to quotes for gem-local HAL headers
(task.h, io_hal.h, socket_hal.h), and removed relative path prefix
from task.h include. this follows the mrbgem build system convention
where gem/include/ is automatically added to the include path.
Co-authored-by: Claude <noreply@anthropic.com>
eliminates platform-specific popen implementations by using
mrb_io_hal_pipe and mrb_io_hal_spawn_process. removes io_cloexec_pipe,
io_pipe, and io_process_exec functions. io.pipe now also uses
mrb_io_hal_pipe. reduces platform conditionals and improves portability.
Co-authored-by: Claude <noreply@anthropic.com>
separates platform-specific code into hal-posix-io and hal-win-io gems,
making mruby-io platform-independent. HAL interface defined in
mrbgems/mruby-io/include/io_hal.h covers file operations, I/O operations,
and process operations. follows mruby-task dependency pattern where HAL
gems depend on feature gem. ws2_32 library linked in hal-win-io gem.
Co-authored-by: Claude <noreply@anthropic.com>
This patch fixs a critical segmentation fault in `io_gets` function caused by an uninitialized limit variable.
This bug may specifically heppen when:
- MicroRuby with task scheduler, which I'm implementing, enabled
## Root Cause Analysis
When `io_gets` is called without arguments (argc=0), the local variable `limit` remains uninitialized on the stack.
I guess that this uninitialized memory often contains leftover heap addresses from previous stack frames.
### The problematic flow:
1. `mrb_get_args(mrb, "|o?i?", &rs, &rs_given, &limit, &limit_given)` with 0 arguments
2. `limit_given = FALSE` but limit contains garbage heap address
3. Looks like later processing truncates this address, creating invalid pointer 0xffff0000
4. This value gets pushed onto VM stack during string operations
5. Garbage collector attempts to mark 0xffff0000 as valid object pointer
6. SIGSEGV in mrb_gc_mark() at gc.c:748
```
Program received signal SIGSEGV, Segmentation fault.
0x00005c8bebffa95c in mrb_gc_mark (mrb=0x5c8bec2836c8 <heap_pool+728>, obj=0xffff0000)
at .../gc.c:748
748 if (!is_white(obj)) return;
#1 mark_context_stack (mrb=0x5c8bec2836c8 <heap_pool+728>, c=0x5c8bec2b4a50 <heap_pool+202336>)
at .../gc.c:555
555 mrb_gc_mark(mrb, mrb_basic_ptr(v));
```
## Solution
I couldn't figure out the exact mechanism of the issue. Anyway, initializing the limit variable to zero could prevent invalid garbage stack memory:
```c
mrb_int limit = 0; // Explicit initialization
```
## Files Changed
- mrbgems/picoruby-mruby/lib/mruby/mrbgems/mruby-io/src/io.c
In the Windows-specific code path for IO.popen, the variable 'p'
is a struct, not a pointer. The code was using 'p->klass' to
access a member, which is incorrect and causes a build failure
on Windows. This has been corrected to use the 'klass' argument
directly.
Co-authored-by: Gemini <gemini@google.com>
Implements File.join in C for better performance, replacing the Ruby
implementation with direct C string manipulation and array processing.
Uses mruby's built-in recursion detection (MRB_RECURSIVE_UNARY_P) for
cleaner and more reliable recursive array handling.
Co-authored-by: Claude <noreply@anthropic.com>
Implements File.path in C for better performance, replacing the Ruby
implementation that used kind_of? check with direct C type validation.
Co-authored-by: Claude <noreply@anthropic.com>
Implement C version of File.extname for better performance:
- Direct C string processing instead of Ruby basename + rindex
- Efficient path parsing with single pass through string
- Proper handling of edge cases (dotfiles, trailing slashes, etc.)
- Maintains full compatibility with Ruby implementation
Performance improvement:
- Eliminates Ruby method call overhead for basename/rindex
- Direct C string operations vs Ruby string methods
- Faster path processing for file extension extraction
Co-authored-by: Claude <noreply@anthropic.com>
Moved IO#ungetbyte from Ruby to C implementation to eliminate
boundary crossing overhead and avoid temporary string allocations.
Added io_unget_data helper function to handle raw data operations
efficiently.
Co-authored-by: Claude <noreply@anthropic.com>
Moved IO#<< from Ruby to C implementation to reduce boundary
crossing overhead. Maintains full compatibility with automatic
to_s conversion and proper return value for method chaining.
Co-authored-by: Claude <noreply@anthropic.com>
Moved IO#print from Ruby to C implementation to reduce boundary
crossing overhead. Maintains full compatibility with automatic
to_s conversion for all arguments.
Co-authored-by: Claude <noreply@anthropic.com>
Moved IO#puts from Ruby to C implementation to reduce boundary
crossing overhead. Maintains full compatibility including array
recursion and newline handling.
Co-authored-by: Claude <noreply@anthropic.com>
Extract buffer adjustment logic from io_write into reusable helper
function io_prepare_write. This prepares for implementing io_puts
in C while maintaining consistency in write operations.
Co-authored-by: Claude <noreply@anthropic.com>
This commit refactors the `io_s_popen` function to improve readability
and maintainability. The function has been broken down into smaller,
more manageable functions, and the platform-specific code has been
separated.
Co-authored-by: Gemini <gemini@google.com>
The previous implementation of fd_write had a bug that caused it to
repeatedly write the entire string instead of the remaining portion.
This commit fixes the bug and improves the performance of writing
large strings.
Co-authored-by: Gemini <gemini@google.com>
Replace XML-style markup tags in comments with markdown equivalents:
- <code>...</code> to `...` (inline code)
- <tt>...</tt> to `...` (teletype/monospace)
- <i>...</i> to *...* (italics/emphasis)
- +...+ to `...` (parameter/variable references)
Updated 80+ files across core source, headers, mrbgems, and libraries
to use consistent markdown formatting in documentation comments.
Handled edge cases including special characters like <=> operators.
Co-authored-by: Atlassian Rovo Dev
Added complete call-seq documentation for the entire mruby-io gem across
both Ruby and C implementations:
## Ruby Methods (mrblib/) - 50 methods documented:
### Kernel Module (kernel.rb):
- Backtick operator: shell command execution with output capture
- open: unified file/subprocess opening with pipe support
- p: debug output with inspect formatting and multiple argument handling
- print/puts/printf: output methods with proper formatting and separators
- gets/readline/readlines: input methods with various line handling options
### File Constants (file_constants.rb):
- FNM_* constants: file name matching flags for glob and fnmatch operations
with detailed explanations of case sensitivity, escaping, and pattern behavior
### IO Class (io.rb):
Class methods:
- IO.open: creates IO objects with automatic resource management
- IO.popen: subprocess communication with pipe handling
- IO.pipe: creates connected pipe endpoints for IPC
- IO.read: convenience method for reading entire files
Instance methods:
- Stream positioning: pos=, rewind, tell with proper seeking behavior
- Iteration: each, each_byte, each_char with enumerator support
- Output: puts, print, printf with formatting and newline handling
- Utility: hash, <<, ungetbyte with proper stream manipulation
- Global streams: STDIN/STDOUT/STDERR and $stdin/$stdout/$stderr
### File Class (file.rb):
Instance methods:
- Constructor: handles both file paths and file descriptors
- Timestamps: atime, ctime, mtime with proper Time object conversion
- Inspection: inspect method for debugging file objects
Class methods:
- Path utilities: join with cross-platform separator handling
- File iteration: foreach with block and enumerator support
- FileTest delegation: complete set of file type and existence checks
(directory?, exist?, file?, pipe?, size, socket?, symlink?, zero?)
- Path manipulation: extname for extension extraction, path for conversion
## C Methods (src/) - 25 methods documented:
### Core IO Operations (io.c):
- File descriptor management: fileno with proper error handling
- Stream state: closed?, eof?, sync/sync= for buffering control
- Process management: pid for pipe process tracking
- Resource management: close_on_exec?/close_on_exec= for FD_CLOEXEC handling
### Reading Operations:
- Character reading: getc, readchar with EOF handling differences
- Byte reading: getbyte, readbyte with integer conversion
- Buffer reading: read with length and output buffer support
- Stream manipulation: ungetc for character pushback
### System Operations:
- IO multiplexing: IO.select for monitoring multiple streams
- Constructor: IO.new for creating IO objects from file descriptors
- Stream flushing: flush for forcing output to OS
Co-authored-by: Atlassian Rovo Dev