Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wasm-builder): Check all gear requirements for code at compile time #3649

Merged
merged 21 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions utils/wasm-builder/src/checks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use gear_wasm_instrument::parity_wasm::elements::{Internal, Module, Type};

#[derive(Debug)]
pub enum Error {
ExportSectionMissing,
ImportSectionMissing,
FunctionSectionMissing,
TypeSectionMissing,
CodeSectionMissing,
UnexpectedFunctionExport(String),
MissingEntryFunction,
InvalidExportFunctionSignature,
}

pub fn do_checks(module: Module) -> Result<(), Error> {

let exports = module.export_section().ok_or(Error::ExportSectionMissing)?;
let imports = module.import_section().ok_or(Error::ImportSectionMissing)?;
let functions = module.function_section().ok_or(Error::FunctionSectionMissing)?;
let types = module.type_section().ok_or(Error::TypeSectionMissing)?;
let code = module.code_section().ok_or(Error::CodeSectionMissing)?;

let imported_functions = imports.functions();

// While this is checked in Code::new, we might as well check it when building wasm program
StackOverflowExcept1on marked this conversation as resolved.
Show resolved Hide resolved
let mut entry = false;
for e in exports.entries() {
if let Internal::Function(i) = e.internal() {
match e.field() {
"init" | "handle" | "handle_reply" | "handle_signal" | "state" | "meta" => {
entry = true;
let Type::Function(ref t) = types.types()[functions.entries()[*i as usize - imported_functions]];
if !t.params().is_empty() || !t.results().is_empty() {
return Err(Error::InvalidExportFunctionSignature);
}
},
_ => return Err(Error::UnexpectedFunctionExport(e.field().to_string()))
}
}
}
if !entry {
return Err(Error::MissingEntryFunction)
}



Ok(())
}
1 change: 1 addition & 0 deletions utils/wasm-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub mod optimize;
mod smart_fs;
mod stack_end;
mod wasm_project;
mod checks;

pub const TARGET: &str = env!("TARGET");

Expand Down
6 changes: 6 additions & 0 deletions utils/wasm-builder/src/wasm_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ use std::{
path::{Path, PathBuf},
};
use toml::value::Table;
use crate::checks::do_checks;
use crate::optimize::do_optimization;

const OPT_LEVEL: &str = "z";

Expand Down Expand Up @@ -371,6 +373,10 @@ extern "C" fn metahash() {{
.context("Failed to write optimized WASM binary")?;
}

// Generate module from optimized wasm file to run gear checks
let module = parity_wasm::elements::Module::from_bytes(fs::read(opt_wasm_path.clone()).expect("Failed to read optimized wasm binary")).expect("Invalid wasm generated by wasm-opt");
do_checks(module).expect("Wasm code did not pass gear checks");

// Create path string in `.binpath` file.
let relative_path_to_wasm = pathdiff::diff_paths(&self.wasm_target_dir, &self.original_dir)
.with_context(|| {
Expand Down
Loading