mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-12 13:55:33 +00:00
Merge branch 'master' into fix/llvm-trap-windows
This commit is contained in:
commit
5f3df4dd7b
@ -9,6 +9,7 @@ Blocks of changes will separated by version increments.
|
||||
Special thanks to @YaronWittenstein @penberg for their contributions.
|
||||
|
||||
- [#636](https://github.com/wasmerio/wasmer/issues/636) Fix traps with LLVM backend in Windows
|
||||
- [#643](https://github.com/wasmerio/wasmer/issues/643) Implement `wasi::path_symlink` and improve WASI FS public api IO error reporting
|
||||
- [#608](https://github.com/wasmerio/wasmer/issues/608) Implement wasi syscalls `fd_allocate`, `fd_sync`, `fd_pread`, `path_link`, `path_filestat_set_times`; update WASI fs API in a WIP way; reduce coupling of WASI code to host filesystem; make debug messages from WASI more readable; improve rights-checking when calling syscalls; implement reference counting on inodes; misc bug fixes and improvements
|
||||
- [#616](https://github.com/wasmerio/wasmer/issues/616) Create the import object separately from instance instantiation in `runtime-c-api`
|
||||
- [#620](https://github.com/wasmerio/wasmer/issues/620) Replace one `throw()` with `noexcept` in llvm backend
|
||||
|
@ -33,7 +33,7 @@ use wasmer_runtime_core::{
|
||||
use wasmparser::Type as WpType;
|
||||
|
||||
pub struct CraneliftModuleCodeGenerator {
|
||||
isa: Box<isa::TargetIsa>,
|
||||
isa: Box<dyn isa::TargetIsa>,
|
||||
signatures: Option<Arc<Map<SigIndex, FuncSig>>>,
|
||||
pub clif_signatures: Map<SigIndex, ir::Signature>,
|
||||
function_signatures: Option<Arc<Map<FuncIndex, SigIndex>>>,
|
||||
|
@ -26,7 +26,7 @@ extern crate serde_derive;
|
||||
extern crate rayon;
|
||||
extern crate serde;
|
||||
|
||||
fn get_isa() -> Box<isa::TargetIsa> {
|
||||
fn get_isa() -> Box<dyn isa::TargetIsa> {
|
||||
let flags = {
|
||||
let mut builder = settings::builder();
|
||||
builder.set("opt_level", "best").unwrap();
|
||||
|
@ -88,7 +88,7 @@ impl FuncResolverBuilder {
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
isa: &isa::TargetIsa,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||
info: &ModuleInfo,
|
||||
) -> CompileResult<(Self, HandlerData)> {
|
||||
|
@ -66,7 +66,7 @@ impl Trampolines {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(isa: &isa::TargetIsa, module: &ModuleInfo) -> Self {
|
||||
pub fn new(isa: &dyn isa::TargetIsa, module: &ModuleInfo) -> Self {
|
||||
let func_index_iter = module
|
||||
.exports
|
||||
.values()
|
||||
|
@ -11,7 +11,6 @@ wasmparser = "0.35.1"
|
||||
smallvec = "0.6.10"
|
||||
goblin = "0.0.24"
|
||||
libc = "0.2.60"
|
||||
nix = "0.14.1"
|
||||
capstone = { version = "0.6.0", optional = true }
|
||||
|
||||
[dependencies.inkwell]
|
||||
@ -20,6 +19,9 @@ branch = "llvm8-0"
|
||||
default-features = false
|
||||
features = ["llvm8-0", "target-x86"]
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = "0.14.1"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3.7", features = ["memoryapi"] }
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
//! This file was mostly taken from the llvm-sys crate.
|
||||
//! (https://bitbucket.org/tari/llvm-sys.rs/src/21ab524ec4df1450035df895209c3f8fbeb8775f/build.rs?at=default&fileviewer=file-view-default)
|
||||
//! (https://bitbucket.org/tari/llvm-sys.rs/raw/94361c1083a88f439b9d24c59b2d2831517413d7/build.rs)
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
@ -10,23 +10,54 @@ use std::io::{self, ErrorKind};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
// Version of the llvm-sys crate that we (through inkwell) depend on.
|
||||
const LLVM_SYS_MAJOR_VERSION: &str = "80";
|
||||
const LLVM_SYS_MINOR_VERSION: &str = "0";
|
||||
|
||||
// Environment variables that can guide compilation
|
||||
//
|
||||
// When adding new ones, they should also be added to main() to force a
|
||||
// rebuild if they are changed.
|
||||
lazy_static! {
|
||||
|
||||
/// A single path to search for LLVM in (containing bin/llvm-config)
|
||||
static ref ENV_LLVM_PREFIX: String =
|
||||
format!("LLVM_SYS_{}_PREFIX", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If exactly "YES", ignore the version blacklist
|
||||
static ref ENV_IGNORE_BLACKLIST: String =
|
||||
format!("LLVM_SYS_{}_IGNORE_BLACKLIST", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If set, enforce precise correspondence between crate and binary versions.
|
||||
static ref ENV_STRICT_VERSIONING: String =
|
||||
format!("LLVM_SYS_{}_STRICT_VERSIONING", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If set, do not attempt to strip irrelevant options for llvm-config --cflags
|
||||
static ref ENV_NO_CLEAN_CXXFLAGS: String =
|
||||
format!("LLVM_SYS_{}_NO_CLEAN_CXXFLAGS", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If set and targeting MSVC, force the debug runtime library
|
||||
static ref ENV_USE_DEBUG_MSVCRT: String =
|
||||
format!("LLVM_SYS_{}_USE_DEBUG_MSVCRT", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If set, always link against libffi
|
||||
static ref ENV_FORCE_FFI: String =
|
||||
format!("LLVM_SYS_{}_FFI_WORKAROUND", LLVM_SYS_MAJOR_VERSION);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// LLVM version used by this version of the crate.
|
||||
static ref CRATE_VERSION: Version = {
|
||||
let crate_version = Version::parse(env!("CARGO_PKG_VERSION"))
|
||||
.expect("Crate version is somehow not valid semver");
|
||||
Version {
|
||||
major: crate_version.major / 10,
|
||||
minor: crate_version.major % 10,
|
||||
.. crate_version
|
||||
}
|
||||
Version::new(LLVM_SYS_MAJOR_VERSION.parse::<u64>().unwrap() / 10,
|
||||
LLVM_SYS_MINOR_VERSION.parse::<u64>().unwrap() % 10,
|
||||
0)
|
||||
};
|
||||
|
||||
static ref LLVM_CONFIG_BINARY_NAMES: Vec<String> = {
|
||||
vec![
|
||||
"llvm-config".into(),
|
||||
// format!("llvm-config-{}", CRATE_VERSION.major),
|
||||
// format!("llvm-config-{}.{}", CRATE_VERSION.major, CRATE_VERSION.minor),
|
||||
format!("llvm-config-{}", CRATE_VERSION.major),
|
||||
format!("llvm-config-{}.{}", CRATE_VERSION.major, CRATE_VERSION.minor),
|
||||
]
|
||||
};
|
||||
|
||||
@ -41,21 +72,7 @@ lazy_static! {
|
||||
|
||||
// Did the user give us a binary path to use? If yes, try
|
||||
// to use that and fail if it doesn't work.
|
||||
let binary_prefix_var = "LLVM_SYS_80_PREFIX";
|
||||
|
||||
let path = if let Some(path) = env::var_os(&binary_prefix_var) {
|
||||
Some(path.to_str().unwrap().to_owned())
|
||||
} else if let Ok(mut file) = std::fs::File::open(".llvmenv") {
|
||||
use std::io::Read;
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s).unwrap();
|
||||
s.truncate(s.len() - 4);
|
||||
Some(s)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(path) = path {
|
||||
if let Some(path) = env::var_os(&*ENV_LLVM_PREFIX) {
|
||||
for binary_name in LLVM_CONFIG_BINARY_NAMES.iter() {
|
||||
let mut pb: PathBuf = path.clone().into();
|
||||
pb.push("bin");
|
||||
@ -67,7 +84,7 @@ lazy_static! {
|
||||
return pb;
|
||||
} else {
|
||||
println!("LLVM binaries specified by {} are the wrong version.
|
||||
(Found {}, need {}.)", binary_prefix_var, ver, *CRATE_VERSION);
|
||||
(Found {}, need {}.)", *ENV_LLVM_PREFIX, ver, *CRATE_VERSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,7 +96,7 @@ lazy_static! {
|
||||
refer to the llvm-sys documentation for more information.
|
||||
|
||||
llvm-sys: https://crates.io/crates/llvm-sys
|
||||
llvmenv: https://crates.io/crates/llvmenv", binary_prefix_var);
|
||||
llvmenv: https://crates.io/crates/llvmenv", *ENV_LLVM_PREFIX);
|
||||
panic!("Could not find a compatible version of LLVM");
|
||||
};
|
||||
}
|
||||
@ -115,15 +132,55 @@ fn locate_system_llvm_config() -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Check whether the given version of LLVM is blacklisted,
|
||||
/// returning `Some(reason)` if it is.
|
||||
fn is_blacklisted_llvm(llvm_version: &Version) -> Option<&'static str> {
|
||||
static BLACKLIST: &'static [(u64, u64, u64, &'static str)] = &[];
|
||||
|
||||
if let Some(x) = env::var_os(&*ENV_IGNORE_BLACKLIST) {
|
||||
if &x == "YES" {
|
||||
println!(
|
||||
"cargo:warning=Ignoring blacklist entry for LLVM {}",
|
||||
llvm_version
|
||||
);
|
||||
return None;
|
||||
} else {
|
||||
println!(
|
||||
"cargo:warning={} is set but not exactly \"YES\"; blacklist is still honored.",
|
||||
*ENV_IGNORE_BLACKLIST
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for &(major, minor, patch, reason) in BLACKLIST.iter() {
|
||||
let bad_version = Version {
|
||||
major: major,
|
||||
minor: minor,
|
||||
patch: patch,
|
||||
pre: vec![],
|
||||
build: vec![],
|
||||
};
|
||||
|
||||
if &bad_version == llvm_version {
|
||||
return Some(reason);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Check whether the given LLVM version is compatible with this version of
|
||||
/// the crate.
|
||||
fn is_compatible_llvm(llvm_version: &Version) -> bool {
|
||||
let strict = env::var_os(format!(
|
||||
"LLVM_SYS_{}_STRICT_VERSIONING",
|
||||
env!("CARGO_PKG_VERSION_MAJOR")
|
||||
))
|
||||
.is_some()
|
||||
|| cfg!(feature = "strict-versioning");
|
||||
if let Some(reason) = is_blacklisted_llvm(llvm_version) {
|
||||
println!(
|
||||
"Found LLVM {}, which is blacklisted: {}",
|
||||
llvm_version, reason
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
let strict =
|
||||
env::var_os(&*ENV_STRICT_VERSIONING).is_some() || cfg!(feature = "strict-versioning");
|
||||
if strict {
|
||||
llvm_version.major == CRATE_VERSION.major && llvm_version.minor == CRATE_VERSION.minor
|
||||
} else {
|
||||
@ -184,11 +241,7 @@ fn get_llvm_cxxflags() -> String {
|
||||
// include flags that aren't understood by the default compiler we're
|
||||
// using. Unless requested otherwise, clean CFLAGS of options that are
|
||||
// known to be possibly-harmful.
|
||||
let no_clean = env::var_os(format!(
|
||||
"LLVM_SYS_{}_NO_CLEAN_CFLAGS",
|
||||
env!("CARGO_PKG_VERSION_MAJOR")
|
||||
))
|
||||
.is_some();
|
||||
let no_clean = env::var_os(&*ENV_NO_CLEAN_CXXFLAGS).is_some();
|
||||
if no_clean || cfg!(target_env = "msvc") {
|
||||
// MSVC doesn't accept -W... options, so don't try to strip them and
|
||||
// possibly strip something that should be retained. Also do nothing if
|
||||
@ -204,20 +257,43 @@ fn get_llvm_cxxflags() -> String {
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
fn is_llvm_debug() -> bool {
|
||||
// Has to be either Debug or Release
|
||||
llvm_config("--build-mode").contains("Debug")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rustc-link-lib=static=llvm-backend");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=cpp/object_loader.cpp");
|
||||
println!("cargo:rerun-if-changed=cpp/object_loader.hh");
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_LLVM_PREFIX);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_IGNORE_BLACKLIST);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_STRICT_VERSIONING);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_NO_CLEAN_CXXFLAGS);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_USE_DEBUG_MSVCRT);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_FORCE_FFI);
|
||||
|
||||
std::env::set_var("CXXFLAGS", get_llvm_cxxflags());
|
||||
cc::Build::new()
|
||||
.cpp(true)
|
||||
.file("cpp/object_loader.cpp")
|
||||
.compile("llvm-backend");
|
||||
|
||||
println!("cargo:rustc-link-lib=static=llvm-backend");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=cpp/object_loader.cpp");
|
||||
println!("cargo:rerun-if-changed=cpp/object_loader.hh");
|
||||
|
||||
// Enable "nightly" cfg if the current compiler is nightly.
|
||||
if rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly {
|
||||
println!("cargo:rustc-cfg=nightly");
|
||||
}
|
||||
|
||||
let use_debug_msvcrt = env::var_os(&*ENV_USE_DEBUG_MSVCRT).is_some();
|
||||
if cfg!(target_env = "msvc") && (use_debug_msvcrt || is_llvm_debug()) {
|
||||
println!("cargo:rustc-link-lib={}", "msvcrtd");
|
||||
}
|
||||
|
||||
// Link libffi if the user requested this workaround.
|
||||
// See https://bitbucket.org/tari/llvm-sys.rs/issues/12/
|
||||
let force_ffi = env::var_os(&*ENV_FORCE_FFI).is_some();
|
||||
if force_ffi {
|
||||
println!("cargo:rustc-link-lib=dylib={}", "ffi");
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ use libc::c_char;
|
||||
use std::{
|
||||
any::Any,
|
||||
ffi::{c_void, CString},
|
||||
fs::File,
|
||||
io::Write,
|
||||
mem,
|
||||
ops::Deref,
|
||||
ptr::{self, NonNull},
|
||||
@ -177,6 +179,14 @@ impl LLVMBackend {
|
||||
.unwrap();
|
||||
let mem_buf_slice = memory_buffer.as_slice();
|
||||
|
||||
if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.obj_file } {
|
||||
let mut file = File::create(path).unwrap();
|
||||
let mut pos = 0;
|
||||
while pos < mem_buf_slice.len() {
|
||||
pos += file.write(&mem_buf_slice[pos..]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let callbacks = get_callbacks();
|
||||
let mut module: *mut LLVMModule = ptr::null_mut();
|
||||
|
||||
|
@ -4639,6 +4639,10 @@ impl ModuleCodeGenerator<LLVMFunctionCodeGenerator, LLVMBackend, CodegenError>
|
||||
self.intrinsics.as_ref().unwrap(),
|
||||
);
|
||||
|
||||
if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.pre_opt_ir } {
|
||||
self.module.print_to_file(path).unwrap();
|
||||
}
|
||||
|
||||
let pass_manager = PassManager::create(());
|
||||
if cfg!(test) {
|
||||
pass_manager.add_verifier_pass();
|
||||
@ -4658,7 +4662,9 @@ impl ModuleCodeGenerator<LLVMFunctionCodeGenerator, LLVMBackend, CodegenError>
|
||||
pass_manager.add_slp_vectorize_pass();
|
||||
pass_manager.run_on(&self.module);
|
||||
|
||||
// self.module.print_to_stderr();
|
||||
if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.post_opt_ir } {
|
||||
self.module.print_to_file(path).unwrap();
|
||||
}
|
||||
|
||||
let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics.take().unwrap());
|
||||
Ok((backend, Box::new(cache_gen)))
|
||||
|
@ -16,6 +16,8 @@ mod state;
|
||||
mod structs;
|
||||
mod trampolines;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator;
|
||||
pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator;
|
||||
|
||||
@ -27,3 +29,22 @@ pub type LLVMCompiler = SimpleStreamingCompilerGen<
|
||||
backend::LLVMBackend,
|
||||
code::CodegenError,
|
||||
>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// LLVM backend flags.
|
||||
pub struct LLVMOptions {
|
||||
/// Emit LLVM IR before optimization pipeline.
|
||||
pub pre_opt_ir: Option<PathBuf>,
|
||||
|
||||
/// Emit LLVM IR after optimization pipeline.
|
||||
pub post_opt_ir: Option<PathBuf>,
|
||||
|
||||
/// Emit LLVM generated native code object file.
|
||||
pub obj_file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub static mut GLOBAL_OPTIONS: LLVMOptions = LLVMOptions {
|
||||
pre_opt_ir: None,
|
||||
post_opt_ir: None,
|
||||
obj_file: None,
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ use wasmparser::{self, WasmDecoder};
|
||||
use wasmparser::{Operator, Type as WpType};
|
||||
|
||||
pub type BreakpointHandler =
|
||||
Box<Fn(BreakpointInfo) -> Result<(), Box<dyn Any>> + Send + Sync + 'static>;
|
||||
Box<dyn Fn(BreakpointInfo) -> Result<(), Box<dyn Any>> + Send + Sync + 'static>;
|
||||
pub type BreakpointMap = Arc<HashMap<usize, BreakpointHandler>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -232,7 +232,7 @@ impl<'a, 'b> EventSink<'a, 'b> {
|
||||
}
|
||||
|
||||
pub struct MiddlewareChain {
|
||||
chain: Vec<Box<GenericFunctionMiddleware>>,
|
||||
chain: Vec<Box<dyn GenericFunctionMiddleware>>,
|
||||
}
|
||||
|
||||
impl MiddlewareChain {
|
||||
|
@ -35,7 +35,7 @@ type SetJmpBuffer = [i32; SETJMP_BUFFER_LEN];
|
||||
struct UnwindInfo {
|
||||
jmpbuf: SetJmpBuffer, // in
|
||||
breakpoints: Option<BreakpointMap>,
|
||||
payload: Option<Box<Any>>, // out
|
||||
payload: Option<Box<dyn Any>>, // out
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
@ -89,7 +89,7 @@ pub unsafe fn clear_wasm_interrupt() {
|
||||
pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
||||
f: F,
|
||||
breakpoints: Option<BreakpointMap>,
|
||||
) -> Result<R, Box<Any>> {
|
||||
) -> Result<R, Box<dyn Any>> {
|
||||
let unwind = UNWIND.with(|x| x.get());
|
||||
let old = (*unwind).take();
|
||||
*unwind = Some(UnwindInfo {
|
||||
@ -111,7 +111,7 @@ pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn begin_unsafe_unwind(e: Box<Any>) -> ! {
|
||||
pub unsafe fn begin_unsafe_unwind(e: Box<dyn Any>) -> ! {
|
||||
let unwind = UNWIND.with(|x| x.get());
|
||||
let inner = (*unwind)
|
||||
.as_mut()
|
||||
|
@ -46,7 +46,7 @@ impl IsExport for Export {
|
||||
/// ```
|
||||
pub struct ImportObject {
|
||||
map: Rc<RefCell<HashMap<String, Box<dyn LikeNamespace>>>>,
|
||||
pub(crate) state_creator: Option<Rc<Fn() -> (*mut c_void, fn(*mut c_void))>>,
|
||||
pub(crate) state_creator: Option<Rc<dyn Fn() -> (*mut c_void, fn(*mut c_void))>>,
|
||||
pub allow_missing_functions: bool,
|
||||
}
|
||||
|
||||
|
@ -763,7 +763,7 @@ mod vm_ctx_tests {
|
||||
x: u32,
|
||||
y: bool,
|
||||
str: String,
|
||||
finalizer: Box<FnMut()>,
|
||||
finalizer: Box<dyn FnMut()>,
|
||||
}
|
||||
|
||||
impl Drop for TestData {
|
||||
|
@ -148,7 +148,7 @@ pub struct X64FunctionCode {
|
||||
breakpoints: Option<
|
||||
HashMap<
|
||||
AssemblyOffset,
|
||||
Box<Fn(BreakpointInfo) -> Result<(), Box<dyn Any>> + Send + Sync + 'static>,
|
||||
Box<dyn Fn(BreakpointInfo) -> Result<(), Box<dyn Any>> + Send + Sync + 'static>,
|
||||
>,
|
||||
>,
|
||||
returns: SmallVec<[WpType; 1]>,
|
||||
@ -294,7 +294,7 @@ impl RunnableModule for X64ExecutionContext {
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn do_early_trap(&self, data: Box<Any>) -> ! {
|
||||
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> ! {
|
||||
protect_unix::TRAP_EARLY_DATA.with(|x| x.set(Some(data)));
|
||||
protect_unix::trigger_trap();
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ clif:skip:elem.wast:229 # Spec running forever
|
||||
clif:skip:names.wast:* # Names file has parsing error?
|
||||
clif:skip:simd.wast:* # SIMD not implemented
|
||||
clif:skip:simd_binaryen.wast:* # SIMD not implemented
|
||||
|
||||
clif:fail:binary-leb128.wast:74 # Module - caught panic Any
|
||||
clif:fail:binary-leb128.wast:86 # Module - caught panic Any
|
||||
clif:fail:binary-leb128.wast:98 # Module - caught panic Any
|
||||
@ -39,19 +40,11 @@ clif:fail:data.wast:137 # Module - caught panic Any
|
||||
clif:fail:data.wast:143 # Module - caught panic Any
|
||||
clif:fail:data.wast:149 # Module - caught panic Any
|
||||
clif:fail:data.wast:154 # Module - caught panic Any
|
||||
clif:fail:data.wast:162 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:170 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:178 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:186 # AssertUnlinkable - instantiate successful, expected unlinkable
|
||||
clif:fail:data.wast:194 # AssertUnlinkable - instantiate successful, expected unlinkable
|
||||
clif:fail:data.wast:211 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:220 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:227 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:235 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:243 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:251 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:258 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:266 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:273 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:elem.wast:101 # Module - caught panic Any
|
||||
clif:fail:elem.wast:143 # AssertUnlinkable - instantiate successful, expected unlinkable
|
||||
@ -162,20 +155,20 @@ clif:fail:linking.wast:81 # AssertReturn Get - Expected Global I32(241) got: I32
|
||||
clif:fail:linking.wast:83 # AssertReturn - result I32(142) ("0x8e") does not match expected I32(241) ("0xf1")
|
||||
clif:fail:linking.wast:87 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:linking.wast:91 # AssertUnlinkable - caught panic Any
|
||||
clif:fail:linking.wast:137 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106ea0062 - illegal instruction"
|
||||
clif:fail:linking.wast:139 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106ea0062 - illegal instruction"
|
||||
clif:fail:linking.wast:142 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106ea0062 - illegal instruction"
|
||||
clif:fail:linking.wast:144 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106ea0062 - illegal instruction"
|
||||
clif:fail:linking.wast:147 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106ea0037 - illegal instruction"
|
||||
clif:fail:linking.wast:149 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106ea0037 - illegal instruction"
|
||||
clif:fail:linking.wast:137 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x109d44062 - illegal instruction"
|
||||
clif:fail:linking.wast:139 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x109d44062 - illegal instruction"
|
||||
clif:fail:linking.wast:142 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x109d44062 - illegal instruction"
|
||||
clif:fail:linking.wast:144 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x109d44062 - illegal instruction"
|
||||
clif:fail:linking.wast:147 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x109d44037 - illegal instruction"
|
||||
clif:fail:linking.wast:149 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x109d44037 - illegal instruction"
|
||||
clif:fail:linking.wast:172 # AssertReturn - result I32(4) ("0x4") does not match expected I32(-4) ("0xfffffffc")
|
||||
clif:fail:linking.wast:173 # AssertReturn - result I32(4) ("0x4") does not match expected I32(-4) ("0xfffffffc")
|
||||
clif:fail:linking.wast:175 # AssertReturn - result I32(4) ("0x4") does not match expected I32(-4) ("0xfffffffc")
|
||||
clif:fail:linking.wast:178 # AssertReturn - Call failed RuntimeError: WebAssembly trap occurred during runtime: `call_indirect` out-of-bounds
|
||||
clif:fail:linking.wast:179 # AssertReturn - Call failed RuntimeError: "unknown trap at 0x106ea0062 - illegal instruction"
|
||||
clif:fail:linking.wast:181 # AssertReturn - Call failed RuntimeError: "unknown trap at 0x106ea0062 - illegal instruction"
|
||||
clif:fail:linking.wast:185 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106ea0062 - illegal instruction"
|
||||
clif:fail:linking.wast:187 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106ea0062 - illegal instruction"
|
||||
clif:fail:linking.wast:179 # AssertReturn - Call failed RuntimeError: "unknown trap at 0x109d44062 - illegal instruction"
|
||||
clif:fail:linking.wast:181 # AssertReturn - Call failed RuntimeError: "unknown trap at 0x109d44062 - illegal instruction"
|
||||
clif:fail:linking.wast:185 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x109d44062 - illegal instruction"
|
||||
clif:fail:linking.wast:187 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x109d44062 - illegal instruction"
|
||||
clif:fail:linking.wast:200 # Module - caught panic Any
|
||||
clif:fail:linking.wast:204 # AssertReturn Get - No instance available Some("$G2")
|
||||
clif:fail:linking.wast:288 # AssertReturn - result I32(2) ("0x2") does not match expected I32(167) ("0xa7")
|
||||
@ -382,6 +375,14 @@ clif:fail:memory.wast:5:windows # Module - caught panic Any
|
||||
clif:fail:memory.wast:6:windows # Module - caught panic Any
|
||||
clif:fail:stack.wast:137:windows # Module - caught panic Any
|
||||
clif:fail:type.wast:3:windows # Module - caught panic Any
|
||||
clif:fail:data.wast:162:windows # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:170:windows # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:178:windows # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:220:windows # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:235:windows # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:243:windows # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:251:windows # AssertUnlinkable - caught panic Any
|
||||
clif:fail:data.wast:266:windows # AssertUnlinkable - caught panic Any
|
||||
|
||||
# LLVM bug with min/max over NaNs
|
||||
llvm:skip:f32.wast:1651
|
||||
@ -966,19 +967,11 @@ llvm:fail:data.wast:137 # Module - caught panic Any
|
||||
llvm:fail:data.wast:143 # Module - caught panic Any
|
||||
llvm:fail:data.wast:149 # Module - caught panic Any
|
||||
llvm:fail:data.wast:154 # Module - caught panic Any
|
||||
llvm:fail:data.wast:162 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:170 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:178 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:186 # AssertUnlinkable - instantiate successful, expected unlinkable
|
||||
llvm:fail:data.wast:194 # AssertUnlinkable - instantiate successful, expected unlinkable
|
||||
llvm:fail:data.wast:211 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:220 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:227 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:235 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:243 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:251 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:258 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:266 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:data.wast:273 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:elem.wast:101 # Module - caught panic Any
|
||||
llvm:fail:elem.wast:143 # AssertUnlinkable - instantiate successful, expected unlinkable
|
||||
@ -995,10 +988,10 @@ llvm:fail:elem.wast:380 # AssertReturn - result I32(65) ("0x41") does not match
|
||||
llvm:fail:elem.wast:381 # AssertReturn - result I32(66) ("0x42") does not match expected I32(70) ("0x46")
|
||||
llvm:fail:globals.wast:243 # AssertInvalid - caught panic Any
|
||||
llvm:fail:globals.wast:301 # Module - caught panic Any
|
||||
llvm:fail:i32.wast:243 # AssertReturn - result I32(286499151) ("0x1113a14f") does not match expected I32(32) ("0x20")
|
||||
llvm:fail:i32.wast:252 # AssertReturn - result I32(286499168) ("0x1113a160") does not match expected I32(32) ("0x20")
|
||||
llvm:fail:i64.wast:243 # AssertReturn - result I64(4581466607) ("0x11113a1ef") does not match expected I64(64) ("0x40")
|
||||
llvm:fail:i64.wast:252 # AssertReturn - result I64(4581466592) ("0x11113a1e0") does not match expected I64(64) ("0x40")
|
||||
llvm:fail:i32.wast:243 # AssertReturn - result I32(79069519) ("0x4b6814f") does not match expected I32(32) ("0x20")
|
||||
llvm:fail:i32.wast:252 # AssertReturn - result I32(79069536) ("0x4b68160") does not match expected I32(32) ("0x20")
|
||||
llvm:fail:i64.wast:243 # AssertReturn - result I64(4374036975) ("0x104b681ef") does not match expected I64(64) ("0x40")
|
||||
llvm:fail:i64.wast:252 # AssertReturn - result I64(4374036960) ("0x104b681e0") does not match expected I64(64) ("0x40")
|
||||
llvm:fail:imports.wast:98 # Module - caught panic Any
|
||||
llvm:fail:imports.wast:99 # Module - caught panic Any
|
||||
llvm:fail:imports.wast:100 # Module - caught panic Any
|
||||
@ -1122,7 +1115,7 @@ llvm:fail:linking.wast:324 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:linking.wast:335 # AssertUnlinkable - caught panic Any
|
||||
llvm:fail:linking.wast:387 # AssertReturn - result I32(0) ("0x0") does not match expected I32(104) ("0x68")
|
||||
llvm:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: WebAssembly trap occurred during runtime: incorrect `call_indirect` signature
|
||||
llvm:fail:load.wast:201 # AssertReturn - result I32(290889759) ("0x1156a01f") does not match expected I32(32) ("0x20")
|
||||
llvm:fail:load.wast:201 # AssertReturn - result I32(80568351) ("0x4cd601f") does not match expected I32(32) ("0x20")
|
||||
llvm:fail:start.wast:92 # Module - caught panic Any
|
||||
llvm:fail:type.wast:3 # Module - caught panic Any
|
||||
|
||||
@ -1149,25 +1142,25 @@ singlepass:fail:address.wast:202 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:203 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:204 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:479 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:481 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:482 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:483 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:484 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:485 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:486 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:487 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:481 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:482 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:483 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:484 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:485 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:486 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:487 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:489 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:490 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:491 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:492 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:493 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:494 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:493 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:494 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:495 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:539 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:541 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:542 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:586 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:588 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:address.wast:588 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:address.wast:589 # AssertTrap - expected trap, got []
|
||||
singlepass:fail:align.wast:864 # AssertTrap - expected trap, got Runtime:Error unknown error
|
||||
singlepass:fail:binary-leb128.wast:2 # Module - caught panic Any
|
||||
|
@ -16,6 +16,7 @@ mod fseek;
|
||||
mod hello;
|
||||
mod mapdir;
|
||||
mod path_link;
|
||||
mod path_symlink;
|
||||
mod quine;
|
||||
mod readlink;
|
||||
mod wasi_sees_virtual_root;
|
||||
|
20
lib/wasi-tests/tests/wasitests/path_symlink.rs
Normal file
20
lib/wasi-tests/tests/wasitests/path_symlink.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#[test]
|
||||
fn test_path_symlink() {
|
||||
assert_wasi_output!(
|
||||
"../../wasitests/path_symlink.wasm",
|
||||
"path_symlink",
|
||||
vec![],
|
||||
vec![
|
||||
(
|
||||
"temp".to_string(),
|
||||
::std::path::PathBuf::from("wasitests/test_fs/temp")
|
||||
),
|
||||
(
|
||||
"hamlet".to_string(),
|
||||
::std::path::PathBuf::from("wasitests/test_fs/hamlet")
|
||||
),
|
||||
],
|
||||
vec![],
|
||||
"../../wasitests/path_symlink.out"
|
||||
);
|
||||
}
|
4
lib/wasi-tests/wasitests/path_symlink.out
Normal file
4
lib/wasi-tests/wasitests/path_symlink.out
Normal file
@ -0,0 +1,4 @@
|
||||
ACT III
|
||||
SCENE I. A room in the castle.
|
||||
|
||||
Enter KING CLAUDIUS,
|
30
lib/wasi-tests/wasitests/path_symlink.rs
Normal file
30
lib/wasi-tests/wasitests/path_symlink.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Args:
|
||||
// mapdir: temp:wasitests/test_fs/temp
|
||||
// mapdir: hamlet:wasitests/test_fs/hamlet
|
||||
|
||||
use std::fs;
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
let mut base = PathBuf::from("wasitests/test_fs");
|
||||
#[cfg(target_os = "wasi")]
|
||||
let mut base = PathBuf::from("/");
|
||||
|
||||
let symlink_loc = base.join("temp/act3");
|
||||
let symlink_target = "../hamlet/act3";
|
||||
let scene1 = symlink_loc.join("scene1.txt");
|
||||
|
||||
std::fs::soft_link(&symlink_target, &symlink_loc);
|
||||
|
||||
let mut file = fs::File::open(&scene1).expect("Could not open file");
|
||||
|
||||
let mut buffer = [0u8; 64];
|
||||
|
||||
assert_eq!(file.read(&mut buffer).unwrap(), 64);
|
||||
let str_val = std::str::from_utf8(&buffer[..]).unwrap();
|
||||
println!("{}", str_val);
|
||||
|
||||
std::fs::remove_file(symlink_loc).unwrap();
|
||||
}
|
BIN
lib/wasi-tests/wasitests/path_symlink.wasm
Executable file
BIN
lib/wasi-tests/wasitests/path_symlink.wasm
Executable file
Binary file not shown.
@ -393,8 +393,11 @@ impl WasiFs {
|
||||
let path: &Path = Path::new(path);
|
||||
|
||||
let mut cur_inode = base_dir.inode;
|
||||
let n_components = path.components().count();
|
||||
// TODO: rights checks
|
||||
'path_iter: for component in path.components() {
|
||||
'path_iter: for (i, component) in path.components().enumerate() {
|
||||
// used to terminate symlink resolution properly
|
||||
let last_component = i + 1 == n_components;
|
||||
// for each component traverse file structure
|
||||
// loading inodes as necessary
|
||||
'symlink_resolution: while symlink_count < MAX_SYMLINKS {
|
||||
@ -430,7 +433,6 @@ impl WasiFs {
|
||||
cd.push(component);
|
||||
cd
|
||||
};
|
||||
// TODO: verify this returns successfully when given a non-symlink
|
||||
let metadata = file.symlink_metadata().ok().ok_or(__WASI_EINVAL)?;
|
||||
let file_type = metadata.file_type();
|
||||
// we want to insert newly opened dirs and files, but not transient symlinks
|
||||
@ -488,6 +490,7 @@ impl WasiFs {
|
||||
cur_inode = new_inode;
|
||||
|
||||
if loop_for_symlink && follow_symlinks {
|
||||
debug!("Following symlink to {:?}", cur_inode);
|
||||
continue 'symlink_resolution;
|
||||
}
|
||||
}
|
||||
@ -530,6 +533,7 @@ impl WasiFs {
|
||||
base.push(relative_path);
|
||||
base.to_string_lossy().to_string()
|
||||
};
|
||||
debug!("Following symlink recursively");
|
||||
let symlink_inode = self.get_inode_at_path_inner(
|
||||
new_base_dir,
|
||||
&new_path,
|
||||
@ -537,7 +541,15 @@ impl WasiFs {
|
||||
follow_symlinks,
|
||||
)?;
|
||||
cur_inode = symlink_inode;
|
||||
//continue 'symlink_resolution;
|
||||
// if we're at the very end and we found a file, then we're done
|
||||
// TODO: figure out if this should also happen for directories?
|
||||
if let Kind::File { .. } = &self.inodes[cur_inode].kind {
|
||||
// check if on last step
|
||||
if last_component {
|
||||
break 'symlink_resolution;
|
||||
}
|
||||
}
|
||||
continue 'symlink_resolution;
|
||||
}
|
||||
}
|
||||
break 'symlink_resolution;
|
||||
@ -571,6 +583,64 @@ impl WasiFs {
|
||||
Err(__WASI_EINVAL) // this may not make sense
|
||||
}
|
||||
|
||||
// if this is still dead code and the year is 2020 or later, please delete this function
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn path_relative_to_fd(
|
||||
&self,
|
||||
fd: __wasi_fd_t,
|
||||
inode: Inode,
|
||||
) -> Result<PathBuf, __wasi_errno_t> {
|
||||
let mut stack = vec![];
|
||||
let base_fd = self.get_fd(fd)?;
|
||||
let base_inode = base_fd.inode;
|
||||
let mut cur_inode = inode;
|
||||
|
||||
while cur_inode != base_inode {
|
||||
stack.push(self.inodes[cur_inode].name.clone());
|
||||
match &self.inodes[cur_inode].kind {
|
||||
Kind::Dir { parent, .. } => {
|
||||
if let Some(p) = parent {
|
||||
cur_inode = *p;
|
||||
}
|
||||
}
|
||||
_ => return Err(__WASI_EINVAL),
|
||||
}
|
||||
}
|
||||
|
||||
let mut out = PathBuf::new();
|
||||
for p in stack.iter().rev() {
|
||||
out.push(p);
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// finds the number of directories between the fd and the inode if they're connected
|
||||
/// expects inode to point to a directory
|
||||
pub(crate) fn path_depth_from_fd(
|
||||
&self,
|
||||
fd: __wasi_fd_t,
|
||||
inode: Inode,
|
||||
) -> Result<usize, __wasi_errno_t> {
|
||||
let mut counter = 0;
|
||||
let base_fd = self.get_fd(fd)?;
|
||||
let base_inode = base_fd.inode;
|
||||
let mut cur_inode = inode;
|
||||
|
||||
while cur_inode != base_inode {
|
||||
counter += 1;
|
||||
match &self.inodes[cur_inode].kind {
|
||||
Kind::Dir { parent, .. } => {
|
||||
if let Some(p) = parent {
|
||||
cur_inode = *p;
|
||||
}
|
||||
}
|
||||
_ => return Err(__WASI_EINVAL),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(counter)
|
||||
}
|
||||
|
||||
/// gets a host file from a base directory and a path
|
||||
/// this function ensures the fs remains sandboxed
|
||||
// NOTE: follow symlinks is super weird right now
|
||||
@ -704,6 +774,24 @@ impl WasiFs {
|
||||
}))
|
||||
}
|
||||
|
||||
/// creates an inode and inserts it given a Kind, does not assume the file exists to
|
||||
pub fn create_inode_with_default_stat(
|
||||
&mut self,
|
||||
kind: Kind,
|
||||
is_preopened: bool,
|
||||
name: String,
|
||||
) -> Inode {
|
||||
let mut stat = __wasi_filestat_t::default();
|
||||
stat.st_ino = self.get_next_inode_index();
|
||||
|
||||
self.inodes.insert(InodeVal {
|
||||
stat,
|
||||
is_preopened,
|
||||
name,
|
||||
kind,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_fd(
|
||||
&mut self,
|
||||
rights: __wasi_rights_t,
|
||||
|
@ -8,7 +8,7 @@ use std::{
|
||||
};
|
||||
|
||||
/// Error type for external users
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[allow(dead_code)]
|
||||
// dead code beacuse this is for external use
|
||||
pub enum WasiFsError {
|
||||
@ -23,6 +23,38 @@ pub enum WasiFsError {
|
||||
/// Something failed when doing IO. These errors can generally not be handled.
|
||||
/// It may work if tried again.
|
||||
IOError,
|
||||
/// The address was in use
|
||||
AddressInUse,
|
||||
/// The address could not be found
|
||||
AddressNotAvailable,
|
||||
/// A pipe was closed
|
||||
BrokenPipe,
|
||||
/// The connection was aborted
|
||||
ConnectionAborted,
|
||||
/// The connection request was refused
|
||||
ConnectionRefused,
|
||||
/// The connection was reset
|
||||
ConnectionReset,
|
||||
/// The operation was interrupted before it could finish
|
||||
Interrupted,
|
||||
/// Invalid internal data, if the argument data is invalid, use `InvalidInput`
|
||||
InvalidData,
|
||||
/// The provided data is invalid
|
||||
InvalidInput,
|
||||
/// Could not perform the operation because there was not an open connection
|
||||
NotConnected,
|
||||
/// The requested file or directory could not be found
|
||||
EntityNotFound,
|
||||
/// Caller was not allowed to perform this operation
|
||||
PermissionDenied,
|
||||
/// The operation did not complete within the given amount of time
|
||||
TimedOut,
|
||||
/// Found EOF when EOF was not expected
|
||||
UnexpectedEof,
|
||||
/// Operation would block, this error lets the caller know that they can try again
|
||||
WouldBlock,
|
||||
/// A call to write returned 0
|
||||
WriteZero,
|
||||
/// A WASI error without an external name. If you encounter this it means
|
||||
/// that there's probably a bug on our side (maybe as simple as forgetting to wrap
|
||||
/// this error, but perhaps something broke)
|
||||
@ -35,9 +67,51 @@ impl WasiFsError {
|
||||
__WASI_EBADF => WasiFsError::InvalidFd,
|
||||
__WASI_EEXIST => WasiFsError::AlreadyExists,
|
||||
__WASI_EIO => WasiFsError::IOError,
|
||||
__WASI_EADDRINUSE => WasiFsError::AddressInUse,
|
||||
__WASI_EADDRNOTAVAIL => WasiFsError::AddressNotAvailable,
|
||||
__WASI_EPIPE => WasiFsError::BrokenPipe,
|
||||
__WASI_ECONNABORTED => WasiFsError::ConnectionAborted,
|
||||
__WASI_ECONNREFUSED => WasiFsError::ConnectionRefused,
|
||||
__WASI_ECONNRESET => WasiFsError::ConnectionReset,
|
||||
__WASI_EINTR => WasiFsError::Interrupted,
|
||||
__WASI_EINVAL => WasiFsError::InvalidInput,
|
||||
__WASI_ENOTCONN => WasiFsError::NotConnected,
|
||||
__WASI_ENOENT => WasiFsError::EntityNotFound,
|
||||
__WASI_EPERM => WasiFsError::PermissionDenied,
|
||||
__WASI_ETIMEDOUT => WasiFsError::TimedOut,
|
||||
__WASI_EPROTO => WasiFsError::UnexpectedEof,
|
||||
__WASI_EAGAIN => WasiFsError::WouldBlock,
|
||||
__WASI_ENOSPC => WasiFsError::WriteZero,
|
||||
_ => WasiFsError::UnknownError(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_wasi_err(self) -> __wasi_errno_t {
|
||||
match self {
|
||||
WasiFsError::AlreadyExists => __WASI_EEXIST,
|
||||
WasiFsError::AddressInUse => __WASI_EADDRINUSE,
|
||||
WasiFsError::AddressNotAvailable => __WASI_EADDRNOTAVAIL,
|
||||
WasiFsError::BaseNotDirectory => __WASI_ENOTDIR,
|
||||
WasiFsError::BrokenPipe => __WASI_EPIPE,
|
||||
WasiFsError::ConnectionAborted => __WASI_ECONNABORTED,
|
||||
WasiFsError::ConnectionRefused => __WASI_ECONNREFUSED,
|
||||
WasiFsError::ConnectionReset => __WASI_ECONNRESET,
|
||||
WasiFsError::Interrupted => __WASI_EINTR,
|
||||
WasiFsError::InvalidData => __WASI_EIO,
|
||||
WasiFsError::InvalidFd => __WASI_EBADF,
|
||||
WasiFsError::InvalidInput => __WASI_EINVAL,
|
||||
WasiFsError::IOError => __WASI_EIO,
|
||||
WasiFsError::NotAFile => __WASI_EINVAL,
|
||||
WasiFsError::NotConnected => __WASI_ENOTCONN,
|
||||
WasiFsError::EntityNotFound => __WASI_ENOENT,
|
||||
WasiFsError::PermissionDenied => __WASI_EPERM,
|
||||
WasiFsError::TimedOut => __WASI_ETIMEDOUT,
|
||||
WasiFsError::UnexpectedEof => __WASI_EPROTO,
|
||||
WasiFsError::WouldBlock => __WASI_EAGAIN,
|
||||
WasiFsError::WriteZero => __WASI_ENOSPC,
|
||||
WasiFsError::UnknownError(ec) => ec,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait relies on your file closing when it goes out of scope via `Drop`
|
||||
@ -68,20 +142,20 @@ pub trait WasiFile: std::fmt::Debug + Write + Read + Seek {
|
||||
/// Change the size of the file, if the `new_size` is greater than the current size
|
||||
/// the extra bytes will be allocated and zeroed
|
||||
// TODO: stablize this in 0.7.0 by removing default impl
|
||||
fn set_len(&mut self, _new_size: __wasi_filesize_t) -> Option<()> {
|
||||
fn set_len(&mut self, _new_size: __wasi_filesize_t) -> Result<(), WasiFsError> {
|
||||
panic!("Default implementation for compatibilty in the 0.6.X releases; this will be removed in 0.7.0. Please implement WasiFile::allocate for your type before then");
|
||||
}
|
||||
|
||||
/// Request deletion of the file
|
||||
// TODO: break this out into a WasiPath trait which is dynamically in Kind::File
|
||||
// this change can't be done until before release
|
||||
fn unlink(&mut self) -> Option<()> {
|
||||
fn unlink(&mut self) -> Result<(), WasiFsError> {
|
||||
panic!("Default implementation for compatibilty in the 0.6.X releases; this will be removed in 0.7.0. Please implement WasiFile::unlink for your type before then");
|
||||
}
|
||||
|
||||
/// Store file contents and metadata to disk
|
||||
// TODO: stablize this in 0.7.0 by removing default impl
|
||||
fn sync_to_disk(&self) -> Option<()> {
|
||||
fn sync_to_disk(&self) -> Result<(), WasiFsError> {
|
||||
panic!("Default implementation for compatibilty in the 0.6.X releases; this will be removed in 0.7.0. Please implement WasiFile::sync_to_disk for your type before then");
|
||||
}
|
||||
}
|
||||
@ -187,15 +261,42 @@ impl WasiFile for HostFile {
|
||||
self.metadata().len()
|
||||
}
|
||||
|
||||
fn set_len(&mut self, new_size: __wasi_filesize_t) -> Option<()> {
|
||||
fs::File::set_len(&self.inner, new_size).ok()
|
||||
fn set_len(&mut self, new_size: __wasi_filesize_t) -> Result<(), WasiFsError> {
|
||||
fs::File::set_len(&self.inner, new_size).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn unlink(&mut self) -> Option<()> {
|
||||
std::fs::remove_file(&self.host_path).ok()
|
||||
fn unlink(&mut self) -> Result<(), WasiFsError> {
|
||||
std::fs::remove_file(&self.host_path).map_err(Into::into)
|
||||
}
|
||||
fn sync_to_disk(&self) -> Option<()> {
|
||||
self.inner.sync_all().ok()
|
||||
fn sync_to_disk(&self) -> Result<(), WasiFsError> {
|
||||
self.inner.sync_all().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for WasiFsError {
|
||||
fn from(io_error: io::Error) -> Self {
|
||||
match io_error.kind() {
|
||||
io::ErrorKind::AddrInUse => WasiFsError::AddressInUse,
|
||||
io::ErrorKind::AddrNotAvailable => WasiFsError::AddressNotAvailable,
|
||||
io::ErrorKind::AlreadyExists => WasiFsError::AlreadyExists,
|
||||
io::ErrorKind::BrokenPipe => WasiFsError::BrokenPipe,
|
||||
io::ErrorKind::ConnectionAborted => WasiFsError::ConnectionAborted,
|
||||
io::ErrorKind::ConnectionRefused => WasiFsError::ConnectionRefused,
|
||||
io::ErrorKind::ConnectionReset => WasiFsError::ConnectionReset,
|
||||
io::ErrorKind::Interrupted => WasiFsError::Interrupted,
|
||||
io::ErrorKind::InvalidData => WasiFsError::InvalidData,
|
||||
io::ErrorKind::InvalidInput => WasiFsError::InvalidInput,
|
||||
io::ErrorKind::NotConnected => WasiFsError::NotConnected,
|
||||
io::ErrorKind::NotFound => WasiFsError::EntityNotFound,
|
||||
io::ErrorKind::PermissionDenied => WasiFsError::PermissionDenied,
|
||||
io::ErrorKind::TimedOut => WasiFsError::TimedOut,
|
||||
io::ErrorKind::UnexpectedEof => WasiFsError::UnexpectedEof,
|
||||
io::ErrorKind::WouldBlock => WasiFsError::WouldBlock,
|
||||
io::ErrorKind::WriteZero => WasiFsError::WriteZero,
|
||||
io::ErrorKind::Other => WasiFsError::IOError,
|
||||
// if the following triggers, a new error type was added to this non-exhaustive enum
|
||||
_ => WasiFsError::UnknownError(__WASI_EIO),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
ptr::{Array, WasmPtr},
|
||||
state::{
|
||||
self, host_file_type_to_wasi_file_type, Fd, HostFile, Inode, InodeVal, Kind, WasiFile,
|
||||
WasiState, MAX_SYMLINKS,
|
||||
WasiFsError, WasiState, MAX_SYMLINKS,
|
||||
},
|
||||
ExitCode,
|
||||
};
|
||||
@ -338,7 +338,7 @@ pub fn fd_allocate(
|
||||
match &mut state.fs.inodes[inode].kind {
|
||||
Kind::File { handle, .. } => {
|
||||
if let Some(handle) = handle {
|
||||
wasi_try!(handle.set_len(new_size), __WASI_EIO);
|
||||
wasi_try!(handle.set_len(new_size).map_err(WasiFsError::into_wasi_err));
|
||||
} else {
|
||||
return __WASI_EBADF;
|
||||
}
|
||||
@ -549,7 +549,7 @@ pub fn fd_filestat_set_size(
|
||||
match &mut state.fs.inodes[inode].kind {
|
||||
Kind::File { handle, .. } => {
|
||||
if let Some(handle) = handle {
|
||||
wasi_try!(handle.set_len(st_size), __WASI_EIO);
|
||||
wasi_try!(handle.set_len(st_size).map_err(WasiFsError::into_wasi_err));
|
||||
} else {
|
||||
return __WASI_EBADF;
|
||||
}
|
||||
@ -1159,7 +1159,7 @@ pub fn fd_sync(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t {
|
||||
match &mut state.fs.inodes[inode].kind {
|
||||
Kind::File { handle, .. } => {
|
||||
if let Some(h) = handle {
|
||||
wasi_try!(h.sync_to_disk(), __WASI_EIO);
|
||||
wasi_try!(h.sync_to_disk().map_err(WasiFsError::into_wasi_err));
|
||||
} else {
|
||||
return __WASI_EINVAL;
|
||||
}
|
||||
@ -1679,6 +1679,10 @@ pub fn path_open(
|
||||
dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0,
|
||||
);
|
||||
|
||||
if let Ok(m) = maybe_inode {
|
||||
dbg!(&state.fs.inodes[m]);
|
||||
}
|
||||
|
||||
// TODO: traverse rights of dirs properly
|
||||
// COMMENTED OUT: WASI isn't giving appropriate rights here when opening
|
||||
// TODO: look into this; file a bug report if this is a bug
|
||||
@ -1935,6 +1939,20 @@ pub fn path_rename(
|
||||
debug!("wasi::path_rename");
|
||||
unimplemented!("wasi::path_rename")
|
||||
}
|
||||
|
||||
/// ### `path_symlink()`
|
||||
/// Create a symlink
|
||||
/// Inputs:
|
||||
/// - `const char *old_path`
|
||||
/// Array of UTF-8 bytes representing the source path
|
||||
/// - `u32 old_path_len`
|
||||
/// The number of bytes to read from `old_path`
|
||||
/// - `__wasi_fd_t fd`
|
||||
/// The base directory from which the paths are understood
|
||||
/// - `const char *new_path`
|
||||
/// Array of UTF-8 bytes representing the target path
|
||||
/// - `u32 new_path_len`
|
||||
/// The number of bytes to read from `new_path`
|
||||
pub fn path_symlink(
|
||||
ctx: &mut Ctx,
|
||||
old_path: WasmPtr<u8, Array>,
|
||||
@ -1944,16 +1962,89 @@ pub fn path_symlink(
|
||||
new_path_len: u32,
|
||||
) -> __wasi_errno_t {
|
||||
debug!("wasi::path_symlink");
|
||||
unimplemented!("wasi::path_symlink")
|
||||
let state = get_wasi_state(ctx);
|
||||
let memory = ctx.memory(0);
|
||||
let old_path_str = wasi_try!(
|
||||
old_path.get_utf8_string(memory, old_path_len),
|
||||
__WASI_EINVAL
|
||||
);
|
||||
let new_path_str = wasi_try!(
|
||||
new_path.get_utf8_string(memory, new_path_len),
|
||||
__WASI_EINVAL
|
||||
);
|
||||
let base_fd = wasi_try!(state.fs.get_fd(fd));
|
||||
if !has_rights(base_fd.rights, __WASI_RIGHT_PATH_SYMLINK) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
|
||||
// get the depth of the parent + 1 (UNDER INVESTIGATION HMMMMMMMM THINK FISH ^ THINK FISH)
|
||||
let old_path_path = std::path::Path::new(old_path_str);
|
||||
let (source_inode, _) = wasi_try!(state.fs.get_parent_inode_at_path(fd, old_path_path, true));
|
||||
let depth = wasi_try!(state.fs.path_depth_from_fd(fd, source_inode)) - 1;
|
||||
|
||||
let new_path_path = std::path::Path::new(new_path_str);
|
||||
let (target_parent_inode, entry_name) =
|
||||
wasi_try!(state.fs.get_parent_inode_at_path(fd, new_path_path, true));
|
||||
|
||||
// short circuit if anything is wrong, before we create an inode
|
||||
match &state.fs.inodes[target_parent_inode].kind {
|
||||
Kind::Dir { entries, .. } => {
|
||||
if entries.contains_key(&entry_name) {
|
||||
return __WASI_EEXIST;
|
||||
}
|
||||
}
|
||||
Kind::Root { .. } => return __WASI_ENOTCAPABLE,
|
||||
Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => {
|
||||
unreachable!("get_parent_inode_at_path returned something other than a Dir or Root")
|
||||
}
|
||||
}
|
||||
|
||||
let mut source_path = std::path::Path::new(old_path_str);
|
||||
let mut relative_path = std::path::PathBuf::new();
|
||||
for _ in 0..depth {
|
||||
relative_path.push("..");
|
||||
}
|
||||
relative_path.push(source_path);
|
||||
debug!(
|
||||
"Symlinking {} to {}",
|
||||
new_path_str,
|
||||
relative_path.to_string_lossy()
|
||||
);
|
||||
|
||||
let kind = Kind::Symlink {
|
||||
base_po_dir: fd,
|
||||
path_to_symlink: std::path::PathBuf::from(new_path_str),
|
||||
relative_path,
|
||||
};
|
||||
let new_inode = state
|
||||
.fs
|
||||
.create_inode_with_default_stat(kind, false, entry_name.clone());
|
||||
|
||||
if let Kind::Dir {
|
||||
ref mut entries, ..
|
||||
} = &mut state.fs.inodes[target_parent_inode].kind
|
||||
{
|
||||
entries.insert(entry_name, new_inode);
|
||||
}
|
||||
|
||||
__WASI_ESUCCESS
|
||||
}
|
||||
|
||||
/// ### `path_unlink_file()`
|
||||
/// Unlink a file, deleting if the number of hardlinks is 1
|
||||
/// Inputs:
|
||||
/// - `__wasi_fd_t fd`
|
||||
/// The base file descriptor from which the path is understood
|
||||
/// - `const char *path`
|
||||
/// Array of UTF-8 bytes representing the path
|
||||
/// - `u32 path_len`
|
||||
/// The number of bytes in the `path` array
|
||||
pub fn path_unlink_file(
|
||||
ctx: &mut Ctx,
|
||||
fd: __wasi_fd_t,
|
||||
path: WasmPtr<u8, Array>,
|
||||
path_len: u32,
|
||||
) -> __wasi_errno_t {
|
||||
// TODO check if fd is a dir, ensure it's within sandbox, etc.
|
||||
debug!("wasi::path_unlink_file");
|
||||
let state = get_wasi_state(ctx);
|
||||
let memory = ctx.memory(0);
|
||||
@ -1992,7 +2083,7 @@ pub fn path_unlink_file(
|
||||
match &mut state.fs.inodes[removed_inode].kind {
|
||||
Kind::File { handle, path } => {
|
||||
if let Some(h) = handle {
|
||||
wasi_try!(h.unlink().ok_or(__WASI_EIO));
|
||||
wasi_try!(h.unlink().map_err(WasiFsError::into_wasi_err));
|
||||
} else {
|
||||
// File is closed
|
||||
// problem with the abstraction, we can't call unlink because there's no handle
|
||||
@ -2000,7 +2091,11 @@ pub fn path_unlink_file(
|
||||
wasi_try!(std::fs::remove_file(path).map_err(|_| __WASI_EIO));
|
||||
}
|
||||
}
|
||||
_ => unimplemented!("wasi::path_unlink_file for non-files"),
|
||||
Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR,
|
||||
Kind::Symlink { .. } => {
|
||||
// TODO: actually delete real symlinks and do nothing for virtual symlinks
|
||||
}
|
||||
_ => unimplemented!("wasi::path_unlink_file for Buffer"),
|
||||
}
|
||||
let inode_was_removed = unsafe { state.fs.remove_inode(removed_inode) };
|
||||
assert!(
|
||||
|
@ -21,7 +21,7 @@ use structopt::StructOpt;
|
||||
use wasmer::*;
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
#[cfg(feature = "backend-llvm")]
|
||||
use wasmer_llvm_backend::LLVMCompiler;
|
||||
use wasmer_llvm_backend::{LLVMCompiler, LLVMOptions};
|
||||
use wasmer_runtime::{
|
||||
cache::{Cache as BaseCache, FileSystemCache, WasmHash},
|
||||
Func, Value, VERSION,
|
||||
@ -88,6 +88,23 @@ struct PrestandardFeatures {
|
||||
all: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "backend-llvm")]
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
/// LLVM backend flags.
|
||||
pub struct LLVMCLIOptions {
|
||||
/// Emit LLVM IR before optimization pipeline.
|
||||
#[structopt(long = "llvm-pre-opt-ir", parse(from_os_str))]
|
||||
pre_opt_ir: Option<PathBuf>,
|
||||
|
||||
/// Emit LLVM IR after optimization pipeline.
|
||||
#[structopt(long = "llvm-post-opt-ir", parse(from_os_str))]
|
||||
post_opt_ir: Option<PathBuf>,
|
||||
|
||||
/// Emit LLVM generated native code object file.
|
||||
#[structopt(long = "backend-llvm-object-file", parse(from_os_str))]
|
||||
obj_file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
struct Run {
|
||||
// Disable the cache
|
||||
@ -155,6 +172,10 @@ struct Run {
|
||||
#[structopt(long = "cache-key", hidden = true)]
|
||||
cache_key: Option<String>,
|
||||
|
||||
#[cfg(feature = "backend-llvm")]
|
||||
#[structopt(flatten)]
|
||||
backend_llvm_options: LLVMCLIOptions,
|
||||
|
||||
#[structopt(flatten)]
|
||||
features: PrestandardFeatures,
|
||||
|
||||
@ -356,6 +377,20 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
||||
.map_err(|e| format!("Can't convert from wast to wasm: {:?}", e))?;
|
||||
}
|
||||
|
||||
#[cfg(feature = "backend-llvm")]
|
||||
{
|
||||
if options.backend == Backend::LLVM {
|
||||
let options = options.backend_llvm_options.clone();
|
||||
unsafe {
|
||||
wasmer_llvm_backend::GLOBAL_OPTIONS = LLVMOptions {
|
||||
pre_opt_ir: options.pre_opt_ir,
|
||||
post_opt_ir: options.post_opt_ir,
|
||||
obj_file: options.obj_file,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let compiler: Box<dyn Compiler> = match options.backend {
|
||||
#[cfg(feature = "backend-singlepass")]
|
||||
Backend::Singlepass => Box::new(SinglePassCompiler::new()),
|
||||
@ -488,7 +523,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
||||
let index = instance
|
||||
.resolve_func("_start")
|
||||
.expect("The loader requires a _start function to be present in the module");
|
||||
let mut ins: Box<LoadedInstance<Error = String>> = match loader {
|
||||
let mut ins: Box<dyn LoadedInstance<Error = String>> = match loader {
|
||||
LoaderName::Local => Box::new(
|
||||
instance
|
||||
.load(LocalLoader)
|
||||
|
Loading…
Reference in New Issue
Block a user