diff --git a/lib/emscripten/src/emscripten_target.rs b/lib/emscripten/src/emscripten_target.rs index 329136e1198..f12d681f990 100644 --- a/lib/emscripten/src/emscripten_target.rs +++ b/lib/emscripten/src/emscripten_target.rs @@ -135,7 +135,8 @@ pub fn _pthread_condattr_setclock(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 { } pub fn _pthread_create(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32, _d: i32) -> i32 { trace!("emscripten::_pthread_create"); - 0 + // 11 seems to mean "no" + 11 } pub fn _pthread_detach(_ctx: &mut Ctx, _a: i32) -> i32 { trace!("emscripten::_pthread_detach"); diff --git a/lib/emscripten/src/env/unix/mod.rs b/lib/emscripten/src/env/unix/mod.rs index 35c2b1852d8..cd7613ca294 100644 --- a/lib/emscripten/src/env/unix/mod.rs +++ b/lib/emscripten/src/env/unix/mod.rs @@ -220,10 +220,10 @@ pub fn _getaddrinfo( .deref(memory) .map(|m| m as *const Cell as *const c_char)) .unwrap_or(std::ptr::null()), - (service_str_ptr + service_str_ptr .deref(memory) - .map(|m| m as *const Cell as *const c_char)) - .unwrap_or(std::ptr::null()), + .map(|m| m as *const Cell as *const c_char) + .unwrap_or(std::ptr::null()), hints .as_ref() .map(|h| h as *const addrinfo) diff --git a/lib/emscripten/src/memory.rs b/lib/emscripten/src/memory.rs index 0f1cb1f19e6..e3ff2e4c866 100644 --- a/lib/emscripten/src/memory.rs +++ b/lib/emscripten/src/memory.rs @@ -21,9 +21,9 @@ pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u /// emscripten: _emscripten_get_heap_size pub fn _emscripten_get_heap_size(ctx: &mut Ctx) -> u32 { - debug!("emscripten::_emscripten_get_heap_size"); + trace!("emscripten::_emscripten_get_heap_size"); let result = ctx.memory(0).size().bytes().0 as u32; - debug!("=> {}", result); + trace!("=> {}", result); result } diff --git a/lib/emscripten/src/syscalls/mod.rs b/lib/emscripten/src/syscalls/mod.rs index 34ba9081893..084a9afdcbb 100644 --- a/lib/emscripten/src/syscalls/mod.rs +++ b/lib/emscripten/src/syscalls/mod.rs @@ -279,28 +279,38 @@ pub fn ___syscall75(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { // readlink pub fn ___syscall85(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { debug!("emscripten::___syscall85 (readlink)"); - let _path = varargs.get_str(ctx); + let pathname_addr = varargs.get_str(ctx); let buf = varargs.get_str(ctx); // let buf_addr: i32 = varargs.get(ctx); let buf_size: i32 = varargs.get(ctx); - let fd = 3; - let ret = unsafe { read(fd, buf as _, buf_size as _) as i32 }; + let real_path_owned = get_cstr_path(ctx, pathname_addr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + pathname_addr + }; + // let fd = 3; + // let ret = unsafe { read(fd, buf as _, buf_size as _) as i32 }; + // debug!( + // "=> buf: {}, buf_size: {}, return: {} ", + // unsafe { std::ffi::CStr::from_ptr(buf as _).to_str().unwrap() }, + // buf_size, + // ret + // ); + let ret = unsafe { libc::readlink(real_path, buf as _, buf_size as _) as i32 }; + if ret == -1 { + debug!("readlink failed"); + return ret; + } debug!( - "=> buf: {}, buf_size: {}, return: {} ", + "=> path: {}, buf: {}, buf_size: {}, return: {} ", + unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() }, unsafe { std::ffi::CStr::from_ptr(buf as _).to_str().unwrap() }, + // std::ffi::CStr::from_ptr(buf).to_str().unwrap(), + // buf, buf_size, ret ); - // let ret = unsafe { - // readlink(path, buf as _, buf_size as _) as i32 - // }; - // debug!("=> path: {}, buf: {}, buf_size: {}, return: {} ", - // unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }, - // unsafe { std::ffi::CStr::from_ptr(buf as _).to_str().unwrap() }, - // // std::ffi::CStr::from_ptr(buf).to_str().unwrap(), - // // buf, - // buf_size, - // ret); ret } @@ -531,11 +541,6 @@ pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { } } -pub fn ___syscall168(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { - debug!("emscripten::___syscall168 - stub"); - -1 -} - pub fn ___syscall191(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { let _resource: i32 = varargs.get(ctx); debug!( diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index 1c041c434ac..f4eca58be6b 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -72,14 +72,14 @@ use libc::{ F_GETFD, F_SETFD, SOL_SOCKET, - SO_REUSEADDR, TIOCGWINSZ, }; #[allow(unused_imports)] use std::ffi::CStr; -use wasmer_runtime_core::vm::Ctx; +use wasmer_runtime_core::{memory::ptr::WasmPtr, vm::Ctx}; +use crate::env::EmSockAddr; use crate::utils; #[allow(unused_imports)] use std::io::Error; @@ -101,9 +101,9 @@ use libc::{fallocate, fdatasync, ftruncate64, lstat, madvise, wait4}; // Another conditional constant for name resolution: Macos et iOS use // SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. // Other platforms do otherwise. -#[cfg(target_os = "darwin")] +#[cfg(target_os = "macos")] use libc::SO_NOSIGPIPE; -#[cfg(not(target_os = "darwin"))] +#[cfg(not(target_os = "macos"))] const SO_NOSIGPIPE: c_int = 0; /// open @@ -444,6 +444,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let call: u32 = varargs.get(ctx); let mut socket_varargs: VarArgs = varargs.get(ctx); + // migrating to EmSockAddr, port being separate here is nice, should update that too #[repr(C)] pub struct GuestSockaddrIn { pub sin_family: sa_family_t, // u16 @@ -458,13 +459,6 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in pub s_addr: in_addr_t, // u32 } - // debug!("GuestSockaddrIn = {}", size_of::()); - - pub struct LinuxSockAddr { - pub sa_family: u16, - pub sa_data: [c_char; 14], - } - match call { 1 => { debug!("socket: socket"); @@ -487,6 +481,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in unimplemented!("non blocking sockets"); } + // why is this here? type T = u32; let payload = 1 as *const T as _; unsafe { @@ -500,7 +495,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in }; debug!( - "=> domain: {} (AF_INET/2), type: {} (SOCK_STREAM/1), protocol: {} = fd: {}", + "=> domain: {}, type: {}, protocol: {} = fd: {}", domain, ty, protocol, fd ); fd as _ @@ -555,47 +550,75 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in 5 => { debug!("socket: accept"); // accept (socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int - let socket = socket_varargs.get(ctx); - let address_addr: u32 = socket_varargs.get(ctx); - let address_len: u32 = socket_varargs.get(ctx); - let address = emscripten_memory_pointer!(ctx.memory(0), address_addr) as *mut sockaddr; + let socket: i32 = socket_varargs.get(ctx); + let address: WasmPtr = socket_varargs.get(ctx); + let address_len: WasmPtr = socket_varargs.get(ctx); debug!( "=> socket: {}, address: {:?}, address_len: {}", - socket, address, address_len + socket, + address.deref(ctx.memory(0)).unwrap().get(), + address_len.deref(ctx.memory(0)).unwrap().get() ); let address_len_addr = - emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t; + unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() }; // let mut address_len_addr: socklen_t = 0; - let fd = unsafe { accept(socket, address, address_len_addr) }; + let (fd, host_address) = unsafe { + let mut host_address: sockaddr = std::mem::uninitialized(); + let fd = accept(socket, &mut host_address, address_len_addr); - unsafe { - let address_linux = - emscripten_memory_pointer!(ctx.memory(0), address_addr) as *mut LinuxSockAddr; - (*address_linux).sa_family = (*address).sa_family as u16; - (*address_linux).sa_data = (*address).sa_data; + (fd, host_address) }; + let address_addr = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() }; + + address_addr.sa_family = host_address.sa_family as _; + address_addr.sa_data = host_address.sa_data.clone(); + + // why is this here? // set_cloexec unsafe { ioctl(fd, FIOCLEX); }; - debug!("fd: {}", fd); + debug!( + "address: {:?}, len: {}, result fd = {}", + address_addr, address_len_addr, fd + ); fd as _ } 6 => { debug!("socket: getsockname"); // getsockname (socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int - let socket = socket_varargs.get(ctx); - let address: u32 = socket_varargs.get(ctx); - let address_len: u32 = socket_varargs.get(ctx); - let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr; + let socket: i32 = socket_varargs.get(ctx); + let address: WasmPtr = socket_varargs.get(ctx); + let address_len: WasmPtr = socket_varargs.get(ctx); let address_len_addr = - emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t; - unsafe { getsockname(socket, address, address_len_addr) } + unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() }; + + let (ret, sock_addr_host) = unsafe { + // read host data into new var + let mut address: sockaddr = std::mem::uninitialized(); + let ret = getsockname( + socket, + &mut address as *mut sockaddr, + address_len_addr as *mut u32, + ); + (ret, address) + }; + // translate from host data into emscripten data + let mut address_mut = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() }; + address_mut.sa_family = sock_addr_host.sa_family as _; + address_mut.sa_data = sock_addr_host.sa_data.clone(); + + debug!( + "=> socket: {}, address, {:?}, address_len: {}, result = {}", + socket, address_mut, address_len_addr, ret + ); + + ret } 7 => { debug!("socket: getpeername"); @@ -647,25 +670,23 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in } 14 => { debug!("socket: setsockopt"); - // NOTE: Emscripten seems to be passing the wrong values to this syscall - // level: Em passes 1 as SOL_SOCKET; SOL_SOCKET is 0xffff in BSD - // name: Em passes SO_ACCEPTCONN, but Nginx complains about REUSEADDR + // OSX and BSD have completely different values, be very careful here // https://github.com/openbsd/src/blob/master/sys/sys/socket.h#L156 // setsockopt (socket: c_int, level: c_int, name: c_int, value: *const c_void, option_len: socklen_t) -> c_int let socket = socket_varargs.get(ctx); let level: i32 = socket_varargs.get(ctx); - // SOL_SOCKET = 0xffff (BSD, OSX) let level = if level == 1 { SOL_SOCKET } else { level }; - let name: i32 = socket_varargs.get(ctx); - // SO_REUSEADDR = 0x4 (BSD, OSX) - let name = if name == 2 { SO_REUSEADDR } else { name }; + let untranslated_name: i32 = socket_varargs.get(ctx); let value: u32 = socket_varargs.get(ctx); - let option_len = socket_varargs.get(ctx); - let value_addr = emscripten_memory_pointer!(ctx.memory(0), value) as _; // Endian problem + let option_len: u32 = socket_varargs.get(ctx); + let value_addr = + emscripten_memory_pointer!(ctx.memory(0), value) as *const libc::c_void; + let name: i32 = translate_socket_name_flag(untranslated_name); + let ret = unsafe { setsockopt(socket, level, name, value_addr, option_len) }; - debug!("=> socketfd: {}, level: {}, name: {}, value_addr: {:?}, option_len: {} = status: {}", socket, level, name, value_addr, option_len, ret); + debug!("=> socketfd: {}, level: {}, name: {}, value_addr: {:?}, option_len: {} = status: {}", socket, level, untranslated_name, value_addr, option_len, ret); ret } 15 => { @@ -673,7 +694,9 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in // getsockopt (sockfd: c_int, level: c_int, optname: c_int, optval: *mut c_void, optlen: *mut socklen_t) -> c_int let socket = socket_varargs.get(ctx); let level: i32 = socket_varargs.get(ctx); - let name: i32 = socket_varargs.get(ctx); + let level = if level == 1 { SOL_SOCKET } else { level }; + let untranslated_name: i32 = socket_varargs.get(ctx); + let name: i32 = translate_socket_name_flag(untranslated_name); let value: u32 = socket_varargs.get(ctx); let option_len: u32 = socket_varargs.get(ctx); let value_addr = emscripten_memory_pointer!(ctx.memory(0), value) as _; @@ -706,6 +729,60 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in } } +/// OSX and BSD have completely different values, we must translate from emscripten's Linuxy +/// value into one that we can pass to native syscalls +fn translate_socket_name_flag(name: i32) -> i32 { + match name { + 2 => libc::SO_REUSEADDR, + 3 => libc::SO_TYPE, + 4 => libc::SO_ERROR, + 5 => libc::SO_DONTROUTE, + 6 => libc::SO_BROADCAST, + 7 => libc::SO_SNDBUF, + 8 => libc::SO_RCVBUF, + 9 => libc::SO_KEEPALIVE, + 10 => libc::SO_OOBINLINE, + 13 => libc::SO_LINGER, + 18 => libc::SO_RCVLOWAT, + 19 => libc::SO_SNDLOWAT, + 20 => libc::SO_RCVTIMEO, + 21 => libc::SO_SNDTIMEO, + // SO_DEBUG missing + 30 => libc::SO_ACCEPTCONN, + otherwise => otherwise, + } +} + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct EmPollFd { + pub fd: i32, + pub events: i16, + pub revents: i16, +} + +unsafe impl wasmer_runtime_core::types::ValueType for EmPollFd {} + +/// poll +pub fn ___syscall168(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { + debug!("emscripten::___syscall168(poll)"); + let fds: WasmPtr = varargs.get(ctx); + let nfds: u32 = varargs.get(ctx); + let timeout: i32 = varargs.get(ctx); + + let fds_mut = unsafe { fds.deref_mut(ctx.memory(0)).unwrap().get_mut() }; + + let ret = unsafe { + libc::poll( + fds_mut as *mut EmPollFd as *mut libc::pollfd, + nfds as _, + timeout, + ) + }; + + ret +} + // pread pub fn ___syscall180(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall180 (pread) {}", _which); @@ -885,11 +962,11 @@ pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { let dirp = emscripten_memory_pointer!(ctx.memory(0), dirp_addr) as *mut u8; - let mut opened_dirs = &mut get_emscripten_data(ctx).opened_dirs; + let opened_dirs = &mut get_emscripten_data(ctx).opened_dirs; // need to persist stream across calls? // let dir: *mut libc::DIR = unsafe { libc::fdopendir(fd) }; - let mut dir = &*opened_dirs + let dir = &*opened_dirs .entry(fd) .or_insert_with(|| unsafe { Box::new(libc::fdopendir(fd)) }); diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index 5551dd6e12b..8ae1c1d1ae1 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -255,6 +255,12 @@ pub fn ___syscall122(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i -1 } +/// poll +pub fn ___syscall168(_ctx: &mut Ctx, _which: i32, _varargs: VarArgs) -> i32 { + debug!("emscripten::___syscall168(poll) - stub"); + -1 +} + /// lstat64 pub fn ___syscall196(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall196 (lstat64) - stub"); diff --git a/lib/runtime-core/src/memory/ptr.rs b/lib/runtime-core/src/memory/ptr.rs index fd249b5e3a6..465474c1316 100644 --- a/lib/runtime-core/src/memory/ptr.rs +++ b/lib/runtime-core/src/memory/ptr.rs @@ -46,7 +46,9 @@ fn align_pointer(ptr: usize, align: usize) -> usize { impl WasmPtr { #[inline] pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell> { - if (self.offset as usize) + mem::size_of::() >= memory.size().bytes().0 { + if self.offset == 0 + || (self.offset as usize) + mem::size_of::() >= memory.size().bytes().0 + { return None; } unsafe { @@ -60,7 +62,9 @@ impl WasmPtr { #[inline] pub unsafe fn deref_mut<'a>(self, memory: &'a Memory) -> Option<&'a mut Cell> { - if (self.offset as usize) + mem::size_of::() >= memory.size().bytes().0 { + if self.offset == 0 + || (self.offset as usize) + mem::size_of::() >= memory.size().bytes().0 + { return None; } let cell_ptr = align_pointer( @@ -79,7 +83,9 @@ impl WasmPtr { let item_size = mem::size_of::() + (mem::size_of::() % mem::align_of::()); let slice_full_len = index as usize + length as usize; - if (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0 { + if self.offset == 0 + || (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0 + { return None; } @@ -106,7 +112,9 @@ impl WasmPtr { let item_size = mem::size_of::() + (mem::size_of::() % mem::align_of::()); let slice_full_len = index as usize + length as usize; - if (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0 { + if self.offset == 0 + || (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0 + { return None; }