From d825fe9eb25d1327769be2a846d487cf4f91dc39 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 1 Jul 2019 11:42:50 -0700 Subject: [PATCH] remove unix-specific code from code windows sees --- lib/emscripten/src/emscripten_target.rs | 28 +-- lib/emscripten/src/env/mod.rs | 240 ++++-------------------- lib/emscripten/src/env/unix/mod.rs | 199 +++++++++++++++++++- lib/emscripten/src/env/windows/mod.rs | 20 +- lib/emscripten/src/lib.rs | 2 +- 5 files changed, 252 insertions(+), 237 deletions(-) diff --git a/lib/emscripten/src/emscripten_target.rs b/lib/emscripten/src/emscripten_target.rs index a533b094b..6b13beec8 100644 --- a/lib/emscripten/src/emscripten_target.rs +++ b/lib/emscripten/src/emscripten_target.rs @@ -1,13 +1,9 @@ #![allow(non_snake_case)] -use crate::env::{call_malloc_with_cast, get_emscripten_data}; -use libc::c_char; +use crate::env::get_emscripten_data; #[cfg(target_os = "linux")] use libc::getdtablesize; -use wasmer_runtime_core::{ - memory::ptr::{Array, WasmPtr}, - vm::Ctx, -}; +use wasmer_runtime_core::vm::Ctx; pub fn asm_const_i(_ctx: &mut Ctx, _val: i32) -> i32 { debug!("emscripten::asm_const_i: {}", _val); @@ -237,26 +233,6 @@ pub fn ___gxx_personality_v0( 0 } -// this may be a memory leak, probably not though because emscripten does the same thing -pub fn _gai_strerror(ctx: &mut Ctx, ecode: i32) -> i32 { - debug!("emscripten::_gai_strerror({})", ecode); - - let cstr = unsafe { std::ffi::CStr::from_ptr(libc::gai_strerror(ecode)) }; - let bytes = cstr.to_bytes_with_nul(); - let string_on_guest: WasmPtr = call_malloc_with_cast(ctx, bytes.len() as _); - - let writer = unsafe { - string_on_guest - .deref_mut(ctx.memory(0), 0, bytes.len() as _) - .unwrap() - }; - for (i, byte) in bytes.iter().enumerate() { - writer[i].set(*byte as i8); - } - - string_on_guest.offset() as _ -} - #[cfg(target_os = "linux")] pub fn _getdtablesize(_ctx: &mut Ctx) -> i32 { debug!("emscripten::getdtablesize"); diff --git a/lib/emscripten/src/env/mod.rs b/lib/emscripten/src/env/mod.rs index 093ec7973..1b958db9e 100644 --- a/lib/emscripten/src/env/mod.rs +++ b/lib/emscripten/src/env/mod.rs @@ -14,7 +14,6 @@ use libc::c_char; use crate::{allocate_on_stack, EmscriptenData}; -use std::cell::Cell; use std::os::raw::c_int; use wasmer_runtime_core::{ memory::ptr::{Array, WasmPtr}, @@ -22,211 +21,6 @@ use wasmer_runtime_core::{ vm::Ctx, }; -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct EmAddrInfo { - // int - ai_flags: i32, - // int - ai_family: i32, - // int - ai_socktype: i32, - // int - ai_protocol: i32, - // socklen_t - ai_addrlen: u32, - // struct sockaddr* - ai_addr: WasmPtr, - // char* - ai_canonname: WasmPtr, - // struct addrinfo* - ai_next: WasmPtr, -} - -unsafe impl ValueType for EmAddrInfo {} - -// NOTE: from looking at emscripten JS, this should be a union -// TODO: review this, highly likely to have bugs -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct EmSockAddr { - sa_family: i16, - sa_data: [c_char; 14], -} - -unsafe impl ValueType for EmSockAddr {} - -pub fn _getaddrinfo( - ctx: &mut Ctx, - node_ptr: WasmPtr, - service_str_ptr: WasmPtr, - hints_ptr: WasmPtr, - res_val_ptr: WasmPtr>, -) -> i32 { - use libc::{addrinfo, freeaddrinfo}; - debug!("emscripten::_getaddrinfo"); - let memory = ctx.memory(0); - debug!(" => node = {}", unsafe { - node_ptr - .deref(memory) - .map(|np| { - std::ffi::CStr::from_ptr(np as *const Cell as *const c_char) - .to_string_lossy() - }) - .unwrap_or(std::borrow::Cow::Borrowed("null")) - }); - debug!(" => server_str = {}", unsafe { - service_str_ptr - .deref(memory) - .map(|np| { - std::ffi::CStr::from_ptr(np as *const Cell as *const c_char) - .to_string_lossy() - }) - .unwrap_or(std::borrow::Cow::Borrowed("null")) - }); - - let hints = hints_ptr.deref(memory).map(|hints_memory| { - let hints_guest = dbg!(hints_memory.get()); - unsafe { - let mut hints_native: addrinfo = std::mem::uninitialized(); - hints_native.ai_flags = hints_guest.ai_flags; - hints_native.ai_family = hints_guest.ai_family; - hints_native.ai_socktype = hints_guest.ai_socktype; - hints_native.ai_protocol = hints_guest.ai_protocol; - hints_native.ai_addrlen = 0; - hints_native.ai_addr = std::ptr::null_mut(); - hints_native.ai_canonname = std::ptr::null_mut(); - hints_native.ai_next = std::ptr::null_mut(); - - hints_native - } - }); - - let mut out_ptr: *mut addrinfo = std::ptr::null_mut(); - - // allocate equivalent memory for res_val_ptr - let result = unsafe { - libc::getaddrinfo( - (node_ptr - .deref(memory) - .map(|m| m as *const Cell as *const c_char)) - .unwrap_or(std::ptr::null()), - (service_str_ptr - .deref(memory) - .map(|m| m as *const Cell as *const c_char)) - .unwrap_or(std::ptr::null()), - hints - .as_ref() - .map(|h| h as *const addrinfo) - .unwrap_or(std::ptr::null()), - &mut out_ptr as *mut *mut addrinfo, - ) - }; - if dbg!(result) != 0 { - return result; - } - - // walk linked list and copy over, freeing them from the kernel - let head_of_list = unsafe { - let mut current_host_node = out_ptr; - let mut head_of_list = None; - let mut previous_guest_node: Option> = None; - - while !current_host_node.is_null() { - let current_guest_node_ptr: WasmPtr = - call_malloc_with_cast(ctx, std::mem::size_of::() as _); - if head_of_list.is_none() { - dbg!("Setting head of list"); - head_of_list = Some(current_guest_node_ptr); - } - - // connect list - if let Some(prev_guest) = previous_guest_node { - let mut pg = prev_guest.deref_mut(ctx.memory(0)).unwrap().get_mut(); - pg.ai_next = current_guest_node_ptr; - dbg!("list connected"); - } - - // update values - - let host_addrlen = (*current_host_node).ai_addrlen; - // allocate addr and copy data - let guest_sockaddr_ptr = { - let host_sockaddr_ptr = (*current_host_node).ai_addr; - let guest_sockaddr_ptr: WasmPtr = - call_malloc_with_cast(ctx, host_addrlen as _); - let guest_sockaddr = guest_sockaddr_ptr - .deref_mut(ctx.memory(0)) - .unwrap() - .get_mut(); - - guest_sockaddr.sa_family = (*host_sockaddr_ptr).sa_family as i16; - guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data.clone(); - guest_sockaddr_ptr - }; - - dbg!("Socketaddr allocated"); - - // allocate canon name on guest and copy data over - let guest_canonname_ptr = { - let str_ptr = (*current_host_node).ai_canonname; - if !str_ptr.is_null() { - let canonname_cstr = dbg!(std::ffi::CStr::from_ptr(str_ptr)); - let canonname_bytes = canonname_cstr.to_bytes_with_nul(); - let str_size = dbg!(canonname_bytes.len()); - let guest_canonname: WasmPtr = - call_malloc_with_cast(ctx, str_size as _); - - let guest_canonname_writer = guest_canonname - .deref(ctx.memory(0), 0, str_size as _) - .unwrap(); - for (i, b) in canonname_bytes.into_iter().enumerate() { - guest_canonname_writer[i].set(*b as i8) - } - - guest_canonname - } else { - WasmPtr::new(0) - } - }; - - dbg!("canonname allocated"); - - let mut current_guest_node = current_guest_node_ptr - .deref_mut(ctx.memory(0)) - .unwrap() - .get_mut(); - // TODO order these - current_guest_node.ai_flags = (*current_host_node).ai_flags; - current_guest_node.ai_family = (*current_host_node).ai_family; - current_guest_node.ai_socktype = (*current_host_node).ai_socktype; - current_guest_node.ai_protocol = (*current_host_node).ai_protocol; - current_guest_node.ai_addrlen = host_addrlen; - current_guest_node.ai_addr = guest_sockaddr_ptr; - current_guest_node.ai_canonname = guest_canonname_ptr; - current_guest_node.ai_next = WasmPtr::new(0); - - dbg!("Guest node updated"); - - previous_guest_node = Some(current_guest_node_ptr); - current_host_node = (*current_host_node).ai_next; - dbg!("End of loop bookkeeping finished"); - } - - dbg!("freeing memory"); - // this frees all connected nodes on the linked list - freeaddrinfo(out_ptr); - head_of_list.unwrap_or(WasmPtr::new(0)) - }; - - res_val_ptr - .deref(ctx.memory(0)) - .unwrap() - .set(dbg!(head_of_list)); - - 0 -} - pub fn call_malloc(ctx: &mut Ctx, size: u32) -> u32 { get_emscripten_data(ctx).malloc.call(size).unwrap() } @@ -362,3 +156,37 @@ pub fn _fpathconf(_ctx: &mut Ctx, _fildes: c_int, name: c_int) -> c_int { } } } + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct EmAddrInfo { + // int + pub ai_flags: i32, + // int + pub ai_family: i32, + // int + pub ai_socktype: i32, + // int + pub ai_protocol: i32, + // socklen_t + pub ai_addrlen: u32, + // struct sockaddr* + pub ai_addr: WasmPtr, + // char* + pub ai_canonname: WasmPtr, + // struct addrinfo* + pub ai_next: WasmPtr, +} + +unsafe impl ValueType for EmAddrInfo {} + +// NOTE: from looking at emscripten JS, this should be a union +// TODO: review this, highly likely to have bugs +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct EmSockAddr { + pub sa_family: i16, + pub sa_data: [c_char; 14], +} + +unsafe impl ValueType for EmSockAddr {} diff --git a/lib/emscripten/src/env/unix/mod.rs b/lib/emscripten/src/env/unix/mod.rs index 7c846150f..2f4c7f118 100644 --- a/lib/emscripten/src/env/unix/mod.rs +++ b/lib/emscripten/src/env/unix/mod.rs @@ -3,13 +3,17 @@ use libc::{ c_int, getenv, getgrnam as libc_getgrnam, getpwnam as libc_getpwnam, putenv, setenv, sysconf, unsetenv, }; +use std::cell::Cell; use std::ffi::CStr; use std::mem; use std::os::raw::c_char; -use crate::env::call_malloc; +use crate::env::{call_malloc, call_malloc_with_cast, EmAddrInfo, EmSockAddr}; use crate::utils::{copy_cstr_into_wasm, copy_terminated_array_of_cstrs}; -use wasmer_runtime_core::vm::Ctx; +use wasmer_runtime_core::{ + memory::ptr::{Array, WasmPtr}, + vm::Ctx, +}; // #[no_mangle] /// emscripten: _getenv // (name: *const char) -> *const c_char; @@ -140,3 +144,194 @@ pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> i32 { // TODO: Implement like emscripten expects regarding memory/page size unsafe { sysconf(name) as i32 } // TODO review i64 } + +// this may be a memory leak, probably not though because emscripten does the same thing +pub fn _gai_strerror(ctx: &mut Ctx, ecode: i32) -> i32 { + debug!("emscripten::_gai_strerror({})", ecode); + + let cstr = unsafe { std::ffi::CStr::from_ptr(libc::gai_strerror(ecode)) }; + let bytes = cstr.to_bytes_with_nul(); + let string_on_guest: WasmPtr = call_malloc_with_cast(ctx, bytes.len() as _); + + let writer = unsafe { + string_on_guest + .deref_mut(ctx.memory(0), 0, bytes.len() as _) + .unwrap() + }; + for (i, byte) in bytes.iter().enumerate() { + writer[i].set(*byte as i8); + } + + string_on_guest.offset() as _ +} + +pub fn _getaddrinfo( + ctx: &mut Ctx, + node_ptr: WasmPtr, + service_str_ptr: WasmPtr, + hints_ptr: WasmPtr, + res_val_ptr: WasmPtr>, +) -> i32 { + use libc::{addrinfo, freeaddrinfo}; + debug!("emscripten::_getaddrinfo"); + let memory = ctx.memory(0); + debug!(" => node = {}", unsafe { + node_ptr + .deref(memory) + .map(|np| { + std::ffi::CStr::from_ptr(np as *const Cell as *const c_char) + .to_string_lossy() + }) + .unwrap_or(std::borrow::Cow::Borrowed("null")) + }); + debug!(" => server_str = {}", unsafe { + service_str_ptr + .deref(memory) + .map(|np| { + std::ffi::CStr::from_ptr(np as *const Cell as *const c_char) + .to_string_lossy() + }) + .unwrap_or(std::borrow::Cow::Borrowed("null")) + }); + + let hints = hints_ptr.deref(memory).map(|hints_memory| { + let hints_guest = dbg!(hints_memory.get()); + unsafe { + let mut hints_native: addrinfo = std::mem::uninitialized(); + hints_native.ai_flags = hints_guest.ai_flags; + hints_native.ai_family = hints_guest.ai_family; + hints_native.ai_socktype = hints_guest.ai_socktype; + hints_native.ai_protocol = hints_guest.ai_protocol; + hints_native.ai_addrlen = 0; + hints_native.ai_addr = std::ptr::null_mut(); + hints_native.ai_canonname = std::ptr::null_mut(); + hints_native.ai_next = std::ptr::null_mut(); + + hints_native + } + }); + + let mut out_ptr: *mut addrinfo = std::ptr::null_mut(); + + // allocate equivalent memory for res_val_ptr + let result = unsafe { + libc::getaddrinfo( + (node_ptr + .deref(memory) + .map(|m| m as *const Cell as *const c_char)) + .unwrap_or(std::ptr::null()), + (service_str_ptr + .deref(memory) + .map(|m| m as *const Cell as *const c_char)) + .unwrap_or(std::ptr::null()), + hints + .as_ref() + .map(|h| h as *const addrinfo) + .unwrap_or(std::ptr::null()), + &mut out_ptr as *mut *mut addrinfo, + ) + }; + if dbg!(result) != 0 { + return result; + } + + // walk linked list and copy over, freeing them from the kernel + let head_of_list = unsafe { + let mut current_host_node = out_ptr; + let mut head_of_list = None; + let mut previous_guest_node: Option> = None; + + while !current_host_node.is_null() { + let current_guest_node_ptr: WasmPtr = + call_malloc_with_cast(ctx, std::mem::size_of::() as _); + if head_of_list.is_none() { + dbg!("Setting head of list"); + head_of_list = Some(current_guest_node_ptr); + } + + // connect list + if let Some(prev_guest) = previous_guest_node { + let mut pg = prev_guest.deref_mut(ctx.memory(0)).unwrap().get_mut(); + pg.ai_next = current_guest_node_ptr; + dbg!("list connected"); + } + + // update values + + let host_addrlen = (*current_host_node).ai_addrlen; + // allocate addr and copy data + let guest_sockaddr_ptr = { + let host_sockaddr_ptr = (*current_host_node).ai_addr; + let guest_sockaddr_ptr: WasmPtr = + call_malloc_with_cast(ctx, host_addrlen as _); + let guest_sockaddr = guest_sockaddr_ptr + .deref_mut(ctx.memory(0)) + .unwrap() + .get_mut(); + + guest_sockaddr.sa_family = (*host_sockaddr_ptr).sa_family as i16; + guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data.clone(); + guest_sockaddr_ptr + }; + + dbg!("Socketaddr allocated"); + + // allocate canon name on guest and copy data over + let guest_canonname_ptr = { + let str_ptr = (*current_host_node).ai_canonname; + if !str_ptr.is_null() { + let canonname_cstr = dbg!(std::ffi::CStr::from_ptr(str_ptr)); + let canonname_bytes = canonname_cstr.to_bytes_with_nul(); + let str_size = dbg!(canonname_bytes.len()); + let guest_canonname: WasmPtr = + call_malloc_with_cast(ctx, str_size as _); + + let guest_canonname_writer = guest_canonname + .deref(ctx.memory(0), 0, str_size as _) + .unwrap(); + for (i, b) in canonname_bytes.into_iter().enumerate() { + guest_canonname_writer[i].set(*b as i8) + } + + guest_canonname + } else { + WasmPtr::new(0) + } + }; + + dbg!("canonname allocated"); + + let mut current_guest_node = current_guest_node_ptr + .deref_mut(ctx.memory(0)) + .unwrap() + .get_mut(); + // TODO order these + current_guest_node.ai_flags = (*current_host_node).ai_flags; + current_guest_node.ai_family = (*current_host_node).ai_family; + current_guest_node.ai_socktype = (*current_host_node).ai_socktype; + current_guest_node.ai_protocol = (*current_host_node).ai_protocol; + current_guest_node.ai_addrlen = host_addrlen; + current_guest_node.ai_addr = guest_sockaddr_ptr; + current_guest_node.ai_canonname = guest_canonname_ptr; + current_guest_node.ai_next = WasmPtr::new(0); + + dbg!("Guest node updated"); + + previous_guest_node = Some(current_guest_node_ptr); + current_host_node = (*current_host_node).ai_next; + dbg!("End of loop bookkeeping finished"); + } + + dbg!("freeing memory"); + // this frees all connected nodes on the linked list + freeaddrinfo(out_ptr); + head_of_list.unwrap_or(WasmPtr::new(0)) + }; + + res_val_ptr + .deref(ctx.memory(0)) + .unwrap() + .set(dbg!(head_of_list)); + + 0 +} diff --git a/lib/emscripten/src/env/windows/mod.rs b/lib/emscripten/src/env/windows/mod.rs index f738eccbb..814f211ca 100644 --- a/lib/emscripten/src/env/windows/mod.rs +++ b/lib/emscripten/src/env/windows/mod.rs @@ -5,9 +5,9 @@ use std::ffi::CString; use std::mem; use std::os::raw::c_char; -use crate::env::call_malloc; +use crate::env::{call_malloc, EmAddrInfo}; use crate::utils::{copy_cstr_into_wasm, read_string_from_wasm}; -use wasmer_runtime_core::vm::Ctx; +use wasmer_runtime_core::{memory::ptr::WasmPtr, vm::Ctx}; extern "C" { #[link_name = "_putenv"] @@ -131,3 +131,19 @@ pub fn _sysconf(_ctx: &mut Ctx, name: c_int) -> c_long { // stub because sysconf is not valid on windows 0 } + +pub fn _gai_strerror(_ctx: &mut Ctx, _ecode: i32) -> i32 { + debug!("emscripten::_gai_strerror({}) - stub", _ecode); + -1 +} + +pub fn _getaddrinfo( + ctx: &mut Ctx, + node_ptr: WasmPtr, + service_str_ptr: WasmPtr, + hints_ptr: WasmPtr, + res_val_ptr: WasmPtr>, +) -> i32 { + debug!("emscripten::_getaddrinfo -- stub"); + -1 +} diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index e7b51a26a..944fcfa1d 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -887,7 +887,7 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject "_pthread_setspecific" => func!(crate::emscripten_target::_pthread_setspecific), "_pthread_sigmask" => func!(crate::emscripten_target::_pthread_sigmask), "___gxx_personality_v0" => func!(crate::emscripten_target::___gxx_personality_v0), - "_gai_strerror" => func!(crate::emscripten_target::_gai_strerror), + "_gai_strerror" => func!(crate::env::_gai_strerror), "_getdtablesize" => func!(crate::emscripten_target::_getdtablesize), "_gethostbyaddr" => func!(crate::emscripten_target::_gethostbyaddr), "_gethostbyname" => func!(crate::emscripten_target::_gethostbyname),