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

wasm extractor - fix report parameters #1775

Merged
merged 4 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
44 changes: 44 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions framework/meta-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ hex = "0.4"
wasmparser = "0.216"
wasmprinter = "0.216"
semver = "1.0.20"
wat = "1.217.0"

[dependencies.multiversx-sc]
version = "=0.53.0"
Expand Down
2 changes: 1 addition & 1 deletion framework/meta-lib/src/code_report_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl CodeReportJson {
path: report.path.clone(),
size,
has_allocator: report.has_allocator,
has_panic: report.has_panic.clone(),
has_panic: report.has_panic.to_string(),
}
}
}
2 changes: 2 additions & 0 deletions framework/meta-lib/src/tools.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod find_workspace;
mod git_describe;
pub(crate) mod panic_report;
pub(crate) mod report_creator;
pub mod twiggy;
mod wasm_extractor;
mod wasm_extractor_test;
mod wasm_opt;
mod wasm_to_wat;

Expand Down
80 changes: 80 additions & 0 deletions framework/meta-lib/src/tools/panic_report.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use std::fmt::Display;

use wasmparser::DataSectionReader;
const PANIC_WITH_MESSAGE: &[u8; 16] = b"panic occurred: ";
const PANIC_WITHOUT_MESSAGE: &[u8; 14] = b"panic occurred";

#[derive(Default, PartialEq, Clone)]
pub enum PanicReport {
#[default]
None,
WithoutMessage,
WithMessage,
}

impl Display for PanicReport {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let panic_status = match self {
PanicReport::None => "None",
PanicReport::WithoutMessage => "without message",
PanicReport::WithMessage => "with message",
};
write!(f, "{}", panic_status)
}
}

impl PanicReport {
pub fn data_section_severity(&self, data_section: DataSectionReader) -> Self {
if is_panic_with_message_triggered(data_section.clone()) {
return Self::WithMessage;
}

if is_panic_without_message_triggered(data_section) {
println!("here");
return Self::WithoutMessage;
}

Self::None
}

pub fn max_severity(&mut self, data_section: DataSectionReader) {
if *self == PanicReport::WithMessage {
return;
}

let panic_report = self.data_section_severity(data_section);
if panic_report == PanicReport::None {
return;
}

*self = panic_report;
}
}

fn is_panic_with_message_triggered(data_section: DataSectionReader) -> bool {
for data_fragment in data_section.into_iter().flatten() {
if data_fragment
.data
.windows(PANIC_WITH_MESSAGE.len())
.any(|data| data == PANIC_WITH_MESSAGE)
{
return true;
}
}

false
}

fn is_panic_without_message_triggered(data_section: DataSectionReader) -> bool {
for data_fragment in data_section.into_iter().flatten() {
if data_fragment
.data
.windows(PANIC_WITHOUT_MESSAGE.len())
.any(|data| data == PANIC_WITHOUT_MESSAGE)
{
return true;
}
}

false
}
5 changes: 2 additions & 3 deletions framework/meta-lib/src/tools/report_creator.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
pub const WITH_MESSAGE: &str = "with message";
pub const WITHOUT_MESSAGE: &str = "without message";
use super::panic_report::PanicReport;

pub struct ReportCreator {
pub path: String,
pub has_allocator: bool,
pub has_panic: String,
pub has_panic: PanicReport,
}

impl ReportCreator {}
64 changes: 17 additions & 47 deletions framework/meta-lib/src/tools/wasm_extractor.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
use colored::Colorize;
use std::fs;
use wasmparser::{
BinaryReaderError, DataSectionReader, FunctionBody, ImportSectionReader, Parser, Payload,
BinaryReaderError, DataSectionReader, FunctionBody, ImportSectionReader, Operator, Parser,
Payload,
};

use crate::ei::EIVersion;

use super::report_creator::{ReportCreator, WITHOUT_MESSAGE, WITH_MESSAGE};
use super::{panic_report::PanicReport, report_creator::ReportCreator};

const PANIC_WITH_MESSAGE: &[u8; 16] = b"panic occurred: ";
const PANIC_WITHOUT_MESSAGE: &[u8; 14] = b"panic occurred";
const ERROR_FAIL_ALLOCATOR: &[u8; 27] = b"memory allocation forbidden";
const MEMORY_GROW_OPCODE: u8 = 0x40;

pub struct WasmInfo {
pub imports: Vec<String>,
Expand Down Expand Up @@ -39,7 +37,7 @@ impl WasmInfo {
}
}

fn populate_wasm_info(
pub(crate) fn populate_wasm_info(
path: String,
wasm_data: Vec<u8>,
extract_imports_enabled: bool,
Expand All @@ -49,25 +47,21 @@ fn populate_wasm_info(
let mut allocator_trigger = false;
let mut ei_check = false;
let mut memory_grow_flag = false;
let mut has_panic = "none";
let mut has_panic: PanicReport = PanicReport::default();

let parser = Parser::new(0);
for payload in parser.parse_all(&wasm_data) {
match payload? {
Payload::ImportSection(import_section) => {
imports = extract_imports(import_section, extract_imports_enabled);
ei_check = is_ei_valid(imports.clone(), check_ei);
ei_check |= is_ei_valid(imports.clone(), check_ei);
},
Payload::DataSection(data_section) => {
allocator_trigger = is_fail_allocator_triggered(data_section.clone());
if is_panic_with_message_triggered(data_section.clone()) {
has_panic = WITH_MESSAGE;
} else if is_panic_without_message_triggered(data_section) {
has_panic = WITHOUT_MESSAGE;
}
allocator_trigger |= is_fail_allocator_triggered(data_section.clone());
has_panic.max_severity(data_section);
},
Payload::CodeSectionEntry(code_section) => {
memory_grow_flag = is_mem_grow(code_section);
memory_grow_flag |= is_mem_grow(code_section);
},
_ => (),
}
Expand All @@ -76,7 +70,7 @@ fn populate_wasm_info(
let report = ReportCreator {
path,
has_allocator: allocator_trigger,
has_panic: has_panic.to_string(),
has_panic,
};

Ok(WasmInfo {
Expand Down Expand Up @@ -109,34 +103,6 @@ fn is_fail_allocator_triggered(data_section: DataSectionReader) -> bool {
false
}

fn is_panic_with_message_triggered(data_section: DataSectionReader) -> bool {
for data_fragment in data_section.into_iter().flatten() {
if data_fragment
.data
.windows(PANIC_WITH_MESSAGE.len())
.any(|data| data == PANIC_WITH_MESSAGE)
{
return true;
}
}

false
}

fn is_panic_without_message_triggered(data_section: DataSectionReader) -> bool {
for data_fragment in data_section.into_iter().flatten() {
if data_fragment
.data
.windows(PANIC_WITHOUT_MESSAGE.len())
.any(|data| data == PANIC_WITHOUT_MESSAGE)
{
return true;
}
}

false
}

pub fn extract_imports(
import_section: ImportSectionReader,
import_extraction_enabled: bool,
Expand Down Expand Up @@ -173,11 +139,15 @@ fn is_ei_valid(imports: Vec<String>, check_ei: &Option<EIVersion>) -> bool {
}

fn is_mem_grow(code_section: FunctionBody) -> bool {
let mut code = code_section.get_binary_reader();
while code.bytes_remaining() > 0 {
if code.read_u8().unwrap() == MEMORY_GROW_OPCODE {
let mut instructions_reader = code_section
.get_operators_reader()
.expect("Failed to get operators reader");

while let Ok(op) = instructions_reader.read() {
if let Operator::MemoryGrow { mem: _ } = op {
return true;
}
}

false
}
Loading
Loading