danielpclark / rutie

“The Tie Between Ruby and Rust.”
MIT License
939 stars 62 forks source link

Implement bindings to ruby_sysinit and ruby_init_stack (Segmentation fault in Windows on VM#init) #162

Open somedevfox opened 1 year ago

somedevfox commented 1 year ago

Hello all,

Description of issue

Rutie is missing bindings to Virtual Machine Initialization methods such as ruby_sysinit and ruby_init_stack which are vital on Windows New Technology Operating Systems. If one does not use them, they will get STATUS_ACCESS_VIOLATION (Segmentation Fault) on Ruby 3.1 (and on previous versions, perhaps?).

Host information

OS Version: Windows 10 21H2 (19044.1889) Rust Version: 1.65.0-nightly Linked with Ruby Version: 3.1

Steps to reproduce STATUS_ACCESS_VIOLATION

  1. Install dependencies
  2. Clone rcxp
  3. Run in shell cargo run
  4. error: process didn't exit successfully: 'target\debug\rcxp.exe' (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)

Method signatures and their descriptions:

// ruby/interpreter.h

/**
 * Initializes the process for libruby.
 *
 * This function assumes this process is `ruby(1)` and it has just started.
 * Usually programs that embed CRuby interpreter may not call this function,
 * and may do their own initialization.
 *
 * @param[in]  argc  Pointer to process main's `argc`.
 * @param[in]  argv  Pointer to process main's `argv`.
 * @warning    `argc` and `argv` cannot be `NULL`.
 *
 * @internal
 *
 * AFAIK Ruby does write to argv, especially `argv[0][0]`, via setproctitle(3).
 * It is intentional that the argument is not const-qualified.
 */
void ruby_sysinit(int *argc, char ***argv);

/**
 * Set stack bottom of Ruby implementation.
 *
 * You  must   call  this   function  before  any   heap  allocation   by  Ruby
 * implementation.  Or GC will break living objects.
 *
 * @param[in]  addr  A pointer somewhere on the stack, near its bottom.
 */
void ruby_init_stack(volatile VALUE *addr);

And I'm pretty sure they're needed, since I also tried initializing Ruby Virtual Machine from Pure C and it didn't work without at least ruby_sysinit.

So, there are two options.

  1. Implement VM#init_sys - ruby_sysinit and VM#init_stack - ruby_init_stack, requiring Rutie Dev to use them before VM Initialization.
  2. Instead of implementing two new methods, we can modfy VM#init to use these functions internally, freeing the developer from additional code.

What's the better way to go around this?