Move signature checking into export_entry

Looking at the tests it seems that signature checking is expected to be done by `export_entry`. But in fact if signatures don't match, `export_entry` delegates to it's `env` field, which will usually should return `Error::Function` since there is no function registered with a such name.

This change set should fix that.
This commit is contained in:
Sergey Pepyakin 2017-11-23 13:42:17 +03:00
parent 7ed7f79a2d
commit c4245d584e
3 changed files with 73 additions and 28 deletions

View File

@ -125,21 +125,51 @@ impl<'a, E> ModuleInstanceInterface<E> for NativeModuleInstance<'a, E> where E:
let composite_index = NATIVE_INDEX_FUNC_MIN + *index;
match required_type {
&ExportEntryType::Any => return Ok(Internal::Function(composite_index)),
&ExportEntryType::Function(ref required_type)
if self.function_type(ItemIndex::Internal(composite_index))
.expect("by_name contains index; function_type succeeds for all functions from by_name; qed") == *required_type
=> return Ok(Internal::Function(composite_index)),
&ExportEntryType::Function(ref required_type) => {
let actual_type = self.function_type(ItemIndex::Internal(composite_index))
.expect(
"by_name contains index; function_type succeeds for all functions from by_name; qed",
);
return if actual_type == *required_type {
Ok(Internal::Function(composite_index))
} else {
Err(Error::Validation(format!(
"Export function type {} mismatch. Expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
index,
required_type.params(),
required_type.return_type(),
actual_type.params(),
actual_type.return_type()
)))
};
}
_ => (),
}
}
if let Some(index) = self.globals_by_name.get(name) {
let composite_index = NATIVE_INDEX_GLOBAL_MIN + *index;
match required_type {
&ExportEntryType::Any => return Ok(Internal::Global(NATIVE_INDEX_GLOBAL_MIN + *index)),
&ExportEntryType::Global(ref required_type)
if self.globals.get(*index as usize)
.expect("globals_by_name maps to indexes of globals; index read from globals_by_name; qed")
.variable_type() == *required_type
=> return Ok(Internal::Global(NATIVE_INDEX_GLOBAL_MIN + *index)),
&ExportEntryType::Any => {
return Ok(Internal::Global(composite_index))
}
&ExportEntryType::Global(ref required_type) => {
let actual_type = self.globals
.get(*index as usize)
.expect(
"globals_by_name maps to indexes of globals; index read from globals_by_name; qed",
)
.variable_type();
return if actual_type == *required_type {
Ok(Internal::Global(composite_index))
} else {
Err(Error::Validation(format!(
"Export global type {} mismatch. Expected type {:?} when got {:?}",
index,
required_type,
actual_type
)))
};
}
_ => (),
}
}
@ -227,4 +257,4 @@ impl<'a> PartialEq for UserFunctionDescriptor {
self.params() == other.params()
&& self.return_type() == other.return_type()
}
}
}

View File

@ -285,18 +285,18 @@ impl<E> ModuleInstance<E> where E: UserError {
// export entry points to function in function index space
// and Internal::Function points to type in type section
{
let export_function_type = match export_entry {
Internal::Function(function_index) => external_module.function_type(ItemIndex::IndexSpace(function_index))?,
_ => return Err(Error::Validation(format!("Export with name {} from module {} is not a function", import.field(), import.module()))),
};
if export_function_type != import_function_type {
return Err(Error::Validation(format!("Export function type {} mismatch. Expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
function_type_index, import_function_type.params(), import_function_type.return_type(),
export_function_type.params(), export_function_type.return_type())));
match export_entry {
Internal::Function(function_index) => {
external_module.function_type(ItemIndex::IndexSpace(function_index))?
}
}
_ => {
return Err(Error::Validation(format!(
"Export with name {} from module {} is not a function",
import.field(),
import.module()
)))
}
};
},
&External::Global(ref global_type) => if global_type.is_mutable() {
return Err(Error::Validation(format!("trying to import mutable global {}", import.field())));

View File

@ -76,7 +76,7 @@ fn wrong_import() {
let program = DefaultProgramInstance::new().unwrap();
let _side_module_instance = program.add_module("side_module", side_module, None).unwrap();
assert!(program.add_module("main", module, None).is_err());
assert!(program.add_module("main", module, None).is_err());
}
#[test]
@ -314,7 +314,7 @@ fn native_env_function_own_memory() {
let module_instance = program.add_module("main", module, Some(&params.externals)).unwrap();
// now get memory reference
let module_memory = module_instance.memory(ItemIndex::Internal(0)).unwrap();
// post-initialize our executor with memory reference
// post-initialize our executor with memory reference
*memory_ref.memory.borrow_mut() = Some(module_memory);
// now execute function => executor updates memory
@ -427,14 +427,29 @@ fn env_native_export_entry_type_check() {
};
let native_env_instance = Arc::new(env_native_module(program.module("env").unwrap(), UserDefinedElements {
executor: Some(&mut function_executor),
globals: HashMap::new(),
globals: vec![("ext_global".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(1312)).unwrap()))].into_iter().collect(),
functions: ::std::borrow::Cow::from(SIGNATURES),
}).unwrap());
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32, ValueType::I32], Some(ValueType::I32))))).is_ok());
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![], Some(ValueType::I32))))).is_err());
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32, ValueType::I32], None)))).is_err());
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32, ValueType::I32], Some(ValueType::I64))))).is_err());
match native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![], Some(ValueType::I32))))) {
Err(Error::Validation(_)) => { },
result => panic!("Unexpected result {:?}.", result),
}
match native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32, ValueType::I32], None)))) {
Err(Error::Validation(_)) => { },
result => panic!("Unexpected result {:?}.", result),
}
match native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32, ValueType::I32], Some(ValueType::I64))))) {
Err(Error::Validation(_)) => { },
result => panic!("Unexpected result {:?}.", result),
}
assert!(native_env_instance.export_entry("ext_global", &ExportEntryType::Global(VariableType::I32)).is_ok());
match native_env_instance.export_entry("ext_global", &ExportEntryType::Global(VariableType::F32)) {
Err(Error::Validation(_)) => { },
result => panic!("Unexpected result {:?}.", result),
}
}
#[test]