From 9de5c85a7a98f665849d184d0abd059fbb3ac306 Mon Sep 17 00:00:00 2001 From: Julius Jurgelenas Date: Sun, 15 Mar 2026 16:12:14 +0200 Subject: [PATCH] Fix WASI path pointer cast and add new feature flags Fix a bug in set_wasi_context where Vec was cast directly to *const c_char. CString is a 24-byte struct, not an 8-byte pointer, so WAMR received garbage pointers for preopened directory paths, causing segfaults in os_realpath during module instantiation. The fix collects CString pointers into a separate Vec<*const c_char> stored on the Module struct, matching how env and args are already handled. New configurable feature flags: - exception-handling: WAMR_BUILD_EXCE_HANDLING - shared-memory: WAMR_BUILD_SHARED_MEMORY + WAMR_BUILD_THREAD_MGR - wasi-threads: WAMR_BUILD_LIB_WASI_THREADS (implies shared-memory) - fast-interp: WAMR_BUILD_FAST_INTERP Also makes wamrc (AOT compiler) build conditional on the llvmjit feature, so users without LLVM can build for interpreter-only use. --- Cargo.toml | 4 ++ crates/wamr-sys/Cargo.toml | 4 ++ crates/wamr-sys/build.rs | 100 +++++++++++++++++-------------------- src/module.rs | 28 +++++++++-- 4 files changed, 77 insertions(+), 59 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c2aa3b..65558d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,11 @@ component_dirs = ["./crates/wamr-sys/wasm-micro-runtime/build-scripts/esp-idf"] custom-section = ["wamr-sys/custom-section"] dump-call-stack = ["wamr-sys/dump-call-stack"] esp-idf = ["esp-idf-sys", "wamr-sys/esp-idf"] +exception-handling = ["wamr-sys/exception-handling"] +fast-interp = ["wamr-sys/fast-interp"] hw-bound-check = ["wamr-sys/hw-bound-check"] llvmjit = ["wamr-sys/llvmjit"] multi-module = ["wamr-sys/multi-module"] name-section = ["wamr-sys/name-section"] +shared-memory = ["wamr-sys/shared-memory"] +wasi-threads = ["wamr-sys/wasi-threads"] diff --git a/crates/wamr-sys/Cargo.toml b/crates/wamr-sys/Cargo.toml index c8e96aa..b352b5e 100644 --- a/crates/wamr-sys/Cargo.toml +++ b/crates/wamr-sys/Cargo.toml @@ -34,8 +34,12 @@ cmake = "0.1" custom-section = [] dump-call-stack = [] esp-idf = [] +exception-handling = [] +fast-interp = [] hw-bound-check = [] llvmjit = [] multi-module = [] name-section = [ "custom-section" ] +shared-memory = [] std = [] +wasi-threads = ["shared-memory"] diff --git a/crates/wamr-sys/build.rs b/crates/wamr-sys/build.rs index 5874615..1366b3e 100644 --- a/crates/wamr-sys/build.rs +++ b/crates/wamr-sys/build.rs @@ -47,42 +47,32 @@ fn check_is_espidf() -> bool { is_espidf } -fn get_feature_flags() -> (String, String, String, String, String, String) { - let enable_custom_section = if cfg!(feature = "custom-section") { - "1" - } else { - "0" - }; - let enable_dump_call_stack = if cfg!(feature = "dump-call-stack") { - "1" - } else { - "0" - }; - let enable_llvm_jit = if cfg!(feature = "llvmjit") { "1" } else { "0" }; - let enable_multi_module = if cfg!(feature = "multi-module") { - "1" - } else { - "0" - }; - let enable_name_section = if cfg!(feature = "name-section") { - "1" - } else { - "0" - }; - let disable_hw_bound_check = if cfg!(feature = "hw-bound-check") { - "0" - } else { - "1" - }; - - ( - enable_custom_section.to_string(), - enable_dump_call_stack.to_string(), - enable_llvm_jit.to_string(), - enable_multi_module.to_string(), - enable_name_section.to_string(), - disable_hw_bound_check.to_string(), - ) +struct FeatureFlags { + enable_custom_section: String, + enable_dump_call_stack: String, + enable_llvm_jit: String, + enable_multi_module: String, + enable_name_section: String, + disable_hw_bound_check: String, + enable_exception_handling: String, + enable_shared_memory: String, + enable_wasi_threads: String, + enable_fast_interp: String, +} + +fn get_feature_flags() -> FeatureFlags { + FeatureFlags { + enable_custom_section: if cfg!(feature = "custom-section") { "1" } else { "0" }.to_string(), + enable_dump_call_stack: if cfg!(feature = "dump-call-stack") { "1" } else { "0" }.to_string(), + enable_llvm_jit: if cfg!(feature = "llvmjit") { "1" } else { "0" }.to_string(), + enable_multi_module: if cfg!(feature = "multi-module") { "1" } else { "0" }.to_string(), + enable_name_section: if cfg!(feature = "name-section") { "1" } else { "0" }.to_string(), + disable_hw_bound_check: if cfg!(feature = "hw-bound-check") { "0" } else { "1" }.to_string(), + enable_exception_handling: if cfg!(feature = "exception-handling") { "1" } else { "0" }.to_string(), + enable_shared_memory: if cfg!(feature = "shared-memory") { "1" } else { "0" }.to_string(), + enable_wasi_threads: if cfg!(feature = "wasi-threads") { "1" } else { "0" }.to_string(), + enable_fast_interp: if cfg!(feature = "fast-interp") { "1" } else { "0" }.to_string(), + } } fn link_llvm_libraries(llvm_cfg_path: &String, enable_llvm_jit: &String) { @@ -111,32 +101,28 @@ fn link_llvm_libraries(llvm_cfg_path: &String, enable_llvm_jit: &String) { fn setup_config( wamr_root: &PathBuf, - feature_flags: (String, String, String, String, String, String), + feature_flags: FeatureFlags, ) -> Config { - let ( - enable_custom_section, - enable_dump_call_stack, - enable_llvm_jit, - enable_multi_module, - enable_name_section, - disalbe_hw_bound_check, - ) = feature_flags; - let mut cfg = Config::new(wamr_root); cfg.define("WAMR_BUILD_AOT", "1") .define("WAMR_BUILD_INTERP", "1") - .define("WAMR_BUILD_FAST_INTERP", "1") - .define("WAMR_BUILD_JIT", &enable_llvm_jit) + .define("WAMR_BUILD_FAST_INTERP", &feature_flags.enable_fast_interp) + .define("WAMR_BUILD_JIT", &feature_flags.enable_llvm_jit) .define("WAMR_BUILD_BULK_MEMORY", "1") .define("WAMR_BUILD_REF_TYPES", "1") .define("WAMR_BUILD_SIMD", "1") .define("WAMR_BUILD_LIBC_WASI", "1") .define("WAMR_BUILD_LIBC_BUILTIN", "0") - .define("WAMR_DISABLE_HW_BOUND_CHECK", &disalbe_hw_bound_check) - .define("WAMR_BUILD_MULTI_MODULE", &enable_multi_module) - .define("WAMR_BUILD_DUMP_CALL_STACK", &enable_dump_call_stack) - .define("WAMR_BUILD_CUSTOM_NAME_SECTION", &enable_name_section) - .define("WAMR_BUILD_LOAD_CUSTOM_SECTION", &enable_custom_section); + .define("WAMR_DISABLE_HW_BOUND_CHECK", &feature_flags.disable_hw_bound_check) + .define("WAMR_DISABLE_STACK_HW_BOUND_CHECK", &feature_flags.disable_hw_bound_check) + .define("WAMR_BUILD_MULTI_MODULE", &feature_flags.enable_multi_module) + .define("WAMR_BUILD_DUMP_CALL_STACK", &feature_flags.enable_dump_call_stack) + .define("WAMR_BUILD_CUSTOM_NAME_SECTION", &feature_flags.enable_name_section) + .define("WAMR_BUILD_LOAD_CUSTOM_SECTION", &feature_flags.enable_custom_section) + .define("WAMR_BUILD_EXCE_HANDLING", &feature_flags.enable_exception_handling) + .define("WAMR_BUILD_SHARED_MEMORY", &feature_flags.enable_shared_memory) + .define("WAMR_BUILD_LIB_WASI_THREADS", &feature_flags.enable_wasi_threads) + .define("WAMR_BUILD_THREAD_MGR", &feature_flags.enable_shared_memory); // always assume non-empty strings for these environment variables @@ -153,7 +139,7 @@ fn setup_config( } if let Ok(llvm_cfg_path) = env::var("LLVM_LIB_CFG_PATH") { - link_llvm_libraries(&llvm_cfg_path, &enable_llvm_jit); + link_llvm_libraries(&llvm_cfg_path, &feature_flags.enable_llvm_jit); cfg.define("LLVM_DIR", &llvm_cfg_path); } @@ -224,7 +210,11 @@ fn main() { // because the ESP-IDF build procedure differs from the regular one // (build internally by esp-idf-sys), build_wamr_libraries(&wamr_root); - build_wamrc(&wamr_root); + + // Only build the AOT compiler (wamrc) when LLVM JIT is enabled + if cfg!(feature = "llvmjit") { + build_wamrc(&wamr_root); + } } generate_bindings(&wamr_root); diff --git a/src/module.rs b/src/module.rs index 68cbba5..5f9901a 100644 --- a/src/module.rs +++ b/src/module.rs @@ -34,6 +34,9 @@ pub struct Module<'runtime> { // to keep the module content in memory content: Vec, wasi_ctx: WasiCtx, + // cached pointer arrays for WASI paths (must outlive wasm_runtime_set_wasi_args call) + preopen_real_ptrs: Vec<*const c_char>, + preopen_mapped_ptrs: Vec<*const c_char>, _phantom: PhantomData<&'runtime Runtime>, } @@ -109,6 +112,8 @@ impl<'runtime> Module<'runtime> { module, content, wasi_ctx: WasiCtx::default(), + preopen_real_ptrs: Vec::new(), + preopen_mapped_ptrs: Vec::new(), _phantom: PhantomData, }) } @@ -119,16 +124,31 @@ impl<'runtime> Module<'runtime> { pub fn set_wasi_context(&mut self, wasi_ctx: WasiCtx) { self.wasi_ctx = wasi_ctx; - let real_paths = if self.wasi_ctx.get_preopen_real_paths().is_empty() { + // Build pointer arrays from CStrings for FFI. + // These must be stored on self to outlive the wasm_runtime_set_wasi_args call. + self.preopen_real_ptrs = self + .wasi_ctx + .get_preopen_real_paths() + .iter() + .map(|s| s.as_ptr() as *const c_char) + .collect(); + self.preopen_mapped_ptrs = self + .wasi_ctx + .get_preopen_mapped_paths() + .iter() + .map(|s| s.as_ptr() as *const c_char) + .collect(); + + let real_paths = if self.preopen_real_ptrs.is_empty() { ptr::null_mut() } else { - self.wasi_ctx.get_preopen_real_paths().as_ptr() as *mut *const c_char + self.preopen_real_ptrs.as_ptr() as *mut *const c_char }; - let mapped_paths = if self.wasi_ctx.get_preopen_mapped_paths().is_empty() { + let mapped_paths = if self.preopen_mapped_ptrs.is_empty() { ptr::null_mut() } else { - self.wasi_ctx.get_preopen_mapped_paths().as_ptr() as *mut *const c_char + self.preopen_mapped_ptrs.as_ptr() as *mut *const c_char }; let env = if self.wasi_ctx.get_env_vars().is_empty() {