Validate that CPU features are supported when instantiating a module

This commit is contained in:
Amanieu d'Antras
2021-11-23 15:21:34 +00:00
parent 4f65a561ee
commit a603c33def
18 changed files with 89 additions and 17 deletions

5
Cargo.lock generated
View File

@@ -2900,6 +2900,7 @@ name = "wasmer-engine"
version = "2.0.0"
dependencies = [
"backtrace",
"enumset",
"lazy_static",
"loupe",
"memmap2",
@@ -2919,6 +2920,7 @@ name = "wasmer-engine-dummy"
version = "2.0.0"
dependencies = [
"bincode",
"enumset",
"loupe",
"serde",
"serde_bytes",
@@ -2933,6 +2935,7 @@ name = "wasmer-engine-dylib"
version = "2.0.0"
dependencies = [
"cfg-if 1.0.0",
"enumset",
"leb128",
"libloading",
"loupe",
@@ -2954,6 +2957,7 @@ version = "2.0.0"
dependencies = [
"bincode",
"cfg-if 1.0.0",
"enumset",
"leb128",
"libloading",
"loupe",
@@ -2972,6 +2976,7 @@ name = "wasmer-engine-universal"
version = "2.0.0"
dependencies = [
"cfg-if 1.0.0",
"enumset",
"leb128",
"loupe",
"region",

View File

@@ -58,6 +58,11 @@ pub enum InstantiationError {
#[error(transparent)]
Start(RuntimeError),
/// The module was compiled with a CPU feature that is not available on
/// the current host.
#[error("missing requires CPU features: {0:?}")]
CpuFeature(String),
/// Error occurred when initializing the host environment.
#[error(transparent)]
HostEnvInitialization(HostEnvInitError),
@@ -68,6 +73,7 @@ impl From<wasmer_engine::InstantiationError> for InstantiationError {
match other {
wasmer_engine::InstantiationError::Link(e) => Self::Link(e),
wasmer_engine::InstantiationError::Start(e) => Self::Start(e),
wasmer_engine::InstantiationError::CpuFeature(e) => Self::CpuFeature(e),
}
}
}

View File

@@ -73,6 +73,12 @@ pub unsafe extern "C" fn wasm_instance_new(
return None;
}
Err(e @ InstantiationError::CpuFeature(_)) => {
crate::error::update_last_error(e.to_string());
return None;
}
Err(InstantiationError::HostEnvInitialization(error)) => {
crate::error::update_last_error(error);

View File

@@ -25,6 +25,7 @@ tempfile = "3.1"
which = "4.0"
rkyv = "0.6.1"
loupe = "0.1"
enumset = "1.0"
[features]
# Enable the `compiler` feature if you want the engine to compile

View File

@@ -3,6 +3,7 @@
use crate::engine::{DylibEngine, DylibEngineInner};
use crate::serialize::{ArchivedModuleMetadata, ModuleMetadata};
use enumset::EnumSet;
use libloading::{Library, Symbol as LibrarySymbol};
use loupe::MemoryUsage;
use std::error::Error;
@@ -17,8 +18,8 @@ use tracing::log::error;
#[cfg(feature = "compiler")]
use tracing::trace;
use wasmer_compiler::{
Architecture, CompileError, CompiledFunctionFrameInfo, Features, FunctionAddressMap,
OperatingSystem, Symbol, SymbolRegistry, Triple,
Architecture, CompileError, CompiledFunctionFrameInfo, CpuFeature, Features,
FunctionAddressMap, OperatingSystem, Symbol, SymbolRegistry, Triple,
};
#[cfg(feature = "compiler")]
use wasmer_compiler::{
@@ -211,6 +212,7 @@ impl DylibArtifact {
prefix: engine_inner.get_prefix(&data),
data_initializers,
function_body_lengths,
cpu_features: target.cpu_features().as_u64(),
};
let serialized_data = metadata.serialize()?;
@@ -800,6 +802,10 @@ impl Artifact for DylibArtifact {
&self.metadata.compile_info.features
}
fn cpu_features(&self) -> enumset::EnumSet<CpuFeature> {
EnumSet::from_u64(self.metadata.cpu_features)
}
fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.metadata.data_initializers
}

View File

@@ -35,6 +35,7 @@ pub struct ModuleMetadata {
pub data_initializers: Box<[OwnedDataInitializer]>,
// The function body lengths (used to find function by address)
pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>,
pub cpu_features: u64,
}
pub struct ModuleMetadataSymbolRegistry<'a> {

View File

@@ -24,6 +24,7 @@ leb128 = "0.2"
libloading = "0.7"
tempfile = "3.1"
loupe = "0.1"
enumset = "1.0"
[features]
# Enable the `compiler` feature if you want the engine to compile

View File

@@ -3,12 +3,15 @@
use crate::engine::{StaticlibEngine, StaticlibEngineInner};
use crate::serialize::{ModuleMetadata, ModuleMetadataSymbolRegistry};
use enumset::EnumSet;
use loupe::MemoryUsage;
use std::collections::BTreeMap;
use std::error::Error;
use std::mem;
use std::sync::Arc;
use wasmer_compiler::{CompileError, Features, OperatingSystem, SymbolRegistry, Triple};
use wasmer_compiler::{
CompileError, CpuFeature, Features, OperatingSystem, SymbolRegistry, Triple,
};
#[cfg(feature = "compiler")]
use wasmer_compiler::{
CompileModuleInfo, Compiler, FunctionBodyData, ModuleEnvironment, ModuleMiddlewareChain,
@@ -182,6 +185,7 @@ impl StaticlibArtifact {
prefix: engine_inner.get_prefix(&data),
data_initializers,
function_body_lengths,
cpu_features: target.cpu_features().as_u64(),
};
/*
@@ -453,6 +457,10 @@ impl Artifact for StaticlibArtifact {
&self.metadata.compile_info.features
}
fn cpu_features(&self) -> EnumSet<CpuFeature> {
EnumSet::from_u64(self.metadata.cpu_features)
}
fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.metadata.data_initializers
}

View File

@@ -12,6 +12,7 @@ pub struct ModuleMetadata {
pub data_initializers: Box<[OwnedDataInitializer]>,
// The function body lengths (used to find function by address)
pub function_body_lengths: PrimaryMap<LocalFunctionIndex, u64>,
pub cpu_features: u64,
}
#[derive(MemoryUsage)]

View File

@@ -11,8 +11,13 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-types = { path = "../types", version = "2.0.0", features = ["enable-rkyv"] }
wasmer-compiler = { path = "../compiler", version = "2.0.0", features = ["translator", "enable-rkyv"] }
wasmer-types = { path = "../types", version = "2.0.0", features = [
"enable-rkyv",
] }
wasmer-compiler = { path = "../compiler", version = "2.0.0", features = [
"translator",
"enable-rkyv",
] }
wasmer-vm = { path = "../vm", version = "2.0.0", features = ["enable-rkyv"] }
wasmer-engine = { path = "../engine", version = "2.0.0" }
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
@@ -21,6 +26,7 @@ cfg-if = "1.0"
leb128 = "0.2"
rkyv = "0.6.1"
loupe = "0.1"
enumset = "1.0"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winnt", "impl-default"] }

View File

@@ -6,9 +6,10 @@ use crate::link::link_module;
#[cfg(feature = "compiler")]
use crate::serialize::SerializableCompilation;
use crate::serialize::SerializableModule;
use enumset::EnumSet;
use loupe::MemoryUsage;
use std::sync::{Arc, Mutex};
use wasmer_compiler::{CompileError, Features, Triple};
use wasmer_compiler::{CompileError, CpuFeature, Features, Triple};
#[cfg(feature = "compiler")]
use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment, ModuleMiddlewareChain};
use wasmer_engine::{
@@ -128,6 +129,7 @@ impl UniversalArtifact {
compilation: serializable_compilation,
compile_info,
data_initializers,
cpu_features: engine.target().cpu_features().as_u64(),
};
Self::from_parts(&mut inner_engine, serializable)
}
@@ -307,6 +309,10 @@ impl Artifact for UniversalArtifact {
&self.serializable.compile_info.features
}
fn cpu_features(&self) -> EnumSet<CpuFeature> {
EnumSet::from_u64(self.serializable.cpu_features)
}
fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.serializable.data_initializers
}

View File

@@ -38,6 +38,7 @@ pub struct SerializableModule {
pub compilation: SerializableCompilation,
pub compile_info: CompileModuleInfo,
pub data_initializers: Box<[OwnedDataInitializer]>,
pub cpu_features: u64,
}
fn to_serialize_error(err: impl std::error::Error) -> SerializeError {

View File

@@ -25,6 +25,7 @@ serde = { version = "1.0", features = ["derive", "rc"] }
serde_bytes = { version = "0.11" }
lazy_static = "1.4"
loupe = "0.1"
enumset = "1.0"
[badges]
maintenance = { status = "actively-developed" }

View File

@@ -1,12 +1,13 @@
use crate::{
resolve_imports, InstantiationError, Resolver, RuntimeError, SerializeError, Tunables,
};
use enumset::EnumSet;
use loupe::MemoryUsage;
use std::any::Any;
use std::fs;
use std::path::Path;
use std::sync::Arc;
use wasmer_compiler::Features;
use wasmer_compiler::{CpuFeature, Features};
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
use wasmer_types::{
DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo,
@@ -43,6 +44,9 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
/// Returns the features for this Artifact
fn features(&self) -> &Features;
/// Returns the CPU features for this Artifact
fn cpu_features(&self) -> EnumSet<CpuFeature>;
/// Returns the memory styles associated with this `Artifact`.
fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle>;
@@ -96,6 +100,16 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
resolver: &dyn Resolver,
host_state: Box<dyn Any>,
) -> Result<InstanceHandle, InstantiationError> {
// Validate the CPU features this module was compiled with against the
// host CPU features.
let host_cpu_features = CpuFeature::for_host();
if !host_cpu_features.is_superset(self.cpu_features()) {
Err(InstantiationError::CpuFeature(format!(
"{:?}",
self.cpu_features().difference(host_cpu_features)
)))?;
}
self.preinstantiate()?;
let module = self.module();

View File

@@ -91,6 +91,11 @@ pub enum InstantiationError {
#[error(transparent)]
Link(LinkError),
/// The module was compiled with a CPU feature that is not available on
/// the current host.
#[error("module compiled with CPU feature that is missing from host")]
CpuFeature(String),
/// A runtime error occured while invoking the start function
#[error(transparent)]
Start(RuntimeError),

View File

@@ -257,7 +257,9 @@ fn trap_start_function_import(config: crate::Config) -> Result<()> {
.err()
.unwrap();
match err {
InstantiationError::Link(_) | InstantiationError::HostEnvInitialization(_) => {
InstantiationError::Link(_)
| InstantiationError::HostEnvInitialization(_)
| InstantiationError::CpuFeature(_) => {
panic!("It should be a start error")
}
InstantiationError::Start(err) => {

View File

@@ -16,19 +16,14 @@ serde = { version = "1.0", features = ["derive", "rc"], optional = true }
serde_bytes = { version = "0.11", optional = true }
bincode = { version = "1.2", optional = true }
loupe = "0.1"
enumset = "1.0"
[features]
# Enable the `compiler` feature if you want the engine to compile
# and not be only on headless mode.
default = ["serialize", "compiler"]
compiler = [
"wasmer-compiler/translator"
]
serialize = [
"serde",
"serde_bytes",
"bincode"
]
compiler = ["wasmer-compiler/translator"]
serialize = ["serde", "serde_bytes", "bincode"]
[badges]
# TODO: publish this crate again and deprecate it

View File

@@ -2,13 +2,14 @@
//! done as separate steps.
use crate::engine::DummyEngine;
use enumset::EnumSet;
use loupe::MemoryUsage;
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use wasmer_compiler::CompileError;
#[cfg(feature = "compiler")]
use wasmer_compiler::ModuleEnvironment;
use wasmer_compiler::{CompileError, CpuFeature};
use wasmer_engine::{Artifact, DeserializeError, Engine as _, SerializeError, Tunables};
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
use wasmer_types::{
@@ -30,6 +31,7 @@ pub struct DummyArtifactMetadata {
// Plans for that module
pub memory_styles: PrimaryMap<MemoryIndex, MemoryStyle>,
pub table_styles: PrimaryMap<TableIndex, TableStyle>,
pub cpu_features: u64,
}
/// A Dummy artifact.
@@ -104,6 +106,7 @@ impl DummyArtifact {
data_initializers,
memory_styles,
table_styles,
cpu_features: engine.target().cpu_features().as_u64(),
};
Self::from_parts(&engine, metadata)
}
@@ -211,6 +214,10 @@ impl Artifact for DummyArtifact {
&self.metadata.features
}
fn cpu_features(&self) -> EnumSet<CpuFeature> {
EnumSet::from_u64(self.metadata.cpu_features)
}
fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.metadata.data_initializers
}