diff --git a/build/emtests.rs b/build/emtests.rs index 0b5ed4fb01e..2d5306994ee 100644 --- a/build/emtests.rs +++ b/build/emtests.rs @@ -11,7 +11,7 @@ use std::process::Command; static BANNER: &str = "// Rust test file autogenerated with cargo build (build/emtests.rs). // Please do NOT modify it by hand, as it will be reseted on next build.\n"; -const TESTS: [&str; 2] = ["emtests/puts.c", "emtests/printf.c"]; +const TESTS: [&str; 3] = ["emtests/env.c", "emtests/puts.c", "emtests/printf.c"]; pub fn compile(file: &str) -> String { let mut output_path = PathBuf::from(file); diff --git a/emtests/env.c b/emtests/env.c new file mode 100644 index 00000000000..62a9024a3ff --- /dev/null +++ b/emtests/env.c @@ -0,0 +1,25 @@ +#include +#include +int main() +{ + printf("INIT\n"); + const char* UNEXISTENT_ENVVAR = getenv("UNEXISTENT_ENVVAR"); + printf("UNEXISTENT_ENVVAR = %s\n",(UNEXISTENT_ENVVAR!=NULL)? UNEXISTENT_ENVVAR : "[NULL]"); + printf("Setting UNEXISTENT_ENVVAR=PUTENV (via putenv)\n"); + putenv("UNEXISTENT_ENVVAR=PUTENV"); + UNEXISTENT_ENVVAR = getenv("UNEXISTENT_ENVVAR"); + printf("UNEXISTENT_ENVVAR = %s\n",(UNEXISTENT_ENVVAR!=NULL)? UNEXISTENT_ENVVAR : "[NULL]"); + printf("Setting UNEXISTENT_ENVVAR=SETENV (via setenv, overwrite)\n"); + setenv("UNEXISTENT_ENVVAR", "SETENV", 1); + UNEXISTENT_ENVVAR = getenv("UNEXISTENT_ENVVAR"); + printf("UNEXISTENT_ENVVAR = %s\n",(UNEXISTENT_ENVVAR!=NULL)? UNEXISTENT_ENVVAR : "[NULL]"); + printf("Setting UNEXISTENT_ENVVAR=SETENV_NEW (via setenv, NO overwrite)\n"); + setenv("UNEXISTENT_ENVVAR", "SETENV_NEW", 0); + UNEXISTENT_ENVVAR = getenv("UNEXISTENT_ENVVAR"); + printf("UNEXISTENT_ENVVAR = %s\n",(UNEXISTENT_ENVVAR!=NULL)? UNEXISTENT_ENVVAR : "[NULL]"); + printf("Unsetting UNEXISTENT_ENVVAR\n"); + unsetenv("UNEXISTENT_ENVVAR"); + UNEXISTENT_ENVVAR = getenv("UNEXISTENT_ENVVAR"); + printf("UNEXISTENT_ENVVAR = %s\n",(UNEXISTENT_ENVVAR!=NULL)? UNEXISTENT_ENVVAR : "[NULL]"); + printf("END\n"); +} diff --git a/emtests/env.output b/emtests/env.output new file mode 100644 index 00000000000..a6cb3209539 --- /dev/null +++ b/emtests/env.output @@ -0,0 +1,11 @@ +INIT +UNEXISTENT_ENVVAR = [NULL] +Setting UNEXISTENT_ENVVAR=PUTENV (via putenv) +UNEXISTENT_ENVVAR = PUTENV +Setting UNEXISTENT_ENVVAR=SETENV (via setenv, overwrite) +UNEXISTENT_ENVVAR = SETENV +Setting UNEXISTENT_ENVVAR=SETENV_NEW (via setenv, NO overwrite) +UNEXISTENT_ENVVAR = SETENV +Unsetting UNEXISTENT_ENVVAR +UNEXISTENT_ENVVAR = [NULL] +END diff --git a/emtests/env.wasm b/emtests/env.wasm new file mode 100644 index 00000000000..0df9e53a585 Binary files /dev/null and b/emtests/env.wasm differ diff --git a/emtests/printf.wasm b/emtests/printf.wasm index 69cc16f2b77..c3f19ab96f8 100644 Binary files a/emtests/printf.wasm and b/emtests/printf.wasm differ diff --git a/src/apis/emscripten/README.md b/src/apis/emscripten/README.md index e5858b17fc2..b88f1fc03a3 100644 --- a/src/apis/emscripten/README.md +++ b/src/apis/emscripten/README.md @@ -26,9 +26,21 @@ ###### ENVIRONMENT -- **\_getenv**     [:top:](#host-apis) +- **\_getenv** ✅     [:top:](#host-apis) ```rust - + fn _getenv(name: c_int, instance: &mut Instance) + ``` +- **\_putenv** ✅     [:top:](#host-apis) + ```rust + fn _putenv(name: c_int, instance: &mut Instance) + ``` +- **\_setenv** ✅     [:top:](#host-apis) + ```rust + fn _setenv(name: c_int, value: c_int, overwrite: c_int, instance: &mut Instance + ``` +- **\_unsetenv** ✅     [:top:](#host-apis) + ```rust + fn _unsetenv(name: c_int, instance: &mut Instance) ``` ###### THREAD @@ -44,10 +56,6 @@ - **\_pthread_setspecific**     [:top:](#host-apis) ```rust - ``` -- **\_unsetenv**     [:top:](#host-apis) - ```rust - ``` - **\_\_\_lock**     [:top:](#host-apis) ```rust diff --git a/src/apis/emscripten/env.rs b/src/apis/emscripten/env.rs index fd8ea10b581..9e82cab715f 100644 --- a/src/apis/emscripten/env.rs +++ b/src/apis/emscripten/env.rs @@ -1,11 +1,14 @@ use super::super::host; /// NOTE: These syscalls only support wasm_32 for now because they take u32 offset -use libc::{c_int, c_long, getenv, getgrnam as libc_getgrnam, getpwnam as libc_getpwnam, sysconf}; +use libc::{ + c_int, c_long, getenv, getgrnam as libc_getgrnam, getpwnam as libc_getpwnam, putenv, setenv, + sysconf, unsetenv, +}; use std::ffi::CStr; use std::mem; use std::os::raw::c_char; -use super::utils::{copy_cstr_into_wasm, copy_terminated_array_of_cstrs}; +use super::utils::{allocate_on_stack, copy_cstr_into_wasm, copy_terminated_array_of_cstrs}; use crate::webassembly::Instance; // #[no_mangle] @@ -25,6 +28,41 @@ pub extern "C" fn _getenv(name: c_int, instance: &mut Instance) -> u32 { unsafe { copy_cstr_into_wasm(instance, c_str) } } +/// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int); +pub extern "C" fn _setenv(name: c_int, value: c_int, overwrite: c_int, instance: &mut Instance) { + debug!("emscripten::_setenv"); + + let name_addr = instance.memory_offset_addr(0, name as usize) as *const c_char; + let value_addr = instance.memory_offset_addr(0, value as usize) as *const c_char; + + debug!("=> name({:?})", unsafe { CStr::from_ptr(name_addr) }); + debug!("=> value({:?})", unsafe { CStr::from_ptr(value_addr) }); + + unsafe { setenv(name_addr, value_addr, overwrite) }; +} + +/// emscripten: _putenv // (name: *const char); +pub extern "C" fn _putenv(name: c_int, instance: &mut Instance) { + debug!("emscripten::_putenv"); + + let name_addr = instance.memory_offset_addr(0, name as usize) as *const c_char; + + debug!("=> name({:?})", unsafe { CStr::from_ptr(name_addr) }); + + unsafe { putenv(name_addr as _) }; +} + +/// emscripten: _unsetenv // (name: *const char); +pub extern "C" fn _unsetenv(name: c_int, instance: &mut Instance) { + debug!("emscripten::_unsetenv"); + + let name_addr = instance.memory_offset_addr(0, name as usize) as *const c_char; + + debug!("=> name({:?})", unsafe { CStr::from_ptr(name_addr) }); + + unsafe { unsetenv(name_addr) }; +} + pub extern "C" fn _getpwnam(name_ptr: c_int, instance: &mut Instance) -> c_int { debug!("emscripten::_getpwnam {}", name_ptr); @@ -104,8 +142,26 @@ pub extern "C" fn _getpagesize() -> u32 { 16384 } -pub extern "C" fn ___build_environment(environ: c_int) { +pub extern "C" fn ___build_environment(environ: c_int, instance: &mut Instance) { debug!("emscripten::___build_environment {}", environ); + const MAX_ENV_VALUES: u32 = 64; + const TOTAL_ENV_SIZE: u32 = 1024; + let mut environment = instance.memory_offset_addr(0, environ as _) as *mut c_int; + unsafe { + let (pool_offset, pool_slice): (u32, &mut [u8]) = + allocate_on_stack(TOTAL_ENV_SIZE as u32, instance); + let (env_offset, env_slice): (u32, &mut [u8]) = + allocate_on_stack((MAX_ENV_VALUES * 4) as u32, instance); + let mut env_ptr = instance.memory_offset_addr(0, env_offset as _) as *mut c_int; + let mut pool_ptr = instance.memory_offset_addr(0, pool_offset as _) as *mut c_int; + *env_ptr = pool_offset as i32; + *environment = env_offset as i32; + + // *env_ptr = 0; + }; + // unsafe { + // *env_ptr = 0; + // }; } pub extern "C" fn _sysconf(name: c_int, _instance: &mut Instance) -> c_long { diff --git a/src/apis/emscripten/mod.rs b/src/apis/emscripten/mod.rs index 413171e6392..44743d812d0 100644 --- a/src/apis/emscripten/mod.rs +++ b/src/apis/emscripten/mod.rs @@ -114,6 +114,9 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { import_object.set("env", "___wait", ImportValue::Func(lock::___wait as _)); // Env import_object.set("env", "_getenv", ImportValue::Func(env::_getenv as _)); + import_object.set("env", "_setenv", ImportValue::Func(env::_setenv as _)); + import_object.set("env", "_putenv", ImportValue::Func(env::_putenv as _)); + import_object.set("env", "_unsetenv", ImportValue::Func(env::_unsetenv as _)); import_object.set("env", "_getpwnam", ImportValue::Func(env::_getpwnam as _)); import_object.set("env", "_getgrnam", ImportValue::Func(env::_getgrnam as _)); import_object.set( diff --git a/src/emtests/env.rs b/src/emtests/env.rs new file mode 100644 index 00000000000..58b674a3fc0 --- /dev/null +++ b/src/emtests/env.rs @@ -0,0 +1,9 @@ +#[test] +fn test_env() { + assert_emscripten_output!( + "../../emtests/env.wasm", + "env", + vec![], + "../../emtests/env.output" + ); +} diff --git a/src/emtests/mod.rs b/src/emtests/mod.rs index 69466d27ece..b5572f6ddd6 100644 --- a/src/emtests/mod.rs +++ b/src/emtests/mod.rs @@ -4,5 +4,6 @@ // The _common module is not autogenerated, as it provides common macros for the emtests #[macro_use] mod _common; +mod env; mod printf; mod puts;