diff --git a/binding-sandbox/binding-base.cpp b/binding-sandbox/binding-base.cpp index eb6b8da8..bceaf023 100644 --- a/binding-sandbox/binding-base.cpp +++ b/binding-sandbox/binding-base.cpp @@ -83,7 +83,7 @@ wasm_ptr_t binding_base::sandbox_malloc(wasm_size_t size) { // Verify that the entire allocated buffer is in valid memory wasm_ptr_t buf_end; - if (buf == 0 || __builtin_add_overflow(buf, size, &buf_end) || buf_end >= instance().w2c_memory.size) { + if (buf == 0 || (buf_end = buf + size) < buf || buf_end >= instance().w2c_memory.size) { return 0; } diff --git a/binding-sandbox/sandbox.cpp b/binding-sandbox/sandbox.cpp index 14a4312a..204db9b0 100644 --- a/binding-sandbox/sandbox.cpp +++ b/binding-sandbox/sandbox.cpp @@ -46,8 +46,8 @@ usize sandbox::sandbox_malloc(usize size) { // Verify that the returned pointer is non-null and the entire allocated buffer is in valid memory usize buf_end; - if (buf == WASM_NULL || __builtin_add_overflow(buf, size, &buf_end) || buf_end >= ruby->w2c_memory.size) { - throw SandboxOutOfMemoryException(); + if (buf == WASM_NULL || (buf_end = buf + size) < buf || buf_end >= ruby->w2c_memory.size) { + throw std::bad_alloc(); } return buf; @@ -58,83 +58,78 @@ void sandbox::sandbox_free(usize ptr) { } sandbox::sandbox() : ruby(new struct w2c_ruby), wasi(new wasi_t(ruby)), bindings(ruby), yielding(false), transitioning(false) { - try { - // Initialize the sandbox - wasm2c_ruby_instantiate(RB, wasi.get()); - w2c_ruby_mkxp_sandbox_init( - RB, - 0, // heap_free_slots - 1.1, // growth_factor - 0, // growth_max_slots - 0, // heap_free_slots_min_ratio - 0, // heap_free_slots_goal_ratio - 0, // heap_free_slots_max_ratio - 0, // uncollectible_wb_unprotected_objects_limit_ratio - 0, // oldobject_limit_factor - 1 * 0x100000, // malloc_limit_min - 4 * 0x100000, // malloc_limit_max - 1.1, // malloc_limit_growth_factor - 4 * 0x100000, // oldmalloc_limit_min - 8 * 0x100000, // oldmalloc_limit_max - 1.1 // oldmalloc_limit_growth_factor - ); + // Initialize the sandbox + wasm2c_ruby_instantiate(RB, wasi.get()); + w2c_ruby_mkxp_sandbox_init( + RB, + 0, // heap_free_slots + 1.1, // growth_factor + 0, // growth_max_slots + 0, // heap_free_slots_min_ratio + 0, // heap_free_slots_goal_ratio + 0, // heap_free_slots_max_ratio + 0, // uncollectible_wb_unprotected_objects_limit_ratio + 0, // oldobject_limit_factor + 1 * 0x100000, // malloc_limit_min + 4 * 0x100000, // malloc_limit_max + 1.1, // malloc_limit_growth_factor + 4 * 0x100000, // oldmalloc_limit_min + 8 * 0x100000, // oldmalloc_limit_max + 1.1 // oldmalloc_limit_growth_factor + ); - // Determine Ruby command-line arguments - std::vector args{"mkxp-z"}; - args.push_back("/mkxp-retro-dist/bin/mkxp-z"); - if (MJIT_ENABLED) { - std::string verboseLevel("--mjit-verbose="); - std::string maxCache("--mjit-max-cache="); - std::string minCalls("--mjit-min-calls="); - args.push_back("--mjit"); - verboseLevel += std::to_string(MJIT_VERBOSE); - maxCache += std::to_string(MJIT_MAX_CACHE); - minCalls += std::to_string(MJIT_MIN_CALLS); - args.push_back(verboseLevel.c_str()); - args.push_back(maxCache.c_str()); - args.push_back(minCalls.c_str()); - } else if (YJIT_ENABLED) { - args.push_back("--yjit"); - } - - // Copy all the command-line arguments into the sandbox (sandboxed code can't access memory that's outside the sandbox!) - usize argv_buf = sandbox_malloc(args.size() * sizeof(usize)); - for (usize i = 0; i < args.size(); ++i) { - usize arg_buf = sandbox_malloc(args[i].length() + 1); - std::strcpy((char *)WASM_MEM(arg_buf), args[i].c_str()); - WASM_SET(usize, argv_buf + i * sizeof(usize), arg_buf); - } - - // Pass the command-line arguments to Ruby - AWAIT(w2c_ruby_ruby_init_stack(RB, w2c_ruby_rb_wasm_get_stack_pointer(RB))); - AWAIT(w2c_ruby_ruby_init(RB)); - usize node; - AWAIT(node = w2c_ruby_ruby_options(RB, args.size(), argv_buf)); - - // Start up Ruby executable node - bool valid; - u32 state; - usize state_buf = sandbox_malloc(sizeof(usize)); - AWAIT(valid = w2c_ruby_ruby_executable_node(RB, node, state_buf)); - if (valid) { - AWAIT(state = w2c_ruby_ruby_exec_node(RB, node)); - } - if (!valid || state) { - throw SandboxNodeException(); - } - sandbox_free(state_buf); - - // Set the default encoding to UTF-8 - usize encoding; - AWAIT(encoding = w2c_ruby_rb_utf8_encoding(RB)); - usize enc; - AWAIT(enc = w2c_ruby_rb_enc_from_encoding(RB, encoding)); - AWAIT(w2c_ruby_rb_enc_set_default_internal(RB, enc)); - AWAIT(w2c_ruby_rb_enc_set_default_external(RB, enc)); - } catch (SandboxException &) { - wasm2c_ruby_free(RB); - throw; + // Determine Ruby command-line arguments + std::vector args{"mkxp-z"}; + args.push_back("/mkxp-retro-dist/bin/mkxp-z"); + if (MJIT_ENABLED) { + std::string verboseLevel("--mjit-verbose="); + std::string maxCache("--mjit-max-cache="); + std::string minCalls("--mjit-min-calls="); + args.push_back("--mjit"); + verboseLevel += std::to_string(MJIT_VERBOSE); + maxCache += std::to_string(MJIT_MAX_CACHE); + minCalls += std::to_string(MJIT_MIN_CALLS); + args.push_back(verboseLevel.c_str()); + args.push_back(maxCache.c_str()); + args.push_back(minCalls.c_str()); + } else if (YJIT_ENABLED) { + args.push_back("--yjit"); } + + // Copy all the command-line arguments into the sandbox (sandboxed code can't access memory that's outside the sandbox!) + usize argv_buf = sandbox_malloc(args.size() * sizeof(usize)); + for (usize i = 0; i < args.size(); ++i) { + usize arg_buf = sandbox_malloc(args[i].length() + 1); + std::strcpy((char *)WASM_MEM(arg_buf), args[i].c_str()); + WASM_SET(usize, argv_buf + i * sizeof(usize), arg_buf); + } + + // Pass the command-line arguments to Ruby + AWAIT(w2c_ruby_ruby_init_stack(RB, w2c_ruby_rb_wasm_get_stack_pointer(RB))); + AWAIT(w2c_ruby_ruby_init(RB)); + usize node; + AWAIT(node = w2c_ruby_ruby_options(RB, args.size(), argv_buf)); + + // Start up Ruby executable node + bool valid; + u32 state; + usize state_buf = sandbox_malloc(sizeof(usize)); + AWAIT(valid = w2c_ruby_ruby_executable_node(RB, node, state_buf)); + if (valid) { + AWAIT(state = w2c_ruby_ruby_exec_node(RB, node)); + } + if (!valid || state) { + std::abort(); + } + sandbox_free(state_buf); + + // Set the default encoding to UTF-8 + usize encoding; + AWAIT(encoding = w2c_ruby_rb_utf8_encoding(RB)); + usize enc; + AWAIT(enc = w2c_ruby_rb_enc_from_encoding(RB, encoding)); + AWAIT(w2c_ruby_rb_enc_set_default_internal(RB, enc)); + AWAIT(w2c_ruby_rb_enc_set_default_external(RB, enc)); } sandbox::~sandbox() { diff --git a/binding-sandbox/types.h b/binding-sandbox/types.h index 6872ed8d..cec26d57 100644 --- a/binding-sandbox/types.h +++ b/binding-sandbox/types.h @@ -53,12 +53,4 @@ typedef float f32; typedef double f64; #endif // WASM_RT_CORE_TYPES_DEFINED -struct SandboxException {}; -// The call to `ruby_executable_node()` or `ruby_exec_node()` failed when initializing Ruby. -struct SandboxNodeException : SandboxException {}; -// Failed to allocate memory. -struct SandboxOutOfMemoryException : SandboxException {}; -// An exception occurred inside of Ruby and was not caught. -struct SandboxTrapException : SandboxException {}; - #endif // MKXPZ_SANDBOX_TYPES_H diff --git a/binding-sandbox/wasi.cpp b/binding-sandbox/wasi.cpp index 26987cfb..5c6041f5 100644 --- a/binding-sandbox/wasi.cpp +++ b/binding-sandbox/wasi.cpp @@ -805,7 +805,7 @@ extern "C" u32 w2c_wasi__snapshot__preview1_poll_oneoff(wasi_t *wasi, usize in, extern "C" void w2c_wasi__snapshot__preview1_proc_exit(wasi_t *wasi, u32 rval) { WASI_DEBUG("proc_exit(%u)\n", rval); - throw SandboxTrapException(); + std::abort(); } extern "C" u32 w2c_wasi__snapshot__preview1_random_get(wasi_t *wasi, usize buf, u32 buf_len) { diff --git a/libretro/sandbox-bindgen.rb b/libretro/sandbox-bindgen.rb index 1eb34afc..e3cbf76d 100644 --- a/libretro/sandbox-bindgen.rb +++ b/libretro/sandbox-bindgen.rb @@ -291,7 +291,7 @@ PRELUDE = <<~HEREDOC bindings::rb_data_type::rb_data_type(wasm_ptr_t ptr) : ptr(ptr) {} wasm_ptr_t bindings::rb_data_type::get() const { - if (ptr == 0) throw SandboxTrapException(); + if (ptr == 0) std::abort(); return ptr; } @@ -309,12 +309,12 @@ POSTSCRIPT = <<~HEREDOC buf = sandbox_malloc(9 * sizeof(wasm_ptr_t)); if (buf == 0) { - throw SandboxOutOfMemoryException(); + throw std::bad_alloc(); } str = sandbox_malloc(std::strlen(wrap_struct_name) + 1); if (str == 0) { sandbox_free(buf); - throw SandboxOutOfMemoryException(); + throw std::bad_alloc(); } std::strcpy((char *)(**this + str), wrap_struct_name); @@ -480,7 +480,7 @@ File.readlines('tags', chomp: true).each do |line| end coroutine_initializer += <<~HEREDOC default: - throw SandboxTrapException(); + std::abort(); } HEREDOC else @@ -498,7 +498,7 @@ File.readlines('tags', chomp: true).each do |line| elsif !handler[:buf_size].nil? coroutine_initializer += <<~HEREDOC f#{i} = bind.sandbox_malloc(#{handler[:buf_size].gsub('PREV_ARG', "a#{i - 1}").gsub('ARG', "a#{i}")}); - if (f#{i} == 0) throw SandboxOutOfMemoryException(); + if (f#{i} == 0) throw std::bad_alloc(); HEREDOC coroutine_initializer += handler[:serialize].gsub('PREV_ARG', "a#{i - 1}").gsub('ARG', "a#{i}").gsub('BUF', "f#{i}") coroutine_initializer += "\n" @@ -523,7 +523,7 @@ File.readlines('tags', chomp: true).each do |line| fp = w2c_ruby_rb_wasm_get_stack_pointer(&bind.instance()); sp = fp - CEIL_WASMSTACKALIGN(a#{args.length - 2} * sizeof(VALUE)); if (sp > fp) { - throw SandboxOutOfMemoryException(); + throw std::bad_alloc(); } w2c_ruby_rb_wasm_set_stack_pointer(&bind.instance(), sp); std::va_list a; @@ -550,7 +550,7 @@ File.readlines('tags', chomp: true).each do |line| fp = w2c_ruby_rb_wasm_get_stack_pointer(&bind.instance()); sp = fp - CEIL_WASMSTACKALIGN(n * sizeof(VALUE)); if (sp > fp) { - throw SandboxOutOfMemoryException(); + throw std::bad_alloc(); } w2c_ruby_rb_wasm_set_stack_pointer(&bind.instance(), sp); for (wasm_size_t i = 0; i < n; ++i) { diff --git a/src/core.cpp b/src/core.cpp index c96cadab..987ea730 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -320,13 +320,7 @@ static bool init_sandbox() { audio.emplace(*thread_data); - try { - mkxp_retro::sandbox.emplace(); - } catch (SandboxException) { - log_printf(RETRO_LOG_ERROR, "Failed to initialize Ruby\n"); - deinit_sandbox(); - return false; - } + mkxp_retro::sandbox.emplace(); { float refresh_rate; @@ -467,13 +461,8 @@ extern "C" RETRO_API void retro_run() { } if (should_render) { - try { - if (sb().run()) { - log_printf(RETRO_LOG_INFO, "[Sandbox] Ruby terminated normally\n"); - deinit_sandbox(); - } - } catch (SandboxException) { - log_printf(RETRO_LOG_ERROR, "[Sandbox] Ruby threw an exception\n"); + if (sb().run()) { + log_printf(RETRO_LOG_INFO, "[Sandbox] Ruby terminated normally\n"); deinit_sandbox(); } } else if (!dupe_supported && mkxp_retro::sandbox.has_value()) {