From 76895490d4180871dff2f1cd4bd650caf170d3a5 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Thu, 29 Jun 2023 14:23:17 -0700 Subject: [PATCH 01/34] attempt at inserting things where i think they might belong + questions --- cranelift/wasm/src/code_translator.rs | 1 + crates/cranelift/src/func_environ.rs | 49 +++++++++++++++++++++++++++ crates/environ/src/builtin.rs | 5 +++ crates/runtime/src/instance.rs | 3 ++ crates/runtime/src/libcalls.rs | 13 +++++++ 5 files changed, 71 insertions(+) diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index c1c92839718f..6435af2e7628 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -591,6 +591,7 @@ pub fn translate_operator( bitcast_wasm_returns(environ, return_args, builder); builder.ins().return_(return_args); } + handle_before_return(return_args); state.popn(return_count); state.reachable = false; } diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 9b182c1a75f1..42c4badefdbb 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -650,6 +650,51 @@ impl<'module_environment> FuncEnvironment<'module_environment> { self.epoch_check(builder); } + // * is this the right place to define this hook? if so should it be + // added to builtin.rs? + // + // * what is the type for retvals supposed to be? is there a generic + // type that can be used? + // + // * if the valgrind libcalls are made right before returning, doesn't + // that mean that the metadata for the "real" memory is updated before + // there's a check for whether that allocation/free is ok or not? or + // is this a non-issue because of arena allocation? + fn handle_before_return(&mut self, retvals: &[value]) { + // strings are psuedocode + if "the function is malloc" { + builder + .ins() + .call_indirect(check_malloc_exit, &[vmctx]); + // * how to get vmctx from here? + // + // * is check_malloc_exit the right argument? I'm still a bit + // confused as to how & why this works? + } + } + + fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder) { + let check_malloc_sig = self.builtin_function_signatures.check_malloc(builder.func); + let (vmctx, check_malloc) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_malloc(), + ); + builder + .ins() + .call_indirect(check_malloc_sig, check_malloc, &[vmctx, usize, usize]); + } + + fn check_free_exit(&mut self, builder: &mut FunctionBuilder) { + let check_free_sig = self.builtin_function_signatures.check_free(builder.func); + let (vmctx, check_free) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_free(), + ); + builder + .ins() + .call_indirect(check_free_sig, check_free, &[vmctx, usize]); + } + fn epoch_ptr(&mut self, builder: &mut FunctionBuilder<'_>) -> ir::Value { let vmctx = self.vmctx(builder.func); let pointer_type = self.pointer_type(); @@ -2174,6 +2219,10 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m if self.tunables.epoch_interruption { self.epoch_function_entry(builder); } + // + if self.func == "malloc" { //psuedocode + self.check_malloc_entry(); + } Ok(()) } diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 61eb31a1f18a..0880c33ffc07 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -51,6 +51,11 @@ macro_rules! foreach_builtin_function { out_of_gas(vmctx: vmctx); /// Invoked when we reach a new epoch. new_epoch(vmctx: vmctx) -> i64; + /// Memcheck invoked when malloc is called. + // should the datatype for "addr" be "pointer" instead? + check_malloc(vmctx: vmctx, addr: usize, len: usize) -> Result<(), AccessError>; + /// Memcheck invoked when free is called. + check_free(vmctx: vmctx, addr: usize) -> -> Result<(), AccessError>; } }; } diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index 4e24aec4dd4b..c9ccca91a206 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -32,6 +32,7 @@ use wasmtime_environ::{ GlobalInit, HostPtr, MemoryIndex, Module, PrimaryMap, SignatureIndex, TableIndex, TableInitialValue, Trap, VMOffsets, WasmHeapType, WasmRefType, WasmType, VMCONTEXT_MAGIC, }; +use crate::wasm_valgrind::Valgrind; mod allocator; @@ -144,6 +145,8 @@ pub struct Instance { /// represents a dynamically-sized array that extends beyond the nominal /// end of the struct (similar to a flexible array member). vmctx: VMContext, + + valgrind_state: Valgrind, } #[allow(clippy::cast_ptr_alignment)] diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 9b133d3cc8c1..6d0745a92708 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -9,6 +9,8 @@ //! //! * They must only contain basic, raw i32/i64/f32/f64/pointer parameters that //! are safe to pass across the system ABI. +/// is the above something that should be taken into account? check_malloc +/// takes usize as the type for its len arg //! //! * If any nested function propagates an `Err(trap)` out to the library //! function frame, we need to raise it. This involves some nasty and quite @@ -65,6 +67,7 @@ use std::time::{Duration, Instant}; use wasmtime_environ::{ DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Trap, }; +use crate::wasm_valgrind::Valgrind; /// Actually public trampolines which are used by the runtime as the entrypoint /// for libcalls. @@ -487,6 +490,16 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { (*instance.store()).new_epoch() } +// +unsafe fn check_malloc(instance: &mut Instance, addr: usine, len: usize) -> Result<(), AccessError> { + instance.valgrind_state::malloc(addr, len) +} + +// +unsafe fn check_free(instance: &mut Instance, addr: usize) -> Result<(), AccessError> { + instance.valgrind_state::free(addr) +} + /// This module contains functions which are used for resolving relocations at /// runtime if necessary. /// From 3402c15d6e55f6453b5c34cf8d6eba5407d4dba4 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Wed, 5 Jul 2023 13:46:42 -0700 Subject: [PATCH 02/34] entry hook + questions --- cranelift/wasm/src/code_translator.rs | 6 +++- crates/cranelift/src/func_environ.rs | 43 ++++++++++++++++----------- crates/environ/src/builtin.rs | 5 ++-- crates/runtime/src/libcalls.rs | 14 +++++---- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 6435af2e7628..c77dfd832bf3 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -696,7 +696,11 @@ pub fn translate_operator( * Wasm specifies an integer alignment flag but we drop it in Cranelift. * The memory base address is provided by the environment. ************************************************************************************/ - Operator::I32Load8U { memarg } => { + + // there's quite a few different types loads loads; should each of them be individually + // wrapped in an if statement checking if the valgrind flag is on? + // If so, how would the Instance be accessed from here? + Operator::I32Load8U { memarg } => { unwrap_or_return_unreachable_state!( state, translate_load(memarg, ir::Opcode::Uload8, I32, builder, state, environ)? diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 42c4badefdbb..b131b636155a 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -650,27 +650,34 @@ impl<'module_environment> FuncEnvironment<'module_environment> { self.epoch_check(builder); } - // * is this the right place to define this hook? if so should it be - // added to builtin.rs? - // - // * what is the type for retvals supposed to be? is there a generic - // type that can be used? + // * I'm not sure if it's correct to pass instance as an argument + // here, as I've only seen Instance used in libcalls.rs; however, + // I wasn't sure how else to access the Valgrind state + fn handle_after_entry(&mut self, instance: &mut Instance) { + if "the function is malloc" { + instance::valgrind_state::flag = true; + } + } + + // * is self.vmctx already initialized by the time this function + // is called? or does fn vmctx() need to be called? // - // * if the valgrind libcalls are made right before returning, doesn't - // that mean that the metadata for the "real" memory is updated before - // there's a check for whether that allocation/free is ok or not? or - // is this a non-issue because of arena allocation? - fn handle_before_return(&mut self, retvals: &[value]) { - // strings are psuedocode + // * is it correct to use builder as an argument here? + fn handle_before_return(&mut self, retvals: &[value], instance: &mut Instance, builder: &mut FunctionBuilder) { + let block = builder.func.entry_block().unwrap(); + let args = builder.func.dfg.block_params(block, 0); + // * I'm still not sure how to check if the functions are malloc/free? iirc from last week's + // discussion there would have to be some pretty involved changes (something about bitcasting)? if "the function is malloc" { builder .ins() - .call_indirect(check_malloc_exit, &[vmctx]); - // * how to get vmctx from here? - // - // * is check_malloc_exit the right argument? I'm still a bit - // confused as to how & why this works? + .call_indirect(check_malloc_exit, &[self.vmctx, retvals[0], args[0]]) + } else if "the function is free" { + builder + .ins() + .call_indirect(check_free_exit, &[self.vmctx]) } + instance::valgrind_state::flag = false; } fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder) { @@ -681,7 +688,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { ); builder .ins() - .call_indirect(check_malloc_sig, check_malloc, &[vmctx, usize, usize]); + .call_indirect(check_malloc_sig, check_malloc, &[vmctx, pointer, usize]); } fn check_free_exit(&mut self, builder: &mut FunctionBuilder) { @@ -692,7 +699,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { ); builder .ins() - .call_indirect(check_free_sig, check_free, &[vmctx, usize]); + .call_indirect(check_free_sig, check_free, &[vmctx, pointer]); } fn epoch_ptr(&mut self, builder: &mut FunctionBuilder<'_>) -> ir::Value { diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 0880c33ffc07..672464ff6ad9 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -52,10 +52,9 @@ macro_rules! foreach_builtin_function { /// Invoked when we reach a new epoch. new_epoch(vmctx: vmctx) -> i64; /// Memcheck invoked when malloc is called. - // should the datatype for "addr" be "pointer" instead? - check_malloc(vmctx: vmctx, addr: usize, len: usize) -> Result<(), AccessError>; + check_malloc(vmctx: vmctx, addr: pointer, len: usize) -> Result<(), AccessError>; /// Memcheck invoked when free is called. - check_free(vmctx: vmctx, addr: usize) -> -> Result<(), AccessError>; + check_free(vmctx: vmctx, addr: pointer) -> -> Result<(), AccessError>; } }; } diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 6d0745a92708..c0fe226292a9 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -490,14 +490,16 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { (*instance.store()).new_epoch() } -// -unsafe fn check_malloc(instance: &mut Instance, addr: usine, len: usize) -> Result<(), AccessError> { - instance.valgrind_state::malloc(addr, len) +// * is there a good way to cast a pointer to usize? or should the library be modified to take pointer +// arguments instead? +unsafe fn check_malloc(instance: &mut Instance, addr: pointer, len: usize) -> Result<(), AccessError> { + let addr_usize; + instance::valgrind_state::malloc(addr_usize, len) } -// -unsafe fn check_free(instance: &mut Instance, addr: usize) -> Result<(), AccessError> { - instance.valgrind_state::free(addr) +unsafe fn check_free(instance: &mut Instance, addr: pointer) -> Result<(), AccessError> { + let addr_usize; + instance::valgrind_state::free(addr_usize) } /// This module contains functions which are used for resolving relocations at From b999de6d17b088b78007545d3511e6076543c4b5 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Thu, 13 Jul 2023 10:45:53 -0700 Subject: [PATCH 03/34] commented out all changes, doc comment errors --- .gitmodules | 3 + cranelift/wasm/src/code_translator.rs | 6 +- cranelift/wasm/src/sections_translator.rs | 1 + crates/cranelift/src/func_environ.rs | 92 +++++++++++------------ crates/environ/src/builtin.rs | 8 +- crates/runtime/src/instance.rs | 6 +- crates/runtime/src/libcalls.rs | 20 ++--- 7 files changed, 72 insertions(+), 64 deletions(-) diff --git a/.gitmodules b/.gitmodules index 70ad96ad7fa3..787cb073b831 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,3 +23,6 @@ path = tests/wasi_testsuite/wasi-common url = https://github.com/WebAssembly/wasi-testsuite.git branch = prod/testsuite-base +[submodule "wasm-valgrind"] + path = wasm-valgrind + url = https://github.com/ssunkin-fastly/wasm-valgrind diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index c77dfd832bf3..4aac309ba321 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -588,10 +588,12 @@ pub fn translate_operator( }; { let return_args = state.peekn_mut(return_count); + // println!("{:?}", return_args); + //handle_before_return(&return_args); + // curr error: handle_before_return not in scope bitcast_wasm_returns(environ, return_args, builder); builder.ins().return_(return_args); } - handle_before_return(return_args); state.popn(return_count); state.reachable = false; } @@ -699,7 +701,7 @@ pub fn translate_operator( // there's quite a few different types loads loads; should each of them be individually // wrapped in an if statement checking if the valgrind flag is on? - // If so, how would the Instance be accessed from here? + // If so, how would the Instance be accessed free Operator::I32Load8U { memarg } => { unwrap_or_return_unreachable_state!( state, diff --git a/cranelift/wasm/src/sections_translator.rs b/cranelift/wasm/src/sections_translator.rs index e7b0486ea6ce..5a18fcd31acd 100644 --- a/cranelift/wasm/src/sections_translator.rs +++ b/cranelift/wasm/src/sections_translator.rs @@ -385,6 +385,7 @@ pub fn parse_name_section<'data>( // We reserve `u32::MAX` for our own use in cranelift-entity. if index != u32::max_value() { environ.declare_func_name(FuncIndex::from_u32(index), name); + //this is where the function name is translated CLIF } } } diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index b131b636155a..78410118911d 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -653,54 +653,54 @@ impl<'module_environment> FuncEnvironment<'module_environment> { // * I'm not sure if it's correct to pass instance as an argument // here, as I've only seen Instance used in libcalls.rs; however, // I wasn't sure how else to access the Valgrind state - fn handle_after_entry(&mut self, instance: &mut Instance) { - if "the function is malloc" { - instance::valgrind_state::flag = true; - } - } + // + // * when/where are these hooks actually called? + // fn handle_after_entry(&mut self) { + // if "the function is malloc" { + // // valgrind_state.flag = true; + // } + // } // * is self.vmctx already initialized by the time this function // is called? or does fn vmctx() need to be called? // // * is it correct to use builder as an argument here? - fn handle_before_return(&mut self, retvals: &[value], instance: &mut Instance, builder: &mut FunctionBuilder) { - let block = builder.func.entry_block().unwrap(); - let args = builder.func.dfg.block_params(block, 0); - // * I'm still not sure how to check if the functions are malloc/free? iirc from last week's - // discussion there would have to be some pretty involved changes (something about bitcasting)? - if "the function is malloc" { - builder - .ins() - .call_indirect(check_malloc_exit, &[self.vmctx, retvals[0], args[0]]) - } else if "the function is free" { - builder - .ins() - .call_indirect(check_free_exit, &[self.vmctx]) - } - instance::valgrind_state::flag = false; - } - - fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder) { - let check_malloc_sig = self.builtin_function_signatures.check_malloc(builder.func); - let (vmctx, check_malloc) = self.translate_load_builtin_function_address( - &mut builder.cursor(), - BuiltinFunctionIndex::check_malloc(), - ); - builder - .ins() - .call_indirect(check_malloc_sig, check_malloc, &[vmctx, pointer, usize]); - } - - fn check_free_exit(&mut self, builder: &mut FunctionBuilder) { - let check_free_sig = self.builtin_function_signatures.check_free(builder.func); - let (vmctx, check_free) = self.translate_load_builtin_function_address( - &mut builder.cursor(), - BuiltinFunctionIndex::check_free(), - ); - builder - .ins() - .call_indirect(check_free_sig, check_free, &[vmctx, pointer]); - } + // fn handle_before_return(&mut self, retvals: &[Value], builder: &mut FunctionBuilder) { + // let block = builder.func.entry_block().unwrap(); + // let args = builder.func.dfg.block_params(block, 0); + // if "the function is malloc" { + // builder + // .ins() + // .call_indirect(check_malloc_exit, &[self.vmctx, retvals[0], args[0]]); + // } else if "the function is free" { + // builder + // .ins() + // .call_indirect(check_free_exit, &[self.vmctx]); + // } + // valgrind_state.flag = false; + // } + + // fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder) { + // let check_malloc_sig = self.builtin_function_signatures.check_malloc(builder.func); + // let (vmctx, check_malloc) = self.translate_load_builtin_function_address( + // &mut builder.cursor(), + // BuiltinFunctionIndex::check_malloc(), + // ); + // builder + // .ins() + // .call_indirect(check_malloc_sig, check_malloc, &[vmctx, pointer, usize]); + // } + + // fn check_free_exit(&mut self, builder: &mut FunctionBuilder) { + // let check_free_sig = self.builtin_function_signatures.check_free(builder.func); + // let (vmctx, check_free) = self.translate_load_builtin_function_address( + // &mut builder.cursor(), + // BuiltinFunctionIndex::check_free(), + // ); + // builder + // .ins() + // .call_indirect(check_free_sig, check_free, &[vmctx, pointer]); + // } fn epoch_ptr(&mut self, builder: &mut FunctionBuilder<'_>) -> ir::Value { let vmctx = self.vmctx(builder.func); @@ -2227,9 +2227,9 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m self.epoch_function_entry(builder); } // - if self.func == "malloc" { //psuedocode - self.check_malloc_entry(); - } + // if self.func == "malloc" { //psuedocode + // self.check_malloc_entry(); + // } Ok(()) } diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 672464ff6ad9..49309729204b 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -51,10 +51,10 @@ macro_rules! foreach_builtin_function { out_of_gas(vmctx: vmctx); /// Invoked when we reach a new epoch. new_epoch(vmctx: vmctx) -> i64; - /// Memcheck invoked when malloc is called. - check_malloc(vmctx: vmctx, addr: pointer, len: usize) -> Result<(), AccessError>; - /// Memcheck invoked when free is called. - check_free(vmctx: vmctx, addr: pointer) -> -> Result<(), AccessError>; + // Memcheck invoked when malloc is called. + // check_malloc(vmctx: vmctx, addr: pointer, len: usize) -> Result<(), AccessError>; + // Memcheck invoked when free is called. + // check_free(vmctx: vmctx, addr: pointer) -> -> Result<(), AccessError>; } }; } diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index c9ccca91a206..9d8339697254 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -32,7 +32,7 @@ use wasmtime_environ::{ GlobalInit, HostPtr, MemoryIndex, Module, PrimaryMap, SignatureIndex, TableIndex, TableInitialValue, Trap, VMOffsets, WasmHeapType, WasmRefType, WasmType, VMCONTEXT_MAGIC, }; -use crate::wasm_valgrind::Valgrind; +// use crate::wasm_valgrind::Valgrind; mod allocator; @@ -146,7 +146,7 @@ pub struct Instance { /// end of the struct (similar to a flexible array member). vmctx: VMContext, - valgrind_state: Valgrind, + // valgrind_state: Valgrind, } #[allow(clippy::cast_ptr_alignment)] @@ -189,6 +189,8 @@ impl Instance { vmctx: VMContext { _marker: std::marker::PhantomPinned, }, + // valgrind_state: Valgrind::new(1024 * 640, 1024), // dummy data + //not sure how to access mem & stack size? }, ); diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index c0fe226292a9..e683edb2f1d4 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -67,7 +67,7 @@ use std::time::{Duration, Instant}; use wasmtime_environ::{ DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Trap, }; -use crate::wasm_valgrind::Valgrind; +// use crate::wasm_valgrind::AccessError; /// Actually public trampolines which are used by the runtime as the entrypoint /// for libcalls. @@ -492,15 +492,15 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { // * is there a good way to cast a pointer to usize? or should the library be modified to take pointer // arguments instead? -unsafe fn check_malloc(instance: &mut Instance, addr: pointer, len: usize) -> Result<(), AccessError> { - let addr_usize; - instance::valgrind_state::malloc(addr_usize, len) -} - -unsafe fn check_free(instance: &mut Instance, addr: pointer) -> Result<(), AccessError> { - let addr_usize; - instance::valgrind_state::free(addr_usize) -} +// unsafe fn check_malloc(instance: &mut Instance, addr: pointer, len: usize) -> Result<(), AccessError> { +// let addr_usize; +// instance::valgrind_state::malloc(addr_usize, len) +// } + +// unsafe fn check_free(instance: &mut Instance, addr: pointer) -> Result<(), AccessError> { +// let addr_usize; +// instance::valgrind_state::free(addr_usize) +// } /// This module contains functions which are used for resolving relocations at /// runtime if necessary. From 77d72b27b93bda27a5c3be42872a7d13ae42e772 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 17 Jul 2023 09:15:54 -0700 Subject: [PATCH 04/34] fix doc comment --- crates/runtime/src/libcalls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index e683edb2f1d4..e96df466d638 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -9,8 +9,8 @@ //! //! * They must only contain basic, raw i32/i64/f32/f64/pointer parameters that //! are safe to pass across the system ABI. -/// is the above something that should be taken into account? check_malloc -/// takes usize as the type for its len arg +//! TODO(ssunkin): is the above something that should be taken into account? check_malloc takes +//! usize as the type for its len arg //! //! * If any nested function propagates an `Err(trap)` out to the library //! function frame, we need to raise it. This involves some nasty and quite From ebda2a29a591f9516c34ccab450079e666c9e70f Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 17 Jul 2023 09:59:17 -0700 Subject: [PATCH 05/34] libcalls build now!!!! --- crates/environ/src/builtin.rs | 9 +++++---- crates/runtime/src/libcalls.rs | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 49309729204b..60f19685dde9 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -51,10 +51,11 @@ macro_rules! foreach_builtin_function { out_of_gas(vmctx: vmctx); /// Invoked when we reach a new epoch. new_epoch(vmctx: vmctx) -> i64; - // Memcheck invoked when malloc is called. - // check_malloc(vmctx: vmctx, addr: pointer, len: usize) -> Result<(), AccessError>; - // Memcheck invoked when free is called. - // check_free(vmctx: vmctx, addr: pointer) -> -> Result<(), AccessError>; + /// Memcheck invoked when malloc is called. + /// TODO: can we even pass a usize thing here??? + check_malloc(vmctx: vmctx, addr: pointer, len: i32) -> i32; + /// Memcheck invoked when free is called. + check_free(vmctx: vmctx, addr: pointer) -> i32; } }; } diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index e96df466d638..63a641a54a8e 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -492,15 +492,25 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { // * is there a good way to cast a pointer to usize? or should the library be modified to take pointer // arguments instead? -// unsafe fn check_malloc(instance: &mut Instance, addr: pointer, len: usize) -> Result<(), AccessError> { +unsafe fn check_malloc(instance: &mut Instance, addr: *const u8, len: u32) -> Result { // let addr_usize; // instance::valgrind_state::malloc(addr_usize, len) -// } + panic!("pretend we called valgrind_state.free()"); + /* + let result: Result<(), AccessError> = panic!("pretend we called valgrind_state.free()"); + result.to_int() + */ +} -// unsafe fn check_free(instance: &mut Instance, addr: pointer) -> Result<(), AccessError> { +unsafe fn check_free(instance: &mut Instance, addr: *const u8) -> Result { // let addr_usize; // instance::valgrind_state::free(addr_usize) -// } + panic!("pretend we called valgrind_state.free()"); + /* + let result: Result<(), AccessError> = panic!("pretend we called valgrind_state.free()"); + result.to_int() + */ +} /// This module contains functions which are used for resolving relocations at /// runtime if necessary. From f9620785cba89cbefb7a6d42f720ec151133c3a3 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 17 Jul 2023 10:52:11 -0700 Subject: [PATCH 06/34] initial check_malloc_exit setup --- .gitmodules | 2 +- Cargo.toml | 3 +- cranelift/wasm/src/code_translator.rs | 2 +- crates/cranelift/src/func_environ.rs | 64 ++++++++++++++++----------- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/.gitmodules b/.gitmodules index 787cb073b831..472875e1ae35 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,4 +25,4 @@ branch = prod/testsuite-base [submodule "wasm-valgrind"] path = wasm-valgrind - url = https://github.com/ssunkin-fastly/wasm-valgrind + url = https://github.com/ssunkin-fastly/wasm-valgrind.git diff --git a/Cargo.toml b/Cargo.toml index a6c5a7024b55..d3781d92ee9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -113,7 +113,8 @@ members = [ ] exclude = [ 'crates/wasi-common/WASI/tools/witx-cli', - 'docs/rust_wasi_markdown_parser' + 'docs/rust_wasi_markdown_parser', + 'wasm-valgrind', ] [workspace.package] diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 4aac309ba321..a7adb05fb83f 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -589,7 +589,7 @@ pub fn translate_operator( { let return_args = state.peekn_mut(return_count); // println!("{:?}", return_args); - //handle_before_return(&return_args); + handle_before_return(&return_args, panic!("index?"), builder); // curr error: handle_before_return not in scope bitcast_wasm_returns(environ, return_args, builder); builder.ins().return_(return_args); diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 78410118911d..6b0ffa4e4df2 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -110,6 +110,8 @@ pub struct FuncEnvironment<'module_environment> { module: &'module_environment Module, types: &'module_environment ModuleTypes, + translation: &'module_environment ModuleTranslation<'module_environment>, + /// Heaps implementing WebAssembly linear memories. heaps: PrimaryMap, @@ -172,6 +174,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { isa, module: &translation.module, types, + translation, heaps: PrimaryMap::default(), vmctx: None, builtin_function_signatures, @@ -665,31 +668,42 @@ impl<'module_environment> FuncEnvironment<'module_environment> { // is called? or does fn vmctx() need to be called? // // * is it correct to use builder as an argument here? - // fn handle_before_return(&mut self, retvals: &[Value], builder: &mut FunctionBuilder) { - // let block = builder.func.entry_block().unwrap(); - // let args = builder.func.dfg.block_params(block, 0); - // if "the function is malloc" { - // builder - // .ins() - // .call_indirect(check_malloc_exit, &[self.vmctx, retvals[0], args[0]]); - // } else if "the function is free" { - // builder - // .ins() - // .call_indirect(check_free_exit, &[self.vmctx]); - // } - // valgrind_state.flag = false; - // } - - // fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder) { - // let check_malloc_sig = self.builtin_function_signatures.check_malloc(builder.func); - // let (vmctx, check_malloc) = self.translate_load_builtin_function_address( - // &mut builder.cursor(), - // BuiltinFunctionIndex::check_malloc(), - // ); - // builder - // .ins() - // .call_indirect(check_malloc_sig, check_malloc, &[vmctx, pointer, usize]); - // } + fn handle_before_return(&mut self, retvals: &[crate::ir::Value], func_index: FuncIndex, builder: &mut FunctionBuilder) { + let block = builder.func.layout.entry_block().unwrap(); + let args = builder.func.dfg.block_params(block); + let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; + // there is also dlmalloc, realloc, calloc, etc; should these be checked for too? + + if func_name == "malloc" { + self.check_malloc_exit(builder); + /* + builder + ins() + .call_indirect(check_malloc_exit_addr, &[self.vmctx, retvals[0], args[0]]); + */ + } else if func_name == "free" { + /* + builder + .ins() + .call_indirect(check_free_exit, &[self.vmctx]); + */ + } + // TODO: signal something to valgrind state that we're in a function or somethign??? + // valgrind_state.flag = false; + } + + fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder) { + let check_malloc_sig = self.builtin_function_signatures.check_malloc(builder.func); + let (vmctx, check_malloc) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_malloc(), + ); + let pointer = panic!("we can get the pointer somehow"); + let size = panic!("we can get the length somehow"); + builder + .ins() + .call_indirect(check_malloc_sig, check_malloc, &[vmctx, pointer, size]); + } // fn check_free_exit(&mut self, builder: &mut FunctionBuilder) { // let check_free_sig = self.builtin_function_signatures.check_free(builder.func); From 18389d7556ef8518edf45a839ee4f493cbcd79d1 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Mon, 17 Jul 2023 11:19:02 -0700 Subject: [PATCH 07/34] WIP: load/store hooks --- cranelift/wasm/src/code_translator.rs | 40 ++++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index a7adb05fb83f..0406ef31992c 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -793,7 +793,7 @@ pub fn translate_operator( ); } Operator::V128Load8x8S { memarg } => { - let (flags, base) = unwrap_or_return_unreachable_state!( + let (flags, _, base) = unwrap_or_return_unreachable_state!( state, prepare_addr(memarg, 8, builder, state, environ)? ); @@ -801,7 +801,7 @@ pub fn translate_operator( state.push1(loaded); } Operator::V128Load8x8U { memarg } => { - let (flags, base) = unwrap_or_return_unreachable_state!( + let (flags, _, base) = unwrap_or_return_unreachable_state!( state, prepare_addr(memarg, 8, builder, state, environ)? ); @@ -809,7 +809,7 @@ pub fn translate_operator( state.push1(loaded); } Operator::V128Load16x4S { memarg } => { - let (flags, base) = unwrap_or_return_unreachable_state!( + let (flags, _, base) = unwrap_or_return_unreachable_state!( state, prepare_addr(memarg, 8, builder, state, environ)? ); @@ -817,7 +817,7 @@ pub fn translate_operator( state.push1(loaded); } Operator::V128Load16x4U { memarg } => { - let (flags, base) = unwrap_or_return_unreachable_state!( + let (flags, _, base) = unwrap_or_return_unreachable_state!( state, prepare_addr(memarg, 8, builder, state, environ)? ); @@ -825,7 +825,7 @@ pub fn translate_operator( state.push1(loaded); } Operator::V128Load32x2S { memarg } => { - let (flags, base) = unwrap_or_return_unreachable_state!( + let (flags, _, base) = unwrap_or_return_unreachable_state!( state, prepare_addr(memarg, 8, builder, state, environ)? ); @@ -833,7 +833,7 @@ pub fn translate_operator( state.push1(loaded); } Operator::V128Load32x2U { memarg } => { - let (flags, base) = unwrap_or_return_unreachable_state!( + let (flags, _, base) = unwrap_or_return_unreachable_state!( state, prepare_addr(memarg, 8, builder, state, environ)? ); @@ -2574,13 +2574,15 @@ fn translate_unreachable_operator( /// heap address if execution reaches that point. /// /// Returns `None` when the Wasm access will unconditionally trap. +/// +/// Returns `(flags, wasm_addr, native_addr)`. fn prepare_addr( memarg: &MemArg, access_size: u8, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, environ: &mut FE, -) -> WasmResult> +) -> WasmResult> where FE: FuncEnvironment + ?Sized, { @@ -2730,7 +2732,7 @@ where // vmctx, stack) accesses. flags.set_heap(); - Ok(Reachability::Reachable((flags, addr))) + Ok(Reachability::Reachable((flags, index, addr))) } fn align_atomic_addr( @@ -2777,7 +2779,7 @@ fn prepare_atomic_addr( builder: &mut FunctionBuilder, state: &mut FuncTranslationState, environ: &mut FE, -) -> WasmResult> { +) -> WasmResult> { align_atomic_addr(memarg, loaded_bytes, builder, state); prepare_addr(memarg, loaded_bytes, builder, state, environ) } @@ -2809,7 +2811,7 @@ fn translate_load( state: &mut FuncTranslationState, environ: &mut FE, ) -> WasmResult> { - let (flags, base) = match prepare_addr( + let (flags, wasm_index, base) = match prepare_addr( memarg, mem_op_size(opcode, result_ty), builder, @@ -2817,8 +2819,11 @@ fn translate_load( environ, )? { Reachability::Unreachable => return Ok(Reachability::Unreachable), - Reachability::Reachable((f, b)) => (f, b), + Reachability::Reachable((f, i, b)) => (f, i, b), }; + + // TODO: Add a call: wasmtime_valgrind_load_hook(vmctx, wasm_index, memarg.offset) + let (load, dfg) = builder .ins() .Load(opcode, result_ty, flags, Offset32::new(0), base); @@ -2837,10 +2842,13 @@ fn translate_store( let val = state.pop1(); let val_ty = builder.func.dfg.value_type(val); - let (flags, base) = unwrap_or_return_unreachable_state!( + let (flags, wasm_index, base) = unwrap_or_return_unreachable_state!( state, prepare_addr(memarg, mem_op_size(opcode, val_ty), builder, state, environ)? ); + + // TODO: add call to wasmtime_valgrind_store_hook(vmctx, wasm_index, memarg.offset) + builder .ins() .Store(opcode, val_ty, flags, Offset32::new(0), val, base); @@ -2897,7 +2905,7 @@ fn translate_atomic_rmw( arg2 = builder.ins().ireduce(access_ty, arg2); } - let (flags, addr) = unwrap_or_return_unreachable_state!( + let (flags, _, addr) = unwrap_or_return_unreachable_state!( state, prepare_atomic_addr( memarg, @@ -2954,7 +2962,7 @@ fn translate_atomic_cas( replacement = builder.ins().ireduce(access_ty, replacement); } - let (flags, addr) = unwrap_or_return_unreachable_state!( + let (flags, _, addr) = unwrap_or_return_unreachable_state!( state, prepare_atomic_addr( memarg, @@ -2997,7 +3005,7 @@ fn translate_atomic_load( }; assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes()); - let (flags, addr) = unwrap_or_return_unreachable_state!( + let (flags, _, addr) = unwrap_or_return_unreachable_state!( state, prepare_atomic_addr( memarg, @@ -3046,7 +3054,7 @@ fn translate_atomic_store( data = builder.ins().ireduce(access_ty, data); } - let (flags, addr) = unwrap_or_return_unreachable_state!( + let (flags, _, addr) = unwrap_or_return_unreachable_state!( state, prepare_atomic_addr( memarg, From 4e713b1253e6947a723dc7da9b559f0149cf011d Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Wed, 19 Jul 2023 13:50:12 -0700 Subject: [PATCH 08/34] hooks added + building --- cranelift/wasm/src/code_translator.rs | 15 +-- cranelift/wasm/src/environ/spec.rs | 10 ++ cranelift/wasm/src/func_translator.rs | 1 + crates/cranelift/src/func_environ.rs | 167 +++++++++++++++++--------- crates/environ/src/builtin.rs | 13 +- crates/runtime/src/instance.rs | 3 +- crates/runtime/src/libcalls.rs | 40 ++++-- 7 files changed, 166 insertions(+), 83 deletions(-) diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 0406ef31992c..235ff4d29a3d 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -588,9 +588,7 @@ pub fn translate_operator( }; { let return_args = state.peekn_mut(return_count); - // println!("{:?}", return_args); - handle_before_return(&return_args, panic!("index?"), builder); - // curr error: handle_before_return not in scope + environ.handle_before_return(&return_args, builder); bitcast_wasm_returns(environ, return_args, builder); builder.ins().return_(return_args); } @@ -698,11 +696,7 @@ pub fn translate_operator( * Wasm specifies an integer alignment flag but we drop it in Cranelift. * The memory base address is provided by the environment. ************************************************************************************/ - - // there's quite a few different types loads loads; should each of them be individually - // wrapped in an if statement checking if the valgrind flag is on? - // If so, how would the Instance be accessed free - Operator::I32Load8U { memarg } => { + Operator::I32Load8U { memarg } => { unwrap_or_return_unreachable_state!( state, translate_load(memarg, ir::Opcode::Uload8, I32, builder, state, environ)? @@ -2821,9 +2815,11 @@ fn translate_load( Reachability::Unreachable => return Ok(Reachability::Unreachable), Reachability::Reachable((f, i, b)) => (f, i, b), }; - + // TODO: Add a call: wasmtime_valgrind_load_hook(vmctx, wasm_index, memarg.offset) + environ.before_load(builder, wasm_index, memarg.offset); + let (load, dfg) = builder .ins() .Load(opcode, result_ty, flags, Offset32::new(0), base); @@ -2848,6 +2844,7 @@ fn translate_store( ); // TODO: add call to wasmtime_valgrind_store_hook(vmctx, wasm_index, memarg.offset) + environ.before_store(builder, wasm_index, memarg.offset); builder .ins() diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index d20491abc8f5..7c6c5743caff 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -587,6 +587,16 @@ pub trait FuncEnvironment: TargetEnvironment { fn use_x86_pmaddubsw_for_dot(&self) -> bool { false } + + /// + fn handle_before_return(&mut self, retvals: &[ir::Value], builder: &mut FunctionBuilder) {} + + /// + // Type::bytes (?) + fn before_load(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) {} + + /// + fn before_store(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) {} } /// An object satisfying the `ModuleEnvironment` trait can be passed as argument to the diff --git a/cranelift/wasm/src/func_translator.rs b/cranelift/wasm/src/func_translator.rs index e99989010fe2..b290ed117897 100644 --- a/cranelift/wasm/src/func_translator.rs +++ b/cranelift/wasm/src/func_translator.rs @@ -275,6 +275,7 @@ fn parse_function_body( // generate a return instruction that doesn't match the signature. if state.reachable { if !builder.is_unreachable() { + environ.handle_before_return(&state.stack, builder); bitcast_wasm_returns(environ, &mut state.stack, builder); builder.ins().return_(&state.stack); } diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 6b0ffa4e4df2..501739bdc224 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -3,7 +3,7 @@ use cranelift_codegen::ir; use cranelift_codegen::ir::condcodes::*; use cranelift_codegen::ir::immediates::{Imm64, Offset32, Uimm64}; use cranelift_codegen::ir::types::*; -use cranelift_codegen::ir::{AbiParam, ArgumentPurpose, Function, InstBuilder, Signature}; +use cranelift_codegen::ir::{AbiParam, ArgumentPurpose, Function, InstBuilder, Signature, Value, UserFuncName}; use cranelift_codegen::isa::{self, CallConv, TargetFrontendConfig, TargetIsa}; use cranelift_entity::{EntityRef, PrimaryMap}; use cranelift_frontend::FunctionBuilder; @@ -174,7 +174,6 @@ impl<'module_environment> FuncEnvironment<'module_environment> { isa, module: &translation.module, types, - translation, heaps: PrimaryMap::default(), vmctx: None, builtin_function_signatures, @@ -184,6 +183,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { epoch_deadline_var: Variable::new(0), epoch_ptr_var: Variable::new(0), vmruntime_limits_ptr: Variable::new(0), + translation: translation, // Start with at least one fuel being consumed because even empty // functions should consume at least some fuel. @@ -196,6 +196,8 @@ impl<'module_environment> FuncEnvironment<'module_environment> { } fn vmctx(&mut self, func: &mut Function) -> ir::GlobalValue { + //arbitrarily printing funcname/index from inside func_environ + // println!("from vmctx {:?}", self.translation.debuginfo.name_section.func_names); self.vmctx.unwrap_or_else(|| { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); self.vmctx = Some(vmctx); @@ -653,68 +655,29 @@ impl<'module_environment> FuncEnvironment<'module_environment> { self.epoch_check(builder); } - // * I'm not sure if it's correct to pass instance as an argument - // here, as I've only seen Instance used in libcalls.rs; however, - // I wasn't sure how else to access the Valgrind state - // - // * when/where are these hooks actually called? - // fn handle_after_entry(&mut self) { - // if "the function is malloc" { - // // valgrind_state.flag = true; - // } - // } - - // * is self.vmctx already initialized by the time this function - // is called? or does fn vmctx() need to be called? - // - // * is it correct to use builder as an argument here? - fn handle_before_return(&mut self, retvals: &[crate::ir::Value], func_index: FuncIndex, builder: &mut FunctionBuilder) { - let block = builder.func.layout.entry_block().unwrap(); - let args = builder.func.dfg.block_params(block); - let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; - // there is also dlmalloc, realloc, calloc, etc; should these be checked for too? - - if func_name == "malloc" { - self.check_malloc_exit(builder); - /* - builder - ins() - .call_indirect(check_malloc_exit_addr, &[self.vmctx, retvals[0], args[0]]); - */ - } else if func_name == "free" { - /* - builder - .ins() - .call_indirect(check_free_exit, &[self.vmctx]); - */ - } - // TODO: signal something to valgrind state that we're in a function or somethign??? - // valgrind_state.flag = false; - } - - fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder) { + fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder, retvals: &[Value]) { let check_malloc_sig = self.builtin_function_signatures.check_malloc(builder.func); let (vmctx, check_malloc) = self.translate_load_builtin_function_address( &mut builder.cursor(), BuiltinFunctionIndex::check_malloc(), ); - let pointer = panic!("we can get the pointer somehow"); - let size = panic!("we can get the length somehow"); + let len = builder.func.dfg.block_params(builder.func.layout.entry_block().unwrap())[2]; builder .ins() - .call_indirect(check_malloc_sig, check_malloc, &[vmctx, pointer, size]); + .call_indirect(check_malloc_sig, check_malloc, &[vmctx, retvals[0], len]); } - // fn check_free_exit(&mut self, builder: &mut FunctionBuilder) { - // let check_free_sig = self.builtin_function_signatures.check_free(builder.func); - // let (vmctx, check_free) = self.translate_load_builtin_function_address( - // &mut builder.cursor(), - // BuiltinFunctionIndex::check_free(), - // ); - // builder - // .ins() - // .call_indirect(check_free_sig, check_free, &[vmctx, pointer]); - // } + fn check_free_exit(&mut self, builder: &mut FunctionBuilder) { + let check_free_sig = self.builtin_function_signatures.check_free(builder.func); + let (vmctx, check_free) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_free(), + ); + let ptr = builder.func.dfg.block_params(builder.func.layout.entry_block().unwrap())[2]; + builder + .ins() + .call_indirect(check_free_sig, check_free, &[vmctx, ptr]); + } fn epoch_ptr(&mut self, builder: &mut FunctionBuilder<'_>) -> ir::Value { let vmctx = self.vmctx(builder.func); @@ -924,6 +887,28 @@ impl<'module_environment> FuncEnvironment<'module_environment> { builder.switch_to_block(continuation_block); result_param } + + fn check_malloc_start(&mut self, builder: &mut FunctionBuilder) { + let malloc_start_sig = self.builtin_function_signatures.malloc_start(builder.func); + let (vmctx, malloc_start) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::malloc_start(), + ); + builder + .ins() + .call_indirect(malloc_start_sig, malloc_start, &[vmctx]); + } + + fn check_free_start(&mut self, builder: &mut FunctionBuilder) { + let free_start_sig = self.builtin_function_signatures.free_start(builder.func); + let (vmctx, free_start) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::free_start(), + ); + builder + .ins() + .call_indirect(free_start_sig, free_start, &[vmctx]); + } } impl TypeConvert for FuncEnvironment<'_> { @@ -2222,6 +2207,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m Ok(()) } + //insert entry hook calls here? fn before_translate_function( &mut self, builder: &mut FunctionBuilder, @@ -2240,10 +2226,22 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m if self.tunables.epoch_interruption { self.epoch_function_entry(builder); } - // - // if self.func == "malloc" { //psuedocode - // self.check_malloc_entry(); - // } + + let func_index = match &builder.func.name { + UserFuncName::User(user) => { + FuncIndex::from_u32(user.index) + } + _ => { + unreachable!() + } + }; + let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; + if func_name == "malloc" { + self.check_malloc_start(builder); + } else if func_name == "free" { + self.check_free_start(builder); + } + Ok(()) } @@ -2285,4 +2283,55 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m fn use_x86_pmaddubsw_for_dot(&self) -> bool { self.isa.has_x86_pmaddubsw_lowering() } + + fn handle_before_return( + &mut self, + retvals: &[Value], + builder: &mut FunctionBuilder, + ) { + let block = builder.func.layout.entry_block().unwrap(); + let args = builder.func.dfg.block_params(block); + let func_index = match &builder.func.name { + UserFuncName::User(user) => { + FuncIndex::from_u32(user.index) + } + _ => { + unreachable!() + } + }; + let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; + // println!("name: {}, index: {:?}", func_name, func_index); + if func_name == "malloc" { + self.check_malloc_exit(builder, retvals); + } else if func_name == "free" { + self.check_free_exit(builder); + } + // instance.valgrind_on = false; + } + + fn before_load(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) { + let check_load_sig = self.builtin_function_signatures.check_load(builder.func); + let (vmctx, check_load) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_load(), + ); + let num_bytes = builder.ins().iconst(I32, 1); + let offset_val = builder.ins().iconst(I64, offset as i64); + builder + .ins() + .call_indirect(check_load_sig, check_load, &[vmctx, num_bytes, addr, offset_val]); + } + + fn before_store(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) { + let check_store_sig = self.builtin_function_signatures.check_store(builder.func); + let (vmctx, check_store) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_store(), + ); + let num_bytes = builder.ins().iconst(I32, 1); + let offset_val = builder.ins().iconst(I64, offset as i64); + builder + .ins() + .call_indirect(check_store_sig, check_store, &[vmctx, num_bytes, addr, offset_val]); + } } diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 60f19685dde9..a62e1f4d0351 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -52,10 +52,17 @@ macro_rules! foreach_builtin_function { /// Invoked when we reach a new epoch. new_epoch(vmctx: vmctx) -> i64; /// Memcheck invoked when malloc is called. - /// TODO: can we even pass a usize thing here??? - check_malloc(vmctx: vmctx, addr: pointer, len: i32) -> i32; + check_malloc(vmctx: vmctx, addr: i32, len: i32) -> i32; /// Memcheck invoked when free is called. - check_free(vmctx: vmctx, addr: pointer) -> i32; + check_free(vmctx: vmctx, addr: i32) -> i32; + /// + check_load(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32); + /// + check_store(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32); + /// + malloc_start(vmctx: vmctx); + /// + free_start(vmctx: vmctx); } }; } diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index 9d8339697254..dded326ae0e3 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -145,7 +145,6 @@ pub struct Instance { /// represents a dynamically-sized array that extends beyond the nominal /// end of the struct (similar to a flexible array member). vmctx: VMContext, - // valgrind_state: Valgrind, } @@ -189,7 +188,7 @@ impl Instance { vmctx: VMContext { _marker: std::marker::PhantomPinned, }, - // valgrind_state: Valgrind::new(1024 * 640, 1024), // dummy data + // valgrind_state: Valgrind::new(memories.len(), ), //not sure how to access mem & stack size? }, ); diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 63a641a54a8e..3181afe2dfff 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -490,28 +490,48 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { (*instance.store()).new_epoch() } -// * is there a good way to cast a pointer to usize? or should the library be modified to take pointer -// arguments instead? -unsafe fn check_malloc(instance: &mut Instance, addr: *const u8, len: u32) -> Result { -// let addr_usize; -// instance::valgrind_state::malloc(addr_usize, len) - panic!("pretend we called valgrind_state.free()"); +unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { + // let addr_usize; + // instance::valgrind_state::malloc(addr_usize, len) + println!("addr: {} len: {}", addr, len); + Ok(0) + //instance.valgrind_state.malloc(addr as usize, len as usize) /* let result: Result<(), AccessError> = panic!("pretend we called valgrind_state.free()"); result.to_int() */ } -unsafe fn check_free(instance: &mut Instance, addr: *const u8) -> Result { -// let addr_usize; -// instance::valgrind_state::free(addr_usize) - panic!("pretend we called valgrind_state.free()"); +unsafe fn check_free(instance: &mut Instance, addr: u32) -> Result { + // let addr_usize; + // instance::valgrind_state::free(addr_usize) + println!("addr: {}", addr); + Ok(0) + //instance.valgrind_state.free(addr) /* let result: Result<(), AccessError> = panic!("pretend we called valgrind_state.free()"); result.to_int() */ } +fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { + // println!("load addr: {}", addr + offset); + //call valgrind read +} + +fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { + // println!("store addr: {}", addr + offset); + // valgrind write +} + +fn malloc_start(instance: &mut Instance) { + //instance.valgrind_state.flag = false; +} + +fn free_start(instance: &mut Instance) { + //instance.valgrind_state.flag = false; +} + /// This module contains functions which are used for resolving relocations at /// runtime if necessary. /// From 2586e24deee84e75024e99b70d967ae7ffee2678 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Wed, 19 Jul 2023 13:59:57 -0700 Subject: [PATCH 09/34] added valgrind library --- Cargo.lock | 4 + Cargo.toml | 1 + crates/cranelift/src/func_environ.rs | 2 +- crates/runtime/Cargo.toml | 1 + crates/runtime/src/instance.rs | 5 +- crates/valgrind/Cargo.toml | 8 + crates/valgrind/fuzz/.gitignore | 4 + crates/valgrind/fuzz/Cargo.lock | 187 +++++++++ crates/valgrind/fuzz/Cargo.toml | 34 ++ .../fuzz/fuzz_targets/buggy_accesses.rs | 218 ++++++++++ .../fuzz/fuzz_targets/valid_accesses.rs | 216 ++++++++++ crates/valgrind/src/lib.rs | 379 ++++++++++++++++++ 12 files changed, 1056 insertions(+), 3 deletions(-) create mode 100644 crates/valgrind/Cargo.toml create mode 100644 crates/valgrind/fuzz/.gitignore create mode 100644 crates/valgrind/fuzz/Cargo.lock create mode 100644 crates/valgrind/fuzz/Cargo.toml create mode 100644 crates/valgrind/fuzz/fuzz_targets/buggy_accesses.rs create mode 100644 crates/valgrind/fuzz/fuzz_targets/valid_accesses.rs create mode 100644 crates/valgrind/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 804617b3f91a..5676e247bd70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3733,6 +3733,10 @@ dependencies = [ "wat", ] +[[package]] +name = "wasm_valgrind" +version = "0.1.0" + [[package]] name = "wasmi" version = "0.20.0" diff --git a/Cargo.toml b/Cargo.toml index d3781d92ee9a..c76cb2b91c2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,6 +101,7 @@ members = [ "crates/test-programs/wasi-http-tests", "crates/test-programs/command-tests", "crates/test-programs/reactor-tests", + "crates/valgrind", "crates/wasi-preview1-component-adapter", "crates/wasi-preview1-component-adapter/verify", "crates/winch", diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 501739bdc224..cad7f1a820cd 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -20,7 +20,7 @@ use wasmtime_environ::{ BuiltinFunctionIndex, MemoryPlan, MemoryStyle, Module, ModuleTranslation, ModuleTypes, PtrSize, TableStyle, Tunables, TypeConvert, VMOffsets, WASM_PAGE_SIZE, }; -use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK}; +use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK}; // is this the right place to import Value from? macro_rules! declare_function_signatures { ( diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index 279bc0b72e3b..e272980df712 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/bytecodealliance/wasmtime" edition.workspace = true [dependencies] +wasm-valgrind = { workspace = true } wasmtime-asm-macros = { workspace = true } wasmtime-environ = { workspace = true } wasmtime-fiber = { workspace = true, optional = true } diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index dded326ae0e3..bbf38424a6f1 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -15,6 +15,7 @@ use crate::{ ExportFunction, ExportGlobal, ExportMemory, ExportTable, Imports, ModuleRuntimeInfo, SendSyncPtr, Store, VMFunctionBody, VMSharedSignatureIndex, WasmFault, }; +use wasm_valgrind::Valgrind; use anyhow::Error; use anyhow::Result; use sptr::Strict; @@ -145,7 +146,7 @@ pub struct Instance { /// represents a dynamically-sized array that extends beyond the nominal /// end of the struct (similar to a flexible array member). vmctx: VMContext, - // valgrind_state: Valgrind, + valgrind_state: Valgrind, } #[allow(clippy::cast_ptr_alignment)] @@ -188,7 +189,7 @@ impl Instance { vmctx: VMContext { _marker: std::marker::PhantomPinned, }, - // valgrind_state: Valgrind::new(memories.len(), ), + valgrind_state: Valgrind::new(1024 * 1024 * 128, 1024 * 1024), //not sure how to access mem & stack size? }, ); diff --git a/crates/valgrind/Cargo.toml b/crates/valgrind/Cargo.toml new file mode 100644 index 000000000000..0bd753ff5095 --- /dev/null +++ b/crates/valgrind/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "wasm_valgrind" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crates/valgrind/fuzz/.gitignore b/crates/valgrind/fuzz/.gitignore new file mode 100644 index 000000000000..1a45eee7760d --- /dev/null +++ b/crates/valgrind/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/crates/valgrind/fuzz/Cargo.lock b/crates/valgrind/fuzz/Cargo.lock new file mode 100644 index 000000000000..47e030785c26 --- /dev/null +++ b/crates/valgrind/fuzz/Cargo.lock @@ -0,0 +1,187 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.146" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beb09950ae85a0a94b27676cccf37da5ff13f27076aa1adbc6545dd0d0e1bd4e" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "wasm-valgrind-fuzz" +version = "0.0.0" +dependencies = [ + "libfuzzer-sys", + "rand 0.3.23", + "wasm_valgrind", +] + +[[package]] +name = "wasm_valgrind" +version = "0.1.0" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/crates/valgrind/fuzz/Cargo.toml b/crates/valgrind/fuzz/Cargo.toml new file mode 100644 index 000000000000..2171405d4738 --- /dev/null +++ b/crates/valgrind/fuzz/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "wasm-valgrind-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] } +rand="0.3.14" + +[dependencies.wasm_valgrind] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "valid_accesses" +path = "fuzz_targets/valid_accesses.rs" +test = false +doc = false + +[[bin]] +name = "buggy_accesses" +path = "fuzz_targets/buggy_accesses.rs" +test = false +doc = false \ No newline at end of file diff --git a/crates/valgrind/fuzz/fuzz_targets/buggy_accesses.rs b/crates/valgrind/fuzz/fuzz_targets/buggy_accesses.rs new file mode 100644 index 000000000000..202e67937e8d --- /dev/null +++ b/crates/valgrind/fuzz/fuzz_targets/buggy_accesses.rs @@ -0,0 +1,218 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured}; +use wasm_valgrind::{Valgrind, MemState, AccessError}; + +const TEST_MAX_ADDR: usize = 1024 * 640 - 1; +const TEST_MAX_STACK_SIZE: usize = 1024; + +fuzz_target!(|data: &[u8]| { + let u = &mut Unstructured::new(data); + let mut valgrind_state = Valgrind::new(TEST_MAX_ADDR + 1, TEST_MAX_STACK_SIZE); + let cmds = match BuggyCommandSequence::arbitrary(u) { + Ok(val) => val, + Err(_) => return, + }; + println!("commands: {:?}", cmds); + assert_eq!(cmds.commands.len(), cmds.results.len()); + for (cmd, result) in cmds.commands.iter().zip(cmds.results.iter()) { + let cmd: &Command = cmd; + match cmd { + &Command::Malloc { addr, len } => { + assert_eq!(valgrind_state.malloc(addr, len), *result); + } + &Command::Free { addr } => { + assert_eq!(valgrind_state.free(addr), *result); + } + &Command::Read { addr, len } => { + assert_eq!(valgrind_state.read(addr, len), *result); + } + &Command::Write { addr, len } => { + assert_eq!(valgrind_state.write(addr, len), *result); + } + } + } +}); + +#[derive(Debug)] +pub struct Allocation { + addr: usize, + len: usize, + memstate: Vec, +} //TODO: model the stack as an allocation + +impl Allocation { + fn new(addr: usize, len: usize) -> Allocation { + Allocation { addr: addr, len: len, memstate: vec![MemState::ValidToWrite; len] } + } + fn no_overlaps(&self, other: &Allocation) -> bool { + other.addr + other.len <= self.addr || self.addr + self.len <= other.addr + } + fn is_in_bounds(&self) -> bool { + TEST_MAX_STACK_SIZE <= self.addr && self.addr + self.len - 1 <= TEST_MAX_ADDR + } +} + +#[derive(Debug)] +pub enum Command { + Malloc {addr: usize, len: usize}, + Read {addr: usize, len: usize}, + Write {addr: usize, len: usize}, + Free {addr: usize} +} + +#[derive(Debug)] +struct BuggyCommandSequence { + commands: Vec, + results: Vec> +} + +struct BuggyCommandSequenceState { + allocations: Vec, +} + +impl BuggyCommandSequenceState { + fn new() -> BuggyCommandSequenceState { + let allocations = Vec::new(); + BuggyCommandSequenceState { allocations } + } + fn update(&mut self, cmd: &Command) { + match cmd { + &Command::Malloc { addr, len } => { + let alloc = Allocation::new(addr, len); + let validity = is_malloc_valid(&alloc, &self); + if validity.is_ok() { + self.allocations.push(Allocation::new(addr, len)); + } + } + &Command::Free { addr } => { + let validity = is_free_valid(addr, &self); + if validity.is_ok() { + let index = self.allocations.iter().position(|alloc| alloc.addr == addr).unwrap(); + self.allocations.remove(index); + } + } + &Command::Write { addr, len } => { + let validity = is_write_valid(addr, len, &self); + if validity.is_ok() { + let index = self.allocations.iter().position(|alloc| alloc.addr <= addr && addr + len <= alloc.addr + alloc.len).unwrap(); + let alloc_addr = self.allocations[index].addr; + let write_to = &mut self.allocations[index].memstate; + for i in 0..len { + write_to[addr - alloc_addr + i] = MemState::ValidToReadWrite; + } + } + } + _ => {} + } + } +} + + +impl<'a> Arbitrary<'a> for BuggyCommandSequence { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let mut commands = vec![]; + let mut results = vec![]; + let mut state = BuggyCommandSequenceState::new(); + for _ in 0..u.int_in_range(1..=20)? { + let cmd = match u.int_in_range(0..=3)? { + 0 => { + let malloc_addr = u.int_in_range(1..=TEST_MAX_ADDR)?; + let malloc_len = u.int_in_range(1..=TEST_MAX_ADDR)?; + let alloc = Allocation::new(malloc_addr, malloc_len); + results.push(is_malloc_valid(&alloc, &state)); + Command::Malloc { addr: malloc_addr, len: malloc_len } + } + 1 => { + let choose_rand_addr = u.ratio(1, 2)?; + let mut unalloc_addr = 0; + if choose_rand_addr { + unalloc_addr = u.choose_index(TEST_MAX_ADDR)?; + } else { + let some_alloc = u.choose_index(state.allocations.len())?; + unalloc_addr = state.allocations[some_alloc].addr; + } + results.push(is_free_valid(unalloc_addr, &state)); + Command::Free { addr: unalloc_addr } + } + 2 => { + let read_addr = u.choose_index(TEST_MAX_ADDR)?; + let read_len = u.int_in_range(1..=TEST_MAX_ADDR)?; + results.push(is_read_valid(read_addr, read_len, &state)); + Command::Read { addr: read_addr, len: read_len } + } + 3 => { + let write_addr = u.choose_index(TEST_MAX_ADDR)?; + let write_len = u.int_in_range(1..=TEST_MAX_ADDR)?; + results.push(is_write_valid(write_addr, write_len, &state)); + Command::Write { addr: write_addr, len: write_len } + } + _ => { + unreachable!() + } + }; + // println!("{:?} allocs: {:?} resutls: {:?}", cmd, state.allocations, results); + state.update(&cmd); + commands.push(cmd); + } + Ok(BuggyCommandSequence { commands, results }) + } +} + +fn no_allocs_in_range(state: &BuggyCommandSequenceState, other: &Allocation ) -> bool { + state.allocations.iter().all(|alloc| alloc.no_overlaps(other)) +} + +fn is_malloc_valid(alloc: &Allocation, state: &BuggyCommandSequenceState) -> Result<(), AccessError> { + if !alloc.is_in_bounds() { + return Err(AccessError::OutOfBounds { addr: alloc.addr, len: alloc.len }); + } else if !no_allocs_in_range(&state, &alloc) { + return Err(AccessError::DoubleMalloc { addr: alloc.addr, len: alloc.len }); + } else { + return Ok(()); + } +} + +fn is_free_valid(addr: usize, state: &BuggyCommandSequenceState) -> Result<(), AccessError> { + if !state.allocations.iter().any(|alloc| alloc.addr == addr) { + return Err(AccessError::InvalidFree { addr }); + } else { + return Ok(()); + } +} + +fn is_read_valid(addr: usize, len: usize, state: &BuggyCommandSequenceState) -> Result<(), AccessError> { + let dummy = Allocation::new(addr, len); + if !dummy.is_in_bounds() { + return Err(AccessError::OutOfBounds { addr, len }); + } + let in_range: Vec<_> = state.allocations.iter() + .filter(|alloc| alloc.addr <= addr && + addr + len <= alloc.addr + alloc.len && alloc.memstate.contains(&MemState::ValidToReadWrite)).collect(); + if in_range.is_empty() { + return Err(AccessError::InvalidRead { addr, len }); + } else { + let memstate_addr = addr - &in_range[0].addr; + for i in memstate_addr..memstate_addr + len { + // println!("{:?}", mem_index); + if in_range[0].memstate[i] != MemState::ValidToReadWrite { + return Err(AccessError::InvalidRead { addr, len }); + } + } + return Ok(()); + } +} + +fn is_write_valid(addr: usize, len: usize, state: &BuggyCommandSequenceState) -> Result<(), AccessError> { + let dummy = Allocation::new(addr, len); + //this doesn't include stack... have to change to include validity for stack read/writes + if !dummy.is_in_bounds() { + return Err(AccessError::OutOfBounds { addr, len }); + } + if !state.allocations.iter().any(|alloc| alloc.addr <= addr && addr + len <= alloc.addr + alloc.len) { + return Err(AccessError::InvalidWrite { addr, len }); + } else { + return Ok(()); + } +} \ No newline at end of file diff --git a/crates/valgrind/fuzz/fuzz_targets/valid_accesses.rs b/crates/valgrind/fuzz/fuzz_targets/valid_accesses.rs new file mode 100644 index 000000000000..8b3d6e0c1a99 --- /dev/null +++ b/crates/valgrind/fuzz/fuzz_targets/valid_accesses.rs @@ -0,0 +1,216 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured, Error}; +use wasm_valgrind::{Valgrind, MemState}; +use std::cmp::*; + +const TEST_MAX_ADDR: usize = 1024 * 640 - 1; +const TEST_MAX_STACK_SIZE: usize = 1024; + +fuzz_target!(|data: &[u8]| { + let u = &mut Unstructured::new(data); + let mut valgrind_state = Valgrind::new(TEST_MAX_ADDR + 1, TEST_MAX_STACK_SIZE); + let cmds = match CommandSequence::arbitrary(u) { + Ok(val) => val, + Err(_) => return, + }; + println!("commands: {:?}", cmds); + for cmd in cmds.commands.iter() { + let cmd: &Command = cmd; + match cmd { + &Command::Malloc { addr, len } => { + assert!(valgrind_state.malloc(addr, len).is_ok()); + } + &Command::Free { addr } => { + assert!(valgrind_state.free(addr).is_ok()); + } + &Command::Read { addr, len } => { + assert!(valgrind_state.read(addr, len).is_ok()); + } + &Command::Write { addr, len } => { + assert!(valgrind_state.write(addr, len).is_ok()); + } + } + } +}); + +#[derive(Debug)] +pub struct Allocation { + addr: usize, + len: usize, + memstate: Vec, +} + +impl Allocation { + fn new(addr: usize, len: usize) -> Allocation { + Allocation { addr: addr, len: len, memstate: vec![MemState::ValidToWrite; len] } + } + fn no_overlaps(&self, other: &Allocation) -> bool { + other.addr + other.len <= self.addr || self.addr + self.len <= other.addr + } + fn is_in_bounds(&self) -> bool { + TEST_MAX_STACK_SIZE <= self.addr && self.addr + self.len - 1 <= TEST_MAX_ADDR + } +} + +#[derive(Debug)] +enum Command { + Malloc {addr: usize, len: usize}, + Read {addr: usize, len: usize}, + Write {addr: usize, len: usize}, + Free {addr: usize} +} + +#[derive(Debug)] +struct CommandSequence { + commands: Vec, +} + +struct CommandSequenceState { + allocations: Vec, +} + +impl CommandSequenceState { + fn new() -> CommandSequenceState { + let allocations = Vec::new(); + CommandSequenceState { allocations } + } + fn update(&mut self, cmd: &Command) { + match cmd { + &Command::Malloc { addr, len } => { + self.allocations.push(Allocation::new(addr, len)); + } + &Command::Free { addr } => { + let index = self.allocations.iter().position(|alloc| alloc.addr == addr).unwrap(); + self.allocations.remove(index); + } + &Command::Write { addr, len } => { + let index = self.allocations.iter().position(|alloc| alloc.addr <= addr && addr + len <= alloc.addr + alloc.len).unwrap(); + let alloc_addr = self.allocations[index].addr; + let write_to = &mut self.allocations[index].memstate; + for i in 0..len { + write_to[addr - alloc_addr + i] = MemState::ValidToReadWrite; + } + } + _ => {} + } + } + } + +impl<'a> Arbitrary<'a> for CommandSequence { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let mut commands = vec![]; + let mut state = CommandSequenceState::new(); + for _ in 0..u.arbitrary::()? { + let cmd = match u.int_in_range(0..=3)? { + 0 => { + let malloc_range = pick_free_addr_range(&state, u)?; + Command::Malloc { addr: malloc_range.0, len: malloc_range.1 } + } + 1 => { + let unalloc_index = u.choose_index(state.allocations.len())?; + let unalloc_addr = state.allocations[unalloc_index].addr; + Command::Free { addr: unalloc_addr } + } + 2 => { + let read_range = pick_read_range(&state, u)?; + Command::Read { addr: read_range.0, len: read_range.1 } + } + 3 => { + let write_index = u.choose_index(state.allocations.len())?; + let mut write_range = 1; + if state.allocations[write_index].len > 1 { + write_range = u.int_in_range(1..=state.allocations[write_index].len)?; + } + Command::Write { addr: state.allocations[write_index].addr, len: write_range } + } + _ => { + unreachable!() + } + }; + println!("{:?}", cmd); + state.update(&cmd); + commands.push(cmd); + } + Ok(CommandSequence { commands }) + } +} + +fn pick_free_addr_range(state: &CommandSequenceState, u: &mut Unstructured<'_>) -> Result<(usize, usize), Error> { + let mut addr = u.int_in_range(TEST_MAX_STACK_SIZE..=TEST_MAX_ADDR)?; + let dummy_alloc = Allocation::new(addr, 1); + let mut attempts = 0; + while !no_allocs_in_range(state, &dummy_alloc) { + addr = u.int_in_range(1024..=TEST_MAX_ADDR)?; + attempts += 1; + if attempts == 10 { + return Err(Error::NotEnoughData); + } + } + let mut len = 1; + if TEST_MAX_ADDR - addr > 1 { + len = u.int_in_range(1..=TEST_MAX_ADDR - addr)?; + } + attempts = 0; + while !no_allocs_in_range(state, &Allocation::new(addr, len)) { + if TEST_MAX_ADDR - addr > 1 { + len = u.int_in_range(1..=TEST_MAX_ADDR - addr)?; + } + attempts += 1; + if attempts == 10 { + return Err(Error::NotEnoughData); + } + } + Ok((addr, len)) +} + +fn pick_read_range(state: &CommandSequenceState, u: &mut Unstructured<'_>) -> Result<(usize, usize), Error> { + if state.allocations.is_empty() { + return Err(Error::NotEnoughData); + } + let mut alloc_index = u.choose_index(state.allocations.len())?; // may error when state.allocations.len() == 1 + let mut attempts = 0; + while !state.allocations[alloc_index].memstate.contains(&MemState::ValidToReadWrite) { + alloc_index = u.choose_index(state.allocations.len())?; + attempts += 1; + if attempts == min(state.allocations.len(), 10) { + return Err(Error::NotEnoughData); + } + } + let mut memstate_addr = u.int_in_range(0..=state.allocations[alloc_index].len - 1)?; + attempts = 0; + while let MemState::ValidToWrite = state.allocations[alloc_index].memstate[memstate_addr] { + memstate_addr = u.int_in_range(0..=state.allocations[alloc_index].len - 1)?; + attempts += 1; + if attempts == 10 { + return Err(Error::NotEnoughData); + } + } + if state.allocations[alloc_index].memstate.len() - memstate_addr <= 1 { + return Ok((state.allocations[alloc_index].addr + memstate_addr, 1)); + } + let mut len = u.int_in_range(0..=state.allocations[alloc_index].memstate.len() - memstate_addr)?; + attempts = 0; + while !ok_range(state, alloc_index, memstate_addr, memstate_addr + len) { + len = u.int_in_range(0..=state.allocations[alloc_index].memstate.len() - 1)?; + attempts += 1; + if attempts == 10 { + return Err(Error::NotEnoughData); + } + } + Ok((state.allocations[alloc_index].addr + memstate_addr, len)) +} + +fn ok_range(state: &CommandSequenceState, alloc_index: usize, start: usize, end: usize) -> bool { + for i in start..end { + if let MemState::ValidToWrite = state.allocations[alloc_index].memstate[i] { + return false; + } + } + true +} + +fn no_allocs_in_range(state: &CommandSequenceState, other: &Allocation ) -> bool { + state.allocations.iter().all(|alloc| alloc.no_overlaps(other)) +} \ No newline at end of file diff --git a/crates/valgrind/src/lib.rs b/crates/valgrind/src/lib.rs new file mode 100644 index 000000000000..278f0d384dd3 --- /dev/null +++ b/crates/valgrind/src/lib.rs @@ -0,0 +1,379 @@ +/* +The following implementation assumes that the stack sits at the bottom of memory. +*/ + +use std::cmp::*; +use std::collections::HashMap; + +pub struct Valgrind { + metadata: Vec, + mallocs: HashMap, // start addr, len + stack_pointer: usize, + max_stack_size: usize, + //flag: bool, +} + +#[derive(Debug, PartialEq)] +pub enum AccessError { + DoubleMalloc { addr: usize, len: usize }, + InvalidRead { addr: usize, len: usize }, + InvalidWrite { addr: usize, len: usize }, + InvalidFree { addr: usize }, + OutOfBounds { addr: usize, len: usize }, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum MemState { + Unallocated, + ValidToWrite, + ValidToReadWrite, +} + +impl Valgrind { + pub fn new(mem_size: usize, max_stack_size: usize) -> Valgrind { + let metadata = vec![MemState::Unallocated; mem_size]; + let mallocs = HashMap::new(); + let stack_pointer = max_stack_size; + Valgrind { + metadata, + mallocs, + stack_pointer, + max_stack_size, + } + } + pub fn malloc(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { + if !self.is_in_bounds_heap(addr, len) { + return Err(AccessError::OutOfBounds { + addr: addr, + len: len, + }); + } + for i in addr..addr + len { + match self.metadata[i] { + MemState::ValidToWrite => { + return Err(AccessError::DoubleMalloc { + addr: addr, + len: len, + }); + } + MemState::ValidToReadWrite => { + return Err(AccessError::DoubleMalloc { + addr: addr, + len: len, + }); + } + _ => {} + } + } + for i in addr..addr + len { + self.metadata[i] = MemState::ValidToWrite; + } + self.mallocs.insert(addr, len); + Ok(()) + } + pub fn read(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { + if !(self.is_in_bounds_stack(addr, len) || self.is_in_bounds_heap(addr, len)) { + return Err(AccessError::OutOfBounds { + addr: addr, + len: len, + }); + } + for i in addr..addr + len { + match self.metadata[i] { + MemState::Unallocated => { + return Err(AccessError::InvalidRead { + addr: addr, + len: len, + }); + } + MemState::ValidToWrite => { + return Err(AccessError::InvalidRead { + addr: addr, + len: len, + }); + } + _ => {} + } + } + Ok(()) + } + pub fn write(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { + if !(self.is_in_bounds_stack(addr, len) || self.is_in_bounds_heap(addr, len)) { + return Err(AccessError::OutOfBounds { + addr: addr, + len: len, + }); + } + for i in addr..addr + len { + if let MemState::Unallocated = self.metadata[i] { + return Err(AccessError::InvalidWrite { + addr: addr, + len: len, + }); + } + } + for i in addr..addr + len { + self.metadata[i] = MemState::ValidToReadWrite; + } + Ok(()) + } + pub fn free(&mut self, addr: usize) -> Result<(), AccessError> { + if !self.mallocs.contains_key(&addr) { + return Err(AccessError::InvalidFree { addr: addr }); + } + let len = self.mallocs[&addr]; + for i in addr..addr + len { + if let MemState::Unallocated = self.metadata[i] { + return Err(AccessError::InvalidFree { addr: addr }); + } + } + self.mallocs.remove(&addr); + for i in addr..addr + len { + self.metadata[i] = MemState::Unallocated; + } + Ok(()) + } + fn is_in_bounds_heap(&self, addr: usize, len: usize) -> bool { + self.max_stack_size <= addr && addr + len <= self.metadata.len() + } + fn is_in_bounds_stack(&self, addr: usize, len: usize) -> bool { + self.stack_pointer <= addr && addr + len < self.max_stack_size + } + pub fn update_stack_pointer(&mut self, new_sp: usize) -> Result<(), AccessError> { + if new_sp > self.max_stack_size { + return Err(AccessError::OutOfBounds { + addr: self.stack_pointer, + len: new_sp - self.stack_pointer, + }); + } else if new_sp < self.stack_pointer { + for i in new_sp..self.stack_pointer + 1 { + // +1 to account for sp == max_stack_size (?) + self.metadata[i] = MemState::ValidToReadWrite; + } + } else { + for i in self.stack_pointer..new_sp { + self.metadata[i] = MemState::Unallocated; + } + } + self.stack_pointer = new_sp; + Ok(()) + } +} + +#[test] +fn basic_valgrind() { + let mut valgrind_state = Valgrind::new(640 * 1024, 0); + + assert!(valgrind_state.malloc(0x1000, 32).is_ok()); + assert!(valgrind_state.write(0x1000, 4).is_ok()); + assert!(valgrind_state.read(0x1000, 4).is_ok()); + assert_eq!(valgrind_state.mallocs, HashMap::from([(0x1000, 32)])); + assert!(valgrind_state.free(0x1000).is_ok()); + assert!(valgrind_state.mallocs.is_empty()); +} + +#[test] +fn read_before_initializing() { + let mut valgrind_state = Valgrind::new(640 * 1024, 0); + + assert!(valgrind_state.malloc(0x1000, 32).is_ok()); + assert_eq!( + valgrind_state.read(0x1000, 4), + Err(AccessError::InvalidRead { + addr: 0x1000, + len: 4 + }) + ); + assert!(valgrind_state.write(0x1000, 4).is_ok()); + assert!(valgrind_state.free(0x1000).is_ok()); +} + +#[test] +fn use_after_free() { + let mut valgrind_state = Valgrind::new(640 * 1024, 0); + + assert!(valgrind_state.malloc(0x1000, 32).is_ok()); + assert!(valgrind_state.write(0x1000, 4).is_ok()); + assert!(valgrind_state.write(0x1000, 4).is_ok()); + assert!(valgrind_state.free(0x1000).is_ok()); + assert_eq!( + valgrind_state.write(0x1000, 4), + Err(AccessError::InvalidWrite { + addr: 0x1000, + len: 4 + }) + ); +} + +#[test] +fn double_free() { + let mut valgrind_state = Valgrind::new(640 * 1024, 0); + + assert!(valgrind_state.malloc(0x1000, 32).is_ok()); + assert!(valgrind_state.write(0x1000, 4).is_ok()); + assert!(valgrind_state.free(0x1000).is_ok()); + assert_eq!( + valgrind_state.free(0x1000), + Err(AccessError::InvalidFree { addr: 0x1000 }) + ); +} + +#[test] +fn out_of_bounds_malloc() { + let mut valgrind_state = Valgrind::new(640 * 1024, 0); + + assert_eq!( + valgrind_state.malloc(640 * 1024, 1), + Err(AccessError::OutOfBounds { + addr: 640 * 1024, + len: 1 + }) + ); + assert_eq!( + valgrind_state.malloc(640 * 1024 - 10, 15), + Err(AccessError::OutOfBounds { + addr: 640 * 1024 - 10, + len: 15 + }) + ); + assert!(valgrind_state.mallocs.is_empty()); +} + +#[test] +fn out_of_bounds_read() { + let mut valgrind_state = Valgrind::new(640 * 1024, 0); + + assert!(valgrind_state.malloc(640 * 1024 - 24, 24).is_ok()); + assert_eq!( + valgrind_state.read(640 * 1024 - 24, 25), + Err(AccessError::OutOfBounds { + addr: 640 * 1024 - 24, + len: 25 + }) + ); +} + +#[test] +fn double_malloc() { + let mut valgrind_state = Valgrind::new(640 * 1024, 0); + + assert!(valgrind_state.malloc(0x1000, 32).is_ok()); + assert_eq!( + valgrind_state.malloc(0x1000, 32), + Err(AccessError::DoubleMalloc { + addr: 0x1000, + len: 32 + }) + ); + assert_eq!( + valgrind_state.malloc(0x1002, 32), + Err(AccessError::DoubleMalloc { + addr: 0x1002, + len: 32 + }) + ); + assert!(valgrind_state.free(0x1000).is_ok()); +} + +#[test] +fn error_type() { + let mut valgrind_state = Valgrind::new(640 * 1024, 0); + + assert!(valgrind_state.malloc(0x1000, 32).is_ok()); + assert_eq!( + valgrind_state.malloc(0x1000, 32), + Err(AccessError::DoubleMalloc { + addr: 0x1000, + len: 32 + }) + ); + assert_eq!( + valgrind_state.malloc(640 * 1024, 32), + Err(AccessError::OutOfBounds { + addr: 640 * 1024, + len: 32 + }) + ); + assert!(valgrind_state.free(0x1000).is_ok()); +} + +#[test] +fn update_sp_no_error() { + let mut valgrind_state = Valgrind::new(640 * 1024, 1024); + + assert_eq!(valgrind_state.max_stack_size, 1024); + assert!(valgrind_state.update_stack_pointer(768).is_ok()); + assert_eq!(valgrind_state.stack_pointer, 768); + assert!(valgrind_state.malloc(1024 * 2, 32).is_ok()); + assert!(valgrind_state.free(1024 * 2).is_ok()); + assert!(valgrind_state.update_stack_pointer(896).is_ok()); + assert_eq!(valgrind_state.stack_pointer, 896); + assert!(valgrind_state.update_stack_pointer(1024).is_ok()); +} + +#[test] +fn bad_stack_malloc() { + let mut valgrind_state = Valgrind::new(640 * 1024, 1024); + + assert!(valgrind_state.update_stack_pointer(0).is_ok()); + assert_eq!(valgrind_state.stack_pointer, 0); + assert_eq!( + valgrind_state.malloc(512, 32), + Err(AccessError::OutOfBounds { addr: 512, len: 32 }) + ); + assert_eq!( + valgrind_state.malloc(1022, 32), + Err(AccessError::OutOfBounds { + addr: 1022, + len: 32 + }) + ); +} + +#[test] +fn bad_stack_read_write() { + let mut valgrind_state = Valgrind::new(640 * 1024, 1024); + + assert!(valgrind_state.update_stack_pointer(512).is_ok()); + assert_eq!(valgrind_state.stack_pointer, 512); + assert_eq!( + valgrind_state.read(256, 16), + Err(AccessError::InvalidRead { addr: 256, len: 16 }) + ); + assert_eq!( + valgrind_state.write(500, 32), + Err(AccessError::InvalidWrite { addr: 500, len: 32 }) + ); +} + +#[test] +fn stack_full_empty() { + let mut valgrind_state = Valgrind::new(640 * 1024, 1024); + + assert!(valgrind_state.update_stack_pointer(0).is_ok()); + assert_eq!(valgrind_state.stack_pointer, 0); + assert!(valgrind_state.update_stack_pointer(1024).is_ok()); + assert_eq!(valgrind_state.stack_pointer, 1024) +} + +#[test] +fn stack_underflow() { + let mut valgrind_state = Valgrind::new(640 * 1024, 1024); + + assert!(valgrind_state.update_stack_pointer(800).is_ok()); + assert_eq!( + valgrind_state.update_stack_pointer(1025), + Err(AccessError::OutOfBounds { + addr: 800, + len: 225 + }) + ); + assert_eq!( + valgrind_state.update_stack_pointer(2000), + Err(AccessError::OutOfBounds { + addr: 800, + len: 1200 + }) + ); + assert_eq!(valgrind_state.stack_pointer, 800); +} From e4d7a0c78ebcd092f66b5986528897cb5b76f3d7 Mon Sep 17 00:00:00 2001 From: iximeow Date: Wed, 19 Jul 2023 14:08:10 -0700 Subject: [PATCH 10/34] made wasm-valgrind accessible in wasmtime --- Cargo.lock | 3 ++- Cargo.toml | 2 +- crates/valgrind/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5676e247bd70..a98b7f34722a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3734,7 +3734,7 @@ dependencies = [ ] [[package]] -name = "wasm_valgrind" +name = "wasm-valgrind" version = "0.1.0" [[package]] @@ -4210,6 +4210,7 @@ dependencies = [ "rand 0.8.5", "rustix", "sptr", + "wasm-valgrind", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-fiber", diff --git a/Cargo.toml b/Cargo.toml index c76cb2b91c2d..ffdba654440f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,7 +115,6 @@ members = [ exclude = [ 'crates/wasi-common/WASI/tools/witx-cli', 'docs/rust_wasi_markdown_parser', - 'wasm-valgrind', ] [workspace.package] @@ -125,6 +124,7 @@ edition = "2021" rust-version = "1.66.0" [workspace.dependencies] +wasm-valgrind = { path = "crates/valgrind", version = "0.1.0" } wasmtime = { path = "crates/wasmtime", version = "11.0.0", default-features = false } wasmtime-cache = { path = "crates/cache", version = "=11.0.0" } wasmtime-cli-flags = { path = "crates/cli-flags", version = "=11.0.0" } diff --git a/crates/valgrind/Cargo.toml b/crates/valgrind/Cargo.toml index 0bd753ff5095..da0a9553d316 100644 --- a/crates/valgrind/Cargo.toml +++ b/crates/valgrind/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "wasm_valgrind" +name = "wasm-valgrind" version = "0.1.0" edition = "2021" From adde43c2231004df32d7a02dd99a6a34d2d189c1 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Wed, 19 Jul 2023 14:16:05 -0700 Subject: [PATCH 11/34] check_malloc filled in... --- crates/runtime/src/instance.rs | 2 +- crates/runtime/src/libcalls.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index bbf38424a6f1..8f3280352ab3 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -146,7 +146,7 @@ pub struct Instance { /// represents a dynamically-sized array that extends beyond the nominal /// end of the struct (similar to a flexible array member). vmctx: VMContext, - valgrind_state: Valgrind, + pub(crate) valgrind_state: Valgrind, } #[allow(clippy::cast_ptr_alignment)] diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 3181afe2dfff..fa24d7f19de0 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -494,12 +494,12 @@ unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result = panic!("pretend we called valgrind_state.free()"); - result.to_int() - */ + let result = instance.valgrind_state.malloc(addr as usize, len as usize); + if result.is_ok() { + Ok(0) + } else { + panic!("failed") + } } unsafe fn check_free(instance: &mut Instance, addr: u32) -> Result { From 13035b1f2fd792841d80f98bea9ef507ab6ae864 Mon Sep 17 00:00:00 2001 From: iximeow Date: Wed, 19 Jul 2023 15:12:14 -0700 Subject: [PATCH 12/34] move valgrind_state to an appropriate part of instance it works!!!!! --- crates/runtime/src/instance.rs | 11 +++++++++-- crates/runtime/src/libcalls.rs | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index 8f3280352ab3..1eb210eff6b5 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -142,11 +142,12 @@ pub struct Instance { /// seems not too bad. vmctx_self_reference: SendSyncPtr, + pub(crate) valgrind_state: Valgrind, + /// Additional context used by compiled wasm code. This field is last, and /// represents a dynamically-sized array that extends beyond the nominal /// end of the struct (similar to a flexible array member). vmctx: VMContext, - pub(crate) valgrind_state: Valgrind, } #[allow(clippy::cast_ptr_alignment)] @@ -189,7 +190,13 @@ impl Instance { vmctx: VMContext { _marker: std::marker::PhantomPinned, }, - valgrind_state: Valgrind::new(1024 * 1024 * 128, 1024 * 1024), + valgrind_state: { + const MiB: usize = 1024 * 1024; // 1 MiB + // ad-hoc testing seems to show... + // TODO: how do we determine this more consistently? + const C_STACK_SIZE: usize = 128 * 1024; + Valgrind::new(128 * MiB, C_STACK_SIZE) + }, //not sure how to access mem & stack size? }, ); diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index fa24d7f19de0..6827d7f1cf79 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -493,6 +493,7 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { // let addr_usize; // instance::valgrind_state::malloc(addr_usize, len) + println!("instance is: {:p}", instance as *mut Instance); println!("addr: {} len: {}", addr, len); let result = instance.valgrind_state.malloc(addr as usize, len as usize); if result.is_ok() { From 759b12971c7cd733595925a624a6e3527c1aa143 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Wed, 19 Jul 2023 16:22:41 -0700 Subject: [PATCH 13/34] yay it's working! (?) i think?? --- crates/cranelift/src/func_environ.rs | 1 + crates/runtime/src/instance.rs | 8 ++++--- crates/runtime/src/libcalls.rs | 35 ++++++++++++++-------------- crates/valgrind/src/lib.rs | 17 +++++++++++++- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index cad7f1a820cd..0eeb895d6099 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -2317,6 +2317,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m ); let num_bytes = builder.ins().iconst(I32, 1); let offset_val = builder.ins().iconst(I64, offset as i64); + let addr_and_offset = builder.ins().iadd(offset_val, addr); builder .ins() .call_indirect(check_load_sig, check_load, &[vmctx, num_bytes, addr, offset_val]); diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index 1eb210eff6b5..a6c5db4a4be8 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -194,10 +194,12 @@ impl Instance { const MiB: usize = 1024 * 1024; // 1 MiB // ad-hoc testing seems to show... // TODO: how do we determine this more consistently? - const C_STACK_SIZE: usize = 128 * 1024; - Valgrind::new(128 * MiB, C_STACK_SIZE) + const C_STACK_SIZE: usize = 70863; + let mut valg = Valgrind::new(128 * MiB, C_STACK_SIZE); + valg.update_stack_pointer(0); + valg }, - //not sure how to access mem & stack size? + // not sure how to access mem & stack size? }, ); diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 6827d7f1cf79..f7eefc37f470 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -491,11 +491,9 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { } unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { - // let addr_usize; - // instance::valgrind_state::malloc(addr_usize, len) - println!("instance is: {:p}", instance as *mut Instance); println!("addr: {} len: {}", addr, len); let result = instance.valgrind_state.malloc(addr as usize, len as usize); + instance.valgrind_state.flag = true; if result.is_ok() { Ok(0) } else { @@ -504,33 +502,36 @@ unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result Result { - // let addr_usize; - // instance::valgrind_state::free(addr_usize) println!("addr: {}", addr); - Ok(0) - //instance.valgrind_state.free(addr) - /* - let result: Result<(), AccessError> = panic!("pretend we called valgrind_state.free()"); - result.to_int() - */ + let result = instance.valgrind_state.free(addr as usize); + instance.valgrind_state.flag = true; + if result.is_ok() { + Ok(0) + } else { + panic!("failed") + } } fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { - // println!("load addr: {}", addr + offset); - //call valgrind read + if instance.valgrind_state.read(addr as usize + offset as usize, num_bytes as usize).is_err() { + eprintln!("load of size {} failed at addr {}", num_bytes, addr as usize + offset as usize); + } } fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { - // println!("store addr: {}", addr + offset); - // valgrind write + if instance.valgrind_state.write(addr as usize + offset as usize, num_bytes as usize).is_err() { + eprintln!("store of size {} failed at addr {}", num_bytes, addr as usize + offset as usize); + } } fn malloc_start(instance: &mut Instance) { - //instance.valgrind_state.flag = false; + println!("started malloc"); + instance.valgrind_state.flag = false; } fn free_start(instance: &mut Instance) { - //instance.valgrind_state.flag = false; + println!("started free"); + instance.valgrind_state.flag = false; } /// This module contains functions which are used for resolving relocations at diff --git a/crates/valgrind/src/lib.rs b/crates/valgrind/src/lib.rs index 278f0d384dd3..64f4885a8c3a 100644 --- a/crates/valgrind/src/lib.rs +++ b/crates/valgrind/src/lib.rs @@ -10,7 +10,7 @@ pub struct Valgrind { mallocs: HashMap, // start addr, len stack_pointer: usize, max_stack_size: usize, - //flag: bool, + pub flag: bool, } #[derive(Debug, PartialEq)] @@ -39,6 +39,7 @@ impl Valgrind { mallocs, stack_pointer, max_stack_size, + flag: true, } } pub fn malloc(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { @@ -72,6 +73,9 @@ impl Valgrind { Ok(()) } pub fn read(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { + if !self.flag { + return Ok(()); + } if !(self.is_in_bounds_stack(addr, len) || self.is_in_bounds_heap(addr, len)) { return Err(AccessError::OutOfBounds { addr: addr, @@ -98,6 +102,9 @@ impl Valgrind { Ok(()) } pub fn write(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { + if !self.flag { + return Ok(()); + } if !(self.is_in_bounds_stack(addr, len) || self.is_in_bounds_heap(addr, len)) { return Err(AccessError::OutOfBounds { addr: addr, @@ -377,3 +384,11 @@ fn stack_underflow() { ); assert_eq!(valgrind_state.stack_pointer, 800); } + +#[test] +fn from_test_program() { + let mut valgrind_state = Valgrind::new(1024 * 1024 * 128, 70864); + + assert!(valgrind_state.write(70832, 1).is_ok()); + assert!(valgrind_state.read(1138, 1).is_ok()); +} From efd934344c63c70d7679038c66983d22d8c563f7 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Thu, 20 Jul 2023 14:55:37 -0700 Subject: [PATCH 14/34] stack tracing in progress --- cranelift/wasm/src/code_translator.rs | 1 + cranelift/wasm/src/environ/spec.rs | 3 +++ crates/cranelift/src/func_environ.rs | 14 +++++++++++++- crates/environ/src/builtin.rs | 2 ++ crates/runtime/src/instance.rs | 15 ++++++++++----- crates/runtime/src/libcalls.rs | 14 ++++++++++---- crates/valgrind/src/lib.rs | 17 +++++++++++++---- 7 files changed, 52 insertions(+), 14 deletions(-) diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 235ff4d29a3d..fef551d5ff61 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -208,6 +208,7 @@ pub fn translate_operator( } debug_assert_eq!(ty, builder.func.dfg.value_type(val)); builder.ins().store(flags, val, addr, offset); + environ.update_global(builder, *global_index, val); } GlobalVariable::Custom => { let val = state.pop1(); diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index 7c6c5743caff..6bfb52bbba06 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -597,6 +597,9 @@ pub trait FuncEnvironment: TargetEnvironment { /// fn before_store(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) {} + + /// + fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) {} } /// An object satisfying the `ModuleEnvironment` trait can be passed as argument to the diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 0eeb895d6099..da6c35333000 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -2306,7 +2306,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } else if func_name == "free" { self.check_free_exit(builder); } - // instance.valgrind_on = false; } fn before_load(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) { @@ -2335,4 +2334,17 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m .ins() .call_indirect(check_store_sig, check_store, &[vmctx, num_bytes, addr, offset_val]); } + + fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) { + if global_index == 0 { + let update_stack_pointer_sig = self.builtin_function_signatures.update_stack_pointer(builder.func); + let (vmctx, update_stack_pointer) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::update_stack_pointer(), + ); + builder + .ins() + .call_indirect(update_stack_pointer_sig, update_stack_pointer, &[vmctx, value]); + } + } } diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index a62e1f4d0351..1add32947841 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -63,6 +63,8 @@ macro_rules! foreach_builtin_function { malloc_start(vmctx: vmctx); /// free_start(vmctx: vmctx); + /// + update_stack_pointer(vmctx: vmctx, value: i32); } }; } diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index a6c5db4a4be8..5318ea02b3d5 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -194,10 +194,8 @@ impl Instance { const MiB: usize = 1024 * 1024; // 1 MiB // ad-hoc testing seems to show... // TODO: how do we determine this more consistently? - const C_STACK_SIZE: usize = 70863; - let mut valg = Valgrind::new(128 * MiB, C_STACK_SIZE); - valg.update_stack_pointer(0); - valg + // const C_STACK_SIZE: usize = 70863; + Valgrind::new(128 * MiB) }, // not sure how to access mem & stack size? }, @@ -1140,7 +1138,14 @@ impl Instance { ptr::write(to, VMGlobalDefinition::new()); match *init { - GlobalInit::I32Const(x) => *(*to).as_i32_mut() = x, + GlobalInit::I32Const(x) => { + let index = module.global_index(index); + if index.index() == 0 { + println!("stack size: {}", x); + self.valgrind_state.set_stack_size(x as usize); + } + *(*to).as_i32_mut() = x; + } GlobalInit::I64Const(x) => *(*to).as_i64_mut() = x, GlobalInit::F32Const(x) => *(*to).as_f32_bits_mut() = x, GlobalInit::F64Const(x) => *(*to).as_f64_bits_mut() = x, diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index f7eefc37f470..f5e220ddcc28 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -9,8 +9,6 @@ //! //! * They must only contain basic, raw i32/i64/f32/f64/pointer parameters that //! are safe to pass across the system ABI. -//! TODO(ssunkin): is the above something that should be taken into account? check_malloc takes -//! usize as the type for its len arg //! //! * If any nested function propagates an `Err(trap)` out to the library //! function frame, we need to raise it. This involves some nasty and quite @@ -493,10 +491,11 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { println!("addr: {} len: {}", addr, len); let result = instance.valgrind_state.malloc(addr as usize, len as usize); - instance.valgrind_state.flag = true; + instance.valgrind_state.memcheck_on(); if result.is_ok() { Ok(0) } else { + //converting AccessError to u32? panic!("failed") } } @@ -504,7 +503,7 @@ unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result Result { println!("addr: {}", addr); let result = instance.valgrind_state.free(addr as usize); - instance.valgrind_state.flag = true; + instance.valgrind_state.memcheck_on(); if result.is_ok() { Ok(0) } else { @@ -512,7 +511,9 @@ unsafe fn check_free(instance: &mut Instance, addr: u32) -> Result { } } +//should be returning result? error propogation? fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { + // println!("load of size {} at addr {}", num_bytes, addr as usize + offset as usize); if instance.valgrind_state.read(addr as usize + offset as usize, num_bytes as usize).is_err() { eprintln!("load of size {} failed at addr {}", num_bytes, addr as usize + offset as usize); } @@ -534,6 +535,11 @@ fn free_start(instance: &mut Instance) { instance.valgrind_state.flag = false; } +fn update_stack_pointer(instance: &mut Instance, value: u32) { + println!("sp updated to {}", value); + instance.valgrind_state.update_stack_pointer(value as usize); +} + /// This module contains functions which are used for resolving relocations at /// runtime if necessary. /// diff --git a/crates/valgrind/src/lib.rs b/crates/valgrind/src/lib.rs index 64f4885a8c3a..98672b9ab440 100644 --- a/crates/valgrind/src/lib.rs +++ b/crates/valgrind/src/lib.rs @@ -30,15 +30,14 @@ pub enum MemState { } impl Valgrind { - pub fn new(mem_size: usize, max_stack_size: usize) -> Valgrind { + pub fn new(mem_size: usize) -> Valgrind { let metadata = vec![MemState::Unallocated; mem_size]; let mallocs = HashMap::new(); - let stack_pointer = max_stack_size; Valgrind { metadata, mallocs, - stack_pointer, - max_stack_size, + stack_pointer: 0, + max_stack_size: 0, flag: true, } } @@ -165,6 +164,16 @@ impl Valgrind { self.stack_pointer = new_sp; Ok(()) } + pub fn memcheck_on(&mut self) { + self.flag = true; + } + pub fn memcheck_off(&mut self) { + self.flag = false; + } + pub fn set_stack_size(&mut self, stack_size: usize) { + self.max_stack_size = stack_size; + self.stack_pointer = stack_size; + } } #[test] From c94c0f760ad604dc42251f9b282249139d0cc984 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Fri, 28 Jul 2023 11:31:05 -0700 Subject: [PATCH 15/34] errors + num bytes displayed --- cranelift/wasm/src/code_translator.rs | 4 +- cranelift/wasm/src/environ/spec.rs | 4 +- crates/cranelift/src/func_environ.rs | 8 +-- crates/runtime/src/instance.rs | 3 +- crates/runtime/src/libcalls.rs | 78 +++++++++++++++++++-------- crates/valgrind/src/lib.rs | 7 ++- 6 files changed, 71 insertions(+), 33 deletions(-) diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index fef551d5ff61..4ff6f5b224c2 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -2819,7 +2819,7 @@ fn translate_load( // TODO: Add a call: wasmtime_valgrind_load_hook(vmctx, wasm_index, memarg.offset) - environ.before_load(builder, wasm_index, memarg.offset); + environ.before_load(builder, result_ty, wasm_index, memarg.offset); let (load, dfg) = builder .ins() @@ -2845,7 +2845,7 @@ fn translate_store( ); // TODO: add call to wasmtime_valgrind_store_hook(vmctx, wasm_index, memarg.offset) - environ.before_store(builder, wasm_index, memarg.offset); + environ.before_store(builder, val_ty, wasm_index, memarg.offset); builder .ins() diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index 6bfb52bbba06..f3c91ffea107 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -593,10 +593,10 @@ pub trait FuncEnvironment: TargetEnvironment { /// // Type::bytes (?) - fn before_load(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) {} + fn before_load(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) {} /// - fn before_store(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) {} + fn before_store(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) {} /// fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) {} diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index da6c35333000..38afc73e78d7 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -2308,13 +2308,13 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } } - fn before_load(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) { + fn before_load(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { let check_load_sig = self.builtin_function_signatures.check_load(builder.func); let (vmctx, check_load) = self.translate_load_builtin_function_address( &mut builder.cursor(), BuiltinFunctionIndex::check_load(), ); - let num_bytes = builder.ins().iconst(I32, 1); + let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); let offset_val = builder.ins().iconst(I64, offset as i64); let addr_and_offset = builder.ins().iadd(offset_val, addr); builder @@ -2322,13 +2322,13 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m .call_indirect(check_load_sig, check_load, &[vmctx, num_bytes, addr, offset_val]); } - fn before_store(&mut self, builder: &mut FunctionBuilder, addr: ir::Value, offset: u64) { + fn before_store(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { let check_store_sig = self.builtin_function_signatures.check_store(builder.func); let (vmctx, check_store) = self.translate_load_builtin_function_address( &mut builder.cursor(), BuiltinFunctionIndex::check_store(), ); - let num_bytes = builder.ins().iconst(I32, 1); + let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); let offset_val = builder.ins().iconst(I64, offset as i64); builder .ins() diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index 5318ea02b3d5..bdf499ab1e9e 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -33,7 +33,6 @@ use wasmtime_environ::{ GlobalInit, HostPtr, MemoryIndex, Module, PrimaryMap, SignatureIndex, TableIndex, TableInitialValue, Trap, VMOffsets, WasmHeapType, WasmRefType, WasmType, VMCONTEXT_MAGIC, }; -// use crate::wasm_valgrind::Valgrind; mod allocator; @@ -1141,7 +1140,7 @@ impl Instance { GlobalInit::I32Const(x) => { let index = module.global_index(index); if index.index() == 0 { - println!("stack size: {}", x); + // println!("stack size: {}", x); self.valgrind_state.set_stack_size(x as usize); } *(*to).as_i32_mut() = x; diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index f5e220ddcc28..3ef2916f4458 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -58,6 +58,7 @@ use crate::externref::VMExternRef; use crate::table::{Table, TableElementType}; use crate::vmcontext::VMFuncRef; use crate::{Instance, TrapReason}; +use wasm_valgrind::AccessError::{DoubleMalloc, InvalidRead, InvalidWrite, InvalidFree, OutOfBounds}; use anyhow::Result; use std::mem; use std::ptr::{self, NonNull}; @@ -489,55 +490,90 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { } unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { - println!("addr: {} len: {}", addr, len); let result = instance.valgrind_state.malloc(addr as usize, len as usize); instance.valgrind_state.memcheck_on(); - if result.is_ok() { - Ok(0) - } else { - //converting AccessError to u32? - panic!("failed") + match result { + Ok(()) => { + Ok(0) + } + Err(DoubleMalloc { addr, len }) => { + panic!("Double malloc at addr {} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + panic!("Malloc out of bounds at addr {} of size {}", addr, len); + } + _ => { + panic!("unreachable") + } } } unsafe fn check_free(instance: &mut Instance, addr: u32) -> Result { - println!("addr: {}", addr); let result = instance.valgrind_state.free(addr as usize); instance.valgrind_state.memcheck_on(); - if result.is_ok() { - Ok(0) - } else { - panic!("failed") + match result { + Ok(()) => { + Ok(0) + } + Err(InvalidFree { addr }) => { + panic!("Invalid free at addr {}", addr) + } + _ => { + panic!("unreachable") + } } } //should be returning result? error propogation? fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { // println!("load of size {} at addr {}", num_bytes, addr as usize + offset as usize); - if instance.valgrind_state.read(addr as usize + offset as usize, num_bytes as usize).is_err() { - eprintln!("load of size {} failed at addr {}", num_bytes, addr as usize + offset as usize); + // if instance.valgrind_state.read(addr as usize + offset as usize, num_bytes as usize).is_err() { + // eprintln!("load of size {} failed at addr {}", num_bytes, addr as usize + offset as usize); + // } + let result = instance.valgrind_state.read(addr as usize + offset as usize, num_bytes as usize); + match result { + Ok(()) => {} + Err(InvalidRead { addr, len }) => { + panic!("Invalid load at addr {} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + panic!("Load out of bounds at addr {} of size {}", addr, len); + } + _ => { + panic!("unreachable") + } } } fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { - if instance.valgrind_state.write(addr as usize + offset as usize, num_bytes as usize).is_err() { - eprintln!("store of size {} failed at addr {}", num_bytes, addr as usize + offset as usize); + // if instance.valgrind_state.write(addr as usize + offset as usize, num_bytes as usize).is_err() { + // eprintln!("store of size {} failed at addr {}", num_bytes, addr as usize + offset as usize); + // } + let result = instance.valgrind_state.write(addr as usize + offset as usize, num_bytes as usize); + match result { + Ok(()) => {} + Err(InvalidWrite { addr, len }) => { + panic!("Invalid store at addr {} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + panic!("Store out of bounds at addr {} of size {}", addr, len); + } + _ => { + panic!("unreachable") + } } } fn malloc_start(instance: &mut Instance) { - println!("started malloc"); - instance.valgrind_state.flag = false; + instance.valgrind_state.memcheck_off(); } fn free_start(instance: &mut Instance) { - println!("started free"); - instance.valgrind_state.flag = false; + instance.valgrind_state.memcheck_off(); } fn update_stack_pointer(instance: &mut Instance, value: u32) { - println!("sp updated to {}", value); - instance.valgrind_state.update_stack_pointer(value as usize); + // instance.valgrind_state.update_stack_pointer(value as usize); } /// This module contains functions which are used for resolving relocations at diff --git a/crates/valgrind/src/lib.rs b/crates/valgrind/src/lib.rs index 98672b9ab440..4002f5c8a61a 100644 --- a/crates/valgrind/src/lib.rs +++ b/crates/valgrind/src/lib.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; pub struct Valgrind { metadata: Vec, mallocs: HashMap, // start addr, len - stack_pointer: usize, + pub stack_pointer: usize, max_stack_size: usize, pub flag: bool, } @@ -171,8 +171,11 @@ impl Valgrind { self.flag = false; } pub fn set_stack_size(&mut self, stack_size: usize) { - self.max_stack_size = stack_size; + self.max_stack_size = stack_size + 1; + //temporary solution to initialize the entire stack + //while keeping stack tracing plumbing in place self.stack_pointer = stack_size; + self.update_stack_pointer(0); } } From 74990f217e36a4c5d292336c4248bdafac613999 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Mon, 31 Jul 2023 14:44:44 -0700 Subject: [PATCH 16/34] initial valgrind configuration --- Cargo.toml | 1 + crates/runtime/Cargo.toml | 2 + crates/runtime/src/instance.rs | 4 + crates/runtime/src/libcalls.rs | 138 ++++++++++++++++++++------------- 4 files changed, 89 insertions(+), 56 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ffdba654440f..822b1c3051fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -268,6 +268,7 @@ component-model = [ "wasmtime-cli-flags/component-model" ] winch = ["wasmtime/winch"] +valgrind = ["wasmtime-runtime/valgrind"] [[test]] name = "host_segfault" diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index e272980df712..4be7ce5d27f7 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -67,3 +67,5 @@ component-model = [ "wasmtime-environ/component-model", "dep:encoding_rs", ] + +valgrind = [] \ No newline at end of file diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index bdf499ab1e9e..fe571e2091eb 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -15,6 +15,7 @@ use crate::{ ExportFunction, ExportGlobal, ExportMemory, ExportTable, Imports, ModuleRuntimeInfo, SendSyncPtr, Store, VMFunctionBody, VMSharedSignatureIndex, WasmFault, }; +#[cfg(feature = "valgrind")] use wasm_valgrind::Valgrind; use anyhow::Error; use anyhow::Result; @@ -141,6 +142,7 @@ pub struct Instance { /// seems not too bad. vmctx_self_reference: SendSyncPtr, + #[cfg(feature = "valgrind")] pub(crate) valgrind_state: Valgrind, /// Additional context used by compiled wasm code. This field is last, and @@ -189,6 +191,7 @@ impl Instance { vmctx: VMContext { _marker: std::marker::PhantomPinned, }, + #[cfg(feature = "valgrind")] valgrind_state: { const MiB: usize = 1024 * 1024; // 1 MiB // ad-hoc testing seems to show... @@ -1141,6 +1144,7 @@ impl Instance { let index = module.global_index(index); if index.index() == 0 { // println!("stack size: {}", x); + #[cfg(feature = "valgrind")] self.valgrind_state.set_stack_size(x as usize); } *(*to).as_i32_mut() = x; diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 3ef2916f4458..e804320d5d36 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -58,6 +58,7 @@ use crate::externref::VMExternRef; use crate::table::{Table, TableElementType}; use crate::vmcontext::VMFuncRef; use crate::{Instance, TrapReason}; +#[cfg(feature = "valgrind")] use wasm_valgrind::AccessError::{DoubleMalloc, InvalidRead, InvalidWrite, InvalidFree, OutOfBounds}; use anyhow::Result; use std::mem; @@ -66,6 +67,7 @@ use std::time::{Duration, Instant}; use wasmtime_environ::{ DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Trap, }; +use cfg_if::cfg_if; // use crate::wasm_valgrind::AccessError; /// Actually public trampolines which are used by the runtime as the entrypoint @@ -489,90 +491,114 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { (*instance.store()).new_epoch() } -unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { - let result = instance.valgrind_state.malloc(addr as usize, len as usize); - instance.valgrind_state.memcheck_on(); - match result { - Ok(()) => { - Ok(0) - } - Err(DoubleMalloc { addr, len }) => { - panic!("Double malloc at addr {} of size {}", addr, len) - } - Err(OutOfBounds { addr, len }) => { - panic!("Malloc out of bounds at addr {} of size {}", addr, len); +cfg_if! { + if #[cfg(feature = "valgrind")] { + unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { + let result = instance.valgrind_state.malloc(addr as usize, len as usize); + instance.valgrind_state.memcheck_on(); + match result { + Ok(()) => { + Ok(0) + } + Err(DoubleMalloc { addr, len }) => { + panic!("Double malloc at addr {} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + panic!("Malloc out of bounds at addr {} of size {}", addr, len); + } + _ => { + panic!("unreachable") + } + } } - _ => { - panic!("unreachable") + } else { + unsafe fn check_malloc(_instance: &mut Instance, _addr: u32, _len: u32) -> Result { + Ok(0) } } } -unsafe fn check_free(instance: &mut Instance, addr: u32) -> Result { - let result = instance.valgrind_state.free(addr as usize); - instance.valgrind_state.memcheck_on(); - match result { - Ok(()) => { - Ok(0) - } - Err(InvalidFree { addr }) => { - panic!("Invalid free at addr {}", addr) +cfg_if! { + if #[cfg(feature = "valgrind")] { + unsafe fn check_free(instance: &mut Instance, addr: u32) -> Result { + let result = instance.valgrind_state.free(addr as usize); + instance.valgrind_state.memcheck_on(); + match result { + Ok(()) => { + Ok(0) + } + Err(InvalidFree { addr }) => { + panic!("Invalid free at addr {}", addr) + } + _ => { + panic!("unreachable") + } + } } - _ => { - panic!("unreachable") + } else { + unsafe fn check_free(_instance: &mut Instance, _addr: u32) -> Result { + Ok(0) } } } //should be returning result? error propogation? -fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { - // println!("load of size {} at addr {}", num_bytes, addr as usize + offset as usize); - // if instance.valgrind_state.read(addr as usize + offset as usize, num_bytes as usize).is_err() { - // eprintln!("load of size {} failed at addr {}", num_bytes, addr as usize + offset as usize); - // } - let result = instance.valgrind_state.read(addr as usize + offset as usize, num_bytes as usize); - match result { - Ok(()) => {} - Err(InvalidRead { addr, len }) => { - panic!("Invalid load at addr {} of size {}", addr, len) - } - Err(OutOfBounds { addr, len }) => { - panic!("Load out of bounds at addr {} of size {}", addr, len); - } - _ => { - panic!("unreachable") +cfg_if! { + if #[cfg(feature = "valgrind")] { + fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { + let result = instance.valgrind_state.read(addr as usize + offset as usize, num_bytes as usize); + match result { + Ok(()) => {} + Err(InvalidRead { addr, len }) => { + panic!("Invalid load at addr {} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + panic!("Load out of bounds at addr {} of size {}", addr, len); + } + _ => { + panic!("unreachable") + } + } } + } else { + fn check_load(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) {} } } -fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { - // if instance.valgrind_state.write(addr as usize + offset as usize, num_bytes as usize).is_err() { - // eprintln!("store of size {} failed at addr {}", num_bytes, addr as usize + offset as usize); - // } - let result = instance.valgrind_state.write(addr as usize + offset as usize, num_bytes as usize); - match result { - Ok(()) => {} - Err(InvalidWrite { addr, len }) => { - panic!("Invalid store at addr {} of size {}", addr, len) - } - Err(OutOfBounds { addr, len }) => { - panic!("Store out of bounds at addr {} of size {}", addr, len); - } - _ => { - panic!("unreachable") +cfg_if! { + if #[cfg(feature = "valgrind")] { + fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { + let result = instance.valgrind_state.write(addr as usize + offset as usize, num_bytes as usize); + match result { + Ok(()) => {} + Err(InvalidWrite { addr, len }) => { + panic!("Invalid store at addr {} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + panic!("Store out of bounds at addr {} of size {}", addr, len); + } + _ => { + panic!("unreachable") + } + } } + } else { + fn check_store(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) {} } } fn malloc_start(instance: &mut Instance) { + #[cfg(feature = "valgrind")] instance.valgrind_state.memcheck_off(); } fn free_start(instance: &mut Instance) { + #[cfg(feature = "valgrind")] instance.valgrind_state.memcheck_off(); } fn update_stack_pointer(instance: &mut Instance, value: u32) { + // #[cfg(feature = "valgrind")] // instance.valgrind_state.update_stack_pointer(value as usize); } From 6e892010d12dfc5b8c5cff3f0dd3e14ec12b4714 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Mon, 31 Jul 2023 15:26:29 -0700 Subject: [PATCH 17/34] valgrind conditional some warnings fixed --- Cargo.lock | 1 + crates/cranelift/Cargo.toml | 2 + crates/cranelift/src/func_environ.rs | 143 +++++++++++++++++---------- crates/runtime/src/libcalls.rs | 33 +++++-- 4 files changed, 118 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a98b7f34722a..066106de5dc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4001,6 +4001,7 @@ name = "wasmtime-cranelift" version = "11.0.0" dependencies = [ "anyhow", + "cfg-if", "cranelift-codegen", "cranelift-control", "cranelift-entity", diff --git a/crates/cranelift/Cargo.toml b/crates/cranelift/Cargo.toml index 40a0a9bfc2d6..5115bad7fe82 100644 --- a/crates/cranelift/Cargo.toml +++ b/crates/cranelift/Cargo.toml @@ -26,8 +26,10 @@ target-lexicon = { workspace = true } gimli = { workspace = true } object = { workspace = true, features = ['write'] } thiserror = { workspace = true } +cfg-if = { workspace = true } [features] all-arch = ["cranelift-codegen/all-arch"] component-model = ["wasmtime-environ/component-model"] incremental-cache = ["cranelift-codegen/incremental-cache"] +valgrind = [] \ No newline at end of file diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 38afc73e78d7..4d873dffd5ac 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -21,6 +21,7 @@ use wasmtime_environ::{ TableStyle, Tunables, TypeConvert, VMOffsets, WASM_PAGE_SIZE, }; use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK}; // is this the right place to import Value from? +use cfg_if::cfg_if; macro_rules! declare_function_signatures { ( @@ -655,6 +656,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { self.epoch_check(builder); } + #[cfg(feature = "valgrind")] fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder, retvals: &[Value]) { let check_malloc_sig = self.builtin_function_signatures.check_malloc(builder.func); let (vmctx, check_malloc) = self.translate_load_builtin_function_address( @@ -667,6 +669,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { .call_indirect(check_malloc_sig, check_malloc, &[vmctx, retvals[0], len]); } + #[cfg(feature = "valgrind")] fn check_free_exit(&mut self, builder: &mut FunctionBuilder) { let check_free_sig = self.builtin_function_signatures.check_free(builder.func); let (vmctx, check_free) = self.translate_load_builtin_function_address( @@ -678,6 +681,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { .ins() .call_indirect(check_free_sig, check_free, &[vmctx, ptr]); } + fn epoch_ptr(&mut self, builder: &mut FunctionBuilder<'_>) -> ir::Value { let vmctx = self.vmctx(builder.func); @@ -2284,67 +2288,102 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m self.isa.has_x86_pmaddubsw_lowering() } - fn handle_before_return( - &mut self, - retvals: &[Value], - builder: &mut FunctionBuilder, - ) { - let block = builder.func.layout.entry_block().unwrap(); - let args = builder.func.dfg.block_params(block); - let func_index = match &builder.func.name { - UserFuncName::User(user) => { - FuncIndex::from_u32(user.index) + cfg_if! { + if #[cfg(feature = "valgrind")] { + fn handle_before_return( + &mut self, + retvals: &[Value], + builder: &mut FunctionBuilder, + ) { + let block = builder.func.layout.entry_block().unwrap(); + let args = builder.func.dfg.block_params(block); + let func_index = match &builder.func.name { + UserFuncName::User(user) => { + FuncIndex::from_u32(user.index) + } + _ => { + unreachable!() + } + }; + let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; + // println!("name: {}, index: {:?}", func_name, func_index); + if func_name == "malloc" { + self.check_malloc_exit(builder, retvals); + } else if func_name == "free" { + self.check_free_exit(builder); + } } - _ => { - unreachable!() + } else { + fn handle_before_return(&mut self, _retvals: &[Value], builder: &mut FunctionBuilder, + ) { + let _ = self.builtin_function_signatures.check_malloc(builder.func); + let _ = self.builtin_function_signatures.check_free(builder.func); } - }; - let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; - // println!("name: {}, index: {:?}", func_name, func_index); - if func_name == "malloc" { - self.check_malloc_exit(builder, retvals); - } else if func_name == "free" { - self.check_free_exit(builder); } } - fn before_load(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { - let check_load_sig = self.builtin_function_signatures.check_load(builder.func); - let (vmctx, check_load) = self.translate_load_builtin_function_address( - &mut builder.cursor(), - BuiltinFunctionIndex::check_load(), - ); - let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); - let offset_val = builder.ins().iconst(I64, offset as i64); - let addr_and_offset = builder.ins().iadd(offset_val, addr); - builder - .ins() - .call_indirect(check_load_sig, check_load, &[vmctx, num_bytes, addr, offset_val]); + cfg_if! { + if #[cfg(feature = "valgrind")] { + fn before_load(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { + let check_load_sig = self.builtin_function_signatures.check_load(builder.func); + let (vmctx, check_load) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_load(), + ); + let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); + let offset_val = builder.ins().iconst(I64, offset as i64); + let addr_and_offset = builder.ins().iadd(offset_val, addr); + builder + .ins() + .call_indirect(check_load_sig, check_load, &[vmctx, num_bytes, addr, offset_val]); + } + } else { + fn before_load(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { + // aren't using check_load, avoiding warnings + let _ = self.builtin_function_signatures.check_load(builder.func); + } + } } - fn before_store(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { - let check_store_sig = self.builtin_function_signatures.check_store(builder.func); - let (vmctx, check_store) = self.translate_load_builtin_function_address( - &mut builder.cursor(), - BuiltinFunctionIndex::check_store(), - ); - let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); - let offset_val = builder.ins().iconst(I64, offset as i64); - builder - .ins() - .call_indirect(check_store_sig, check_store, &[vmctx, num_bytes, addr, offset_val]); + cfg_if! { + if #[cfg(feature = "valgrind")] { + fn before_store(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { + let check_store_sig = self.builtin_function_signatures.check_store(builder.func); + let (vmctx, check_store) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_store(), + ); + let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); + let offset_val = builder.ins().iconst(I64, offset as i64); + builder + .ins() + .call_indirect(check_store_sig, check_store, &[vmctx, num_bytes, addr, offset_val]); + } + } else { + fn before_store(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { + let _ = self.builtin_function_signatures.check_store(builder.func); + } + } } - fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) { - if global_index == 0 { - let update_stack_pointer_sig = self.builtin_function_signatures.update_stack_pointer(builder.func); - let (vmctx, update_stack_pointer) = self.translate_load_builtin_function_address( - &mut builder.cursor(), - BuiltinFunctionIndex::update_stack_pointer(), - ); - builder - .ins() - .call_indirect(update_stack_pointer_sig, update_stack_pointer, &[vmctx, value]); + cfg_if! { + if #[cfg(feature = "valgrind")] { + fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) { + if global_index == 0 { + let update_stack_pointer_sig = self.builtin_function_signatures.update_stack_pointer(builder.func); + let (vmctx, update_stack_pointer) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::update_stack_pointer(), + ); + builder + .ins() + .call_indirect(update_stack_pointer_sig, update_stack_pointer, &[vmctx, value]); + } + } + } else { + fn update_global(&mut self, builder: &mut FunctionBuilder, _global_index: u32, _value: ir::Value) { + let _ = self.builtin_function_signatures.update_stack_pointer(builder.func); + } } } } diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index e804320d5d36..804fad18ce36 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -587,19 +587,34 @@ cfg_if! { } } -fn malloc_start(instance: &mut Instance) { - #[cfg(feature = "valgrind")] - instance.valgrind_state.memcheck_off(); +cfg_if! { + if #[cfg(feature = "valgrind")] { + fn malloc_start(instance: &mut Instance) { + instance.valgrind_state.memcheck_off(); + } + } else { + fn malloc_start(_instance: &mut Instance) {} + } } -fn free_start(instance: &mut Instance) { - #[cfg(feature = "valgrind")] - instance.valgrind_state.memcheck_off(); +cfg_if! { + if #[cfg(feature = "valgrind")] { + fn free_start(instance: &mut Instance) { + instance.valgrind_state.memcheck_off(); + } + } else { + fn free_start(_instance: &mut Instance) {} + } } -fn update_stack_pointer(instance: &mut Instance, value: u32) { - // #[cfg(feature = "valgrind")] - // instance.valgrind_state.update_stack_pointer(value as usize); +cfg_if! { + if #[cfg(feature = "valgrind")] { + fn update_stack_pointer(instance: &mut Instance, value: u32) { + // instance.valgrind_state.update_stack_pointer(value as usize); + } + } else { + fn update_stack_pointer(_instance: &mut Instance, _value: u32) {} + } } /// This module contains functions which are used for resolving relocations at From 59ff0aa463e5da281de306e77b0a303330511552 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Wed, 2 Aug 2023 12:12:24 -0700 Subject: [PATCH 18/34] conditional compilation + CLI flag finished --- Cargo.toml | 2 +- cranelift/wasm/src/code_translator.rs | 3 - crates/cranelift/src/builder.rs | 7 ++ crates/cranelift/src/compiler.rs | 5 +- crates/cranelift/src/func_environ.rs | 103 +++++++++++--------- crates/environ/src/compilation.rs | 3 + crates/runtime/src/instance.rs | 24 +++-- crates/runtime/src/instance/allocator.rs | 3 + crates/runtime/src/libcalls.rs | 117 +++++++++++++---------- crates/wasmtime/Cargo.toml | 2 + crates/wasmtime/src/config.rs | 13 +++ crates/wasmtime/src/instance.rs | 1 + crates/wasmtime/src/module.rs | 1 + crates/wasmtime/src/store.rs | 1 + crates/wasmtime/src/trampoline.rs | 1 + crates/wasmtime/src/trampoline/memory.rs | 1 + src/commands/run.rs | 6 ++ 17 files changed, 184 insertions(+), 109 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 822b1c3051fa..0076012cf01f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -268,7 +268,7 @@ component-model = [ "wasmtime-cli-flags/component-model" ] winch = ["wasmtime/winch"] -valgrind = ["wasmtime-runtime/valgrind"] +valgrind = ["wasmtime/valgrind"] [[test]] name = "host_segfault" diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 4ff6f5b224c2..a17479d4ee18 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -2817,8 +2817,6 @@ fn translate_load( Reachability::Reachable((f, i, b)) => (f, i, b), }; - // TODO: Add a call: wasmtime_valgrind_load_hook(vmctx, wasm_index, memarg.offset) - environ.before_load(builder, result_ty, wasm_index, memarg.offset); let (load, dfg) = builder @@ -2844,7 +2842,6 @@ fn translate_store( prepare_addr(memarg, mem_op_size(opcode, val_ty), builder, state, environ)? ); - // TODO: add call to wasmtime_valgrind_store_hook(vmctx, wasm_index, memarg.offset) environ.before_store(builder, val_ty, wasm_index, memarg.offset); builder diff --git a/crates/cranelift/src/builder.rs b/crates/cranelift/src/builder.rs index 5fcf8e05fbc3..0b509e8ce567 100644 --- a/crates/cranelift/src/builder.rs +++ b/crates/cranelift/src/builder.rs @@ -19,6 +19,7 @@ struct Builder { linkopts: LinkOptions, cache_store: Option>, clif_dir: Option, + valgrind: bool, } #[derive(Clone, Default)] @@ -40,6 +41,7 @@ pub fn builder() -> Box { linkopts: LinkOptions::default(), cache_store: None, clif_dir: None, + valgrind: false, }) } @@ -83,6 +85,7 @@ impl CompilerBuilder for Builder { self.cache_store.clone(), self.linkopts.clone(), self.clif_dir.clone(), + self.valgrind, ))) } @@ -97,6 +100,10 @@ impl CompilerBuilder for Builder { self.cache_store = Some(cache_store); Ok(()) } + + fn valgrind(&mut self, enable: bool) { + self.valgrind = enable; + } } impl fmt::Debug for Builder { diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs index 027c7a51f9eb..d1da6dbd5004 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs @@ -70,6 +70,7 @@ pub(crate) struct Compiler { linkopts: LinkOptions, cache_store: Option>, clif_dir: Option, + valgrind: bool, } impl Drop for Compiler { @@ -106,6 +107,7 @@ impl Compiler { cache_store: Option>, linkopts: LinkOptions, clif_dir: Option, + valgrind: bool, ) -> Compiler { Compiler { contexts: Default::default(), @@ -113,6 +115,7 @@ impl Compiler { linkopts, cache_store, clif_dir, + valgrind, } } } @@ -145,7 +148,7 @@ impl wasmtime_environ::Compiler for Compiler { context.func.collect_debug_info(); } - let mut func_env = FuncEnvironment::new(isa, translation, types, tunables); + let mut func_env = FuncEnvironment::new(isa, translation, types, tunables, self.valgrind); // The `stack_limit` global value below is the implementation of stack // overflow checks in Wasmtime. diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 4d873dffd5ac..ec9506499e67 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -153,6 +153,8 @@ pub struct FuncEnvironment<'module_environment> { epoch_ptr_var: cranelift_frontend::Variable, fuel_consumed: i64, + + valgrind: bool, } impl<'module_environment> FuncEnvironment<'module_environment> { @@ -161,6 +163,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { translation: &'module_environment ModuleTranslation<'module_environment>, types: &'module_environment ModuleTypes, tunables: &'module_environment Tunables, + valgrind: bool, ) -> Self { let builtin_function_signatures = BuiltinFunctionSignatures::new( isa.pointer_type(), @@ -189,6 +192,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { // Start with at least one fuel being consumed because even empty // functions should consume at least some fuel. fuel_consumed: 1, + valgrind, } } @@ -2295,24 +2299,26 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m retvals: &[Value], builder: &mut FunctionBuilder, ) { - let block = builder.func.layout.entry_block().unwrap(); - let args = builder.func.dfg.block_params(block); - let func_index = match &builder.func.name { - UserFuncName::User(user) => { - FuncIndex::from_u32(user.index) - } - _ => { - unreachable!() + if self.valgrind { + let block = builder.func.layout.entry_block().unwrap(); + let args = builder.func.dfg.block_params(block); + let func_index = match &builder.func.name { + UserFuncName::User(user) => { + FuncIndex::from_u32(user.index) + } + _ => { + unreachable!() + } + }; + let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; + if func_name == "malloc" { + self.check_malloc_exit(builder, retvals); + } else if func_name == "free" { + self.check_free_exit(builder); } - }; - let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; - // println!("name: {}, index: {:?}", func_name, func_index); - if func_name == "malloc" { - self.check_malloc_exit(builder, retvals); - } else if func_name == "free" { - self.check_free_exit(builder); } } + } else { fn handle_before_return(&mut self, _retvals: &[Value], builder: &mut FunctionBuilder, ) { @@ -2325,17 +2331,19 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m cfg_if! { if #[cfg(feature = "valgrind")] { fn before_load(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { - let check_load_sig = self.builtin_function_signatures.check_load(builder.func); - let (vmctx, check_load) = self.translate_load_builtin_function_address( - &mut builder.cursor(), - BuiltinFunctionIndex::check_load(), - ); - let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); - let offset_val = builder.ins().iconst(I64, offset as i64); - let addr_and_offset = builder.ins().iadd(offset_val, addr); - builder - .ins() - .call_indirect(check_load_sig, check_load, &[vmctx, num_bytes, addr, offset_val]); + if self.valgrind { + let check_load_sig = self.builtin_function_signatures.check_load(builder.func); + let (vmctx, check_load) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_load(), + ); + let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); + let offset_val = builder.ins().iconst(I64, offset as i64); + let addr_and_offset = builder.ins().iadd(offset_val, addr); + builder + .ins() + .call_indirect(check_load_sig, check_load, &[vmctx, num_bytes, addr, offset_val]); + } } } else { fn before_load(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { @@ -2348,16 +2356,19 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m cfg_if! { if #[cfg(feature = "valgrind")] { fn before_store(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { - let check_store_sig = self.builtin_function_signatures.check_store(builder.func); - let (vmctx, check_store) = self.translate_load_builtin_function_address( - &mut builder.cursor(), - BuiltinFunctionIndex::check_store(), - ); - let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); - let offset_val = builder.ins().iconst(I64, offset as i64); - builder - .ins() - .call_indirect(check_store_sig, check_store, &[vmctx, num_bytes, addr, offset_val]); + if self.valgrind { + let check_store_sig = self.builtin_function_signatures.check_store(builder.func); + let (vmctx, check_store) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::check_store(), + ); + let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); + let offset_val = builder.ins().iconst(I64, offset as i64); + builder + .ins() + .call_indirect(check_store_sig, check_store, &[vmctx, num_bytes, addr, offset_val]); + } + } } else { fn before_store(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { @@ -2369,15 +2380,17 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m cfg_if! { if #[cfg(feature = "valgrind")] { fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) { - if global_index == 0 { - let update_stack_pointer_sig = self.builtin_function_signatures.update_stack_pointer(builder.func); - let (vmctx, update_stack_pointer) = self.translate_load_builtin_function_address( - &mut builder.cursor(), - BuiltinFunctionIndex::update_stack_pointer(), - ); - builder - .ins() - .call_indirect(update_stack_pointer_sig, update_stack_pointer, &[vmctx, value]); + if self.valgrind { + if global_index == 0 { + let update_stack_pointer_sig = self.builtin_function_signatures.update_stack_pointer(builder.func); + let (vmctx, update_stack_pointer) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::update_stack_pointer(), + ); + builder + .ins() + .call_indirect(update_stack_pointer_sig, update_stack_pointer, &[vmctx, value]); + } } } } else { diff --git a/crates/environ/src/compilation.rs b/crates/environ/src/compilation.rs index d9790bc4f6e3..0c73aa2f8bd0 100644 --- a/crates/environ/src/compilation.rs +++ b/crates/environ/src/compilation.rs @@ -124,6 +124,9 @@ pub trait CompilerBuilder: Send + Sync + fmt::Debug { /// Builds a new [`Compiler`] object from this configuration. fn build(&self) -> Result>; + + /// + fn valgrind(&mut self, enable: bool) {} } /// Description of compiler settings returned by [`CompilerBuilder::settings`]. diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index fe571e2091eb..351a8949d937 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -143,7 +143,7 @@ pub struct Instance { vmctx_self_reference: SendSyncPtr, #[cfg(feature = "valgrind")] - pub(crate) valgrind_state: Valgrind, + pub(crate) valgrind_state: Option, /// Additional context used by compiled wasm code. This field is last, and /// represents a dynamically-sized array that extends beyond the nominal @@ -193,11 +193,15 @@ impl Instance { }, #[cfg(feature = "valgrind")] valgrind_state: { - const MiB: usize = 1024 * 1024; // 1 MiB - // ad-hoc testing seems to show... - // TODO: how do we determine this more consistently? - // const C_STACK_SIZE: usize = 70863; - Valgrind::new(128 * MiB) + if req.valgrind { + const MiB: usize = 1024 * 1024; // 1 MiB + // ad-hoc testing seems to show... + // TODO: how do we determine this more consistently? + // const C_STACK_SIZE: usize = 70863; + Some(Valgrind::new(128 * MiB)) + } else { + None + } }, // not sure how to access mem & stack size? }, @@ -1143,9 +1147,11 @@ impl Instance { GlobalInit::I32Const(x) => { let index = module.global_index(index); if index.index() == 0 { - // println!("stack size: {}", x); - #[cfg(feature = "valgrind")] - self.valgrind_state.set_stack_size(x as usize); + #[cfg(feature = "valgrind")] { + if let Some(valgrind) = &mut self.valgrind_state { + valgrind.set_stack_size(x as usize); + } + } } *(*to).as_i32_mut() = x; } diff --git a/crates/runtime/src/instance/allocator.rs b/crates/runtime/src/instance/allocator.rs index a7cbaeef7824..15163d9fef1e 100644 --- a/crates/runtime/src/instance/allocator.rs +++ b/crates/runtime/src/instance/allocator.rs @@ -51,6 +51,9 @@ pub struct InstanceAllocationRequest<'a> { /// We use a number of `PhantomPinned` declarations to indicate this to the /// compiler. More info on this in `wasmtime/src/store.rs` pub store: StorePtr, + + /// Indicates '--valgrind' flag. + pub valgrind: bool, } /// A pointer to a Store. This Option<*mut dyn Store> is wrapped in a struct diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 804fad18ce36..42771142afef 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -494,22 +494,26 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { cfg_if! { if #[cfg(feature = "valgrind")] { unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { - let result = instance.valgrind_state.malloc(addr as usize, len as usize); - instance.valgrind_state.memcheck_on(); - match result { - Ok(()) => { - Ok(0) - } - Err(DoubleMalloc { addr, len }) => { - panic!("Double malloc at addr {} of size {}", addr, len) - } - Err(OutOfBounds { addr, len }) => { - panic!("Malloc out of bounds at addr {} of size {}", addr, len); - } - _ => { - panic!("unreachable") + //safe to unwrap bc function will never be called when valgrind_state == None + if let Some(valgrind_state) = &mut instance.valgrind_state { + let result = valgrind_state.malloc(addr as usize, len as usize); + valgrind_state.memcheck_on(); + match result { + Ok(()) => { + return Ok(0); + } + Err(DoubleMalloc { addr, len }) => { + panic!("Double malloc at addr {} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + panic!("Malloc out of bounds at addr {} of size {}", addr, len); + } + _ => { + panic!("unreachable") + } } } + Ok(0) } } else { unsafe fn check_malloc(_instance: &mut Instance, _addr: u32, _len: u32) -> Result { @@ -521,19 +525,22 @@ cfg_if! { cfg_if! { if #[cfg(feature = "valgrind")] { unsafe fn check_free(instance: &mut Instance, addr: u32) -> Result { - let result = instance.valgrind_state.free(addr as usize); - instance.valgrind_state.memcheck_on(); - match result { - Ok(()) => { - Ok(0) - } - Err(InvalidFree { addr }) => { - panic!("Invalid free at addr {}", addr) - } - _ => { - panic!("unreachable") + if let Some(valgrind_state) = &mut instance.valgrind_state { + let result = valgrind_state.free(addr as usize); + valgrind_state.memcheck_on(); + match result { + Ok(()) => { + return Ok(0); + } + Err(InvalidFree { addr }) => { + panic!("Invalid free at addr {}", addr) + } + _ => { + panic!("unreachable") + } } } + Ok(0) } } else { unsafe fn check_free(_instance: &mut Instance, _addr: u32) -> Result { @@ -546,17 +553,19 @@ cfg_if! { cfg_if! { if #[cfg(feature = "valgrind")] { fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { - let result = instance.valgrind_state.read(addr as usize + offset as usize, num_bytes as usize); - match result { - Ok(()) => {} - Err(InvalidRead { addr, len }) => { - panic!("Invalid load at addr {} of size {}", addr, len) - } - Err(OutOfBounds { addr, len }) => { - panic!("Load out of bounds at addr {} of size {}", addr, len); - } - _ => { - panic!("unreachable") + if let Some(valgrind_state) = &mut instance.valgrind_state { + let result = valgrind_state.read(addr as usize + offset as usize, num_bytes as usize); + match result { + Ok(()) => {} + Err(InvalidRead { addr, len }) => { + panic!("Invalid load at addr {} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + panic!("Load out of bounds at addr {} of size {}", addr, len); + } + _ => { + panic!("unreachable") + } } } } @@ -568,17 +577,19 @@ cfg_if! { cfg_if! { if #[cfg(feature = "valgrind")] { fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { - let result = instance.valgrind_state.write(addr as usize + offset as usize, num_bytes as usize); - match result { - Ok(()) => {} - Err(InvalidWrite { addr, len }) => { - panic!("Invalid store at addr {} of size {}", addr, len) - } - Err(OutOfBounds { addr, len }) => { - panic!("Store out of bounds at addr {} of size {}", addr, len); - } - _ => { - panic!("unreachable") + if let Some(valgrind_state) = &mut instance.valgrind_state { + let result = valgrind_state.write(addr as usize + offset as usize, num_bytes as usize); + match result { + Ok(()) => {} + Err(InvalidWrite { addr, len }) => { + panic!("Invalid store at addr {} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + panic!("Store out of bounds at addr {} of size {}", addr, len); + } + _ => { + panic!("unreachable") + } } } } @@ -590,7 +601,9 @@ cfg_if! { cfg_if! { if #[cfg(feature = "valgrind")] { fn malloc_start(instance: &mut Instance) { - instance.valgrind_state.memcheck_off(); + if let Some(valgrind_state) = &mut instance.valgrind_state { + valgrind_state.memcheck_off(); + } } } else { fn malloc_start(_instance: &mut Instance) {} @@ -600,7 +613,9 @@ cfg_if! { cfg_if! { if #[cfg(feature = "valgrind")] { fn free_start(instance: &mut Instance) { - instance.valgrind_state.memcheck_off(); + if let Some(valgrind_state) = &mut instance.valgrind_state { + valgrind_state.memcheck_off(); + } } } else { fn free_start(_instance: &mut Instance) {} @@ -610,7 +625,9 @@ cfg_if! { cfg_if! { if #[cfg(feature = "valgrind")] { fn update_stack_pointer(instance: &mut Instance, value: u32) { - // instance.valgrind_state.update_stack_pointer(value as usize); + if let Some(valgrind_state) = &mut instance.valgrind_state { + // instance.valgrind_state.update_stack_pointer(value as usize); + } } } else { fn update_stack_pointer(_instance: &mut Instance, _value: u32) {} diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 26d89b0344b3..4b039a4ed136 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -134,3 +134,5 @@ component-model = [ "dep:wasmtime-component-util", "dep:encoding_rs", ] + +valgrind = ["wasmtime-runtime/valgrind", "wasmtime-cranelift/valgrind"] \ No newline at end of file diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index b0d5bdc87fa7..0d4cadb2f857 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -110,6 +110,7 @@ pub struct Config { pub(crate) memory_init_cow: bool, pub(crate) memory_guaranteed_dense_image_size: u64, pub(crate) force_memory_init_memfd: bool, + pub(crate) valgrind: bool, } /// User-provided configuration for the compiler. @@ -123,6 +124,7 @@ struct CompilerConfig { #[cfg(any(feature = "cranelift", feature = "winch"))] cache_store: Option>, clif_dir: Option, + valgrind: bool, } #[cfg(any(feature = "cranelift", feature = "winch"))] @@ -135,6 +137,7 @@ impl CompilerConfig { flags: HashSet::new(), cache_store: None, clif_dir: None, + valgrind: false, } } @@ -199,6 +202,7 @@ impl Config { memory_init_cow: true, memory_guaranteed_dense_image_size: 16 << 20, force_memory_init_memfd: false, + valgrind: false, }; #[cfg(any(feature = "cranelift", feature = "winch"))] { @@ -1450,6 +1454,13 @@ impl Config { self } + /// This option is disabled by default. + pub fn valgrind(&mut self, enable: bool) -> &mut Self { + self.valgrind = enable; + self.compiler_config.valgrind = enable; + self + } + /// Configures the "guaranteed dense image size" for copy-on-write /// initialized memories. /// @@ -1637,6 +1648,8 @@ impl Config { compiler.enable_incremental_compilation(cache_store.clone())?; } + compiler.valgrind(self.compiler_config.valgrind); + Ok((self, compiler.build()?)) } diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index 9350ffbd8bbc..3083385856a4 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -274,6 +274,7 @@ impl Instance { imports, host_state: Box::new(Instance(instance_to_be)), store: StorePtr::new(store.traitobj()), + valgrind: store.engine().config().valgrind, })?; // The instance still has lots of setup, for example diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index 71c1237e7ad9..4aa53fd0bfbb 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -1071,6 +1071,7 @@ impl std::hash::Hash for HashedEngineCompileEnv<'_> { let config = self.0.config(); config.tunables.hash(hasher); config.features.hash(hasher); + config.valgrind.hash(hasher); // Catch accidental bugs of reusing across crate versions. config.module_version.hash(hasher); diff --git a/crates/wasmtime/src/store.rs b/crates/wasmtime/src/store.rs index 930a73ee93aa..9a9c713c5394 100644 --- a/crates/wasmtime/src/store.rs +++ b/crates/wasmtime/src/store.rs @@ -498,6 +498,7 @@ impl Store { imports: Default::default(), store: StorePtr::empty(), runtime_info: &shim, + valgrind: engine.config().valgrind, }) .expect("failed to allocate default callee"); diff --git a/crates/wasmtime/src/trampoline.rs b/crates/wasmtime/src/trampoline.rs index cc9435131305..e712ac127abe 100644 --- a/crates/wasmtime/src/trampoline.rs +++ b/crates/wasmtime/src/trampoline.rs @@ -47,6 +47,7 @@ fn create_handle( host_state, store: StorePtr::new(store.traitobj()), runtime_info, + valgrind: false, }, )?; diff --git a/crates/wasmtime/src/trampoline/memory.rs b/crates/wasmtime/src/trampoline/memory.rs index e10e26bccf32..2813cf1d78f0 100644 --- a/crates/wasmtime/src/trampoline/memory.rs +++ b/crates/wasmtime/src/trampoline/memory.rs @@ -56,6 +56,7 @@ pub fn create_memory( host_state, store: StorePtr::new(store.traitobj()), runtime_info, + valgrind: false, }; unsafe { diff --git a/src/commands/run.rs b/src/commands/run.rs index 18eec5a500be..a0d1be7df59c 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -253,6 +253,10 @@ pub struct RunCommand { /// memory, for example. #[clap(long)] trap_on_grow_failure: bool, + + /// Run valgrind + #[clap(long)] + valgrind: bool, } enum Profile { @@ -281,6 +285,8 @@ impl RunCommand { None => {} } + config.valgrind(self.valgrind); + let engine = Engine::new(&config)?; let preopen_sockets = self.compute_preopen_sockets()?; From 8f5df300a6f0b5723a0eeaebb6573b10baead3af Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Thu, 3 Aug 2023 09:41:23 -0700 Subject: [PATCH 19/34] panic!() changed to bail!() --- crates/environ/src/builtin.rs | 4 ++-- crates/runtime/src/libcalls.rs | 38 +++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 1add32947841..9460a67a44ae 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -56,9 +56,9 @@ macro_rules! foreach_builtin_function { /// Memcheck invoked when free is called. check_free(vmctx: vmctx, addr: i32) -> i32; /// - check_load(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32); + check_load(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32) -> i32; /// - check_store(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32); + check_store(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32) -> i32; /// malloc_start(vmctx: vmctx); /// diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 42771142afef..78b5653fba6a 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -68,7 +68,7 @@ use wasmtime_environ::{ DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Trap, }; use cfg_if::cfg_if; -// use crate::wasm_valgrind::AccessError; +use anyhow::bail; /// Actually public trampolines which are used by the runtime as the entrypoint /// for libcalls. @@ -503,10 +503,10 @@ cfg_if! { return Ok(0); } Err(DoubleMalloc { addr, len }) => { - panic!("Double malloc at addr {} of size {}", addr, len) + bail!("Double malloc at addr {} of size {}", addr, len) } Err(OutOfBounds { addr, len }) => { - panic!("Malloc out of bounds at addr {} of size {}", addr, len); + bail!("Malloc out of bounds at addr {} of size {}", addr, len); } _ => { panic!("unreachable") @@ -533,7 +533,7 @@ cfg_if! { return Ok(0); } Err(InvalidFree { addr }) => { - panic!("Invalid free at addr {}", addr) + bail!("Invalid free at addr {:#x}", addr) } _ => { panic!("unreachable") @@ -552,49 +552,59 @@ cfg_if! { //should be returning result? error propogation? cfg_if! { if #[cfg(feature = "valgrind")] { - fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { + fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) -> Result { if let Some(valgrind_state) = &mut instance.valgrind_state { let result = valgrind_state.read(addr as usize + offset as usize, num_bytes as usize); match result { - Ok(()) => {} + Ok(()) => { + return Ok(0); + } Err(InvalidRead { addr, len }) => { - panic!("Invalid load at addr {} of size {}", addr, len) + bail!("Invalid load at addr {} of size {}", addr, len); } Err(OutOfBounds { addr, len }) => { - panic!("Load out of bounds at addr {} of size {}", addr, len); + bail!("Load out of bounds at addr {} of size {}", addr, len); } _ => { panic!("unreachable") } } } + Ok(0) } } else { - fn check_load(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) {} + fn check_load(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) -> Result { + Ok(0) + } } } cfg_if! { if #[cfg(feature = "valgrind")] { - fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) { + fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) -> Result { if let Some(valgrind_state) = &mut instance.valgrind_state { let result = valgrind_state.write(addr as usize + offset as usize, num_bytes as usize); match result { - Ok(()) => {} + Ok(()) => { + return Ok(0); + } Err(InvalidWrite { addr, len }) => { - panic!("Invalid store at addr {} of size {}", addr, len) + bail!("Invalid store at addr {} of size {}", addr, len) } Err(OutOfBounds { addr, len }) => { - panic!("Store out of bounds at addr {} of size {}", addr, len); + bail!("Store out of bounds at addr {} of size {}", addr, len) } _ => { panic!("unreachable") } } } + Ok(0) } } else { - fn check_store(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) {} + fn check_store(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) -> Result { + Ok(0) + } } } From e2d929c6f43c8c8cde6a8a545e2b907b556b45d5 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Mon, 7 Aug 2023 09:21:02 -0700 Subject: [PATCH 20/34] started adding doc comments --- cranelift/wasm/src/environ/spec.rs | 1 - crates/cranelift/src/func_environ.rs | 46 ++++++---------- crates/environ/src/builtin.rs | 14 ++--- crates/environ/src/compilation.rs | 2 +- crates/runtime/src/instance.rs | 4 +- crates/runtime/src/libcalls.rs | 78 ++++++++++------------------ crates/valgrind/src/lib.rs | 6 +-- 7 files changed, 52 insertions(+), 99 deletions(-) diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index f3c91ffea107..da3faf97d1e7 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -592,7 +592,6 @@ pub trait FuncEnvironment: TargetEnvironment { fn handle_before_return(&mut self, retvals: &[ir::Value], builder: &mut FunctionBuilder) {} /// - // Type::bytes (?) fn before_load(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) {} /// diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index ec9506499e67..6b2be60a9215 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -2215,7 +2215,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m Ok(()) } - //insert entry hook calls here? fn before_translate_function( &mut self, builder: &mut FunctionBuilder, @@ -2319,17 +2318,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } } - } else { - fn handle_before_return(&mut self, _retvals: &[Value], builder: &mut FunctionBuilder, - ) { - let _ = self.builtin_function_signatures.check_malloc(builder.func); - let _ = self.builtin_function_signatures.check_free(builder.func); - } - } - } - - cfg_if! { - if #[cfg(feature = "valgrind")] { fn before_load(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { if self.valgrind { let check_load_sig = self.builtin_function_signatures.check_load(builder.func); @@ -2339,22 +2327,13 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m ); let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); let offset_val = builder.ins().iconst(I64, offset as i64); - let addr_and_offset = builder.ins().iadd(offset_val, addr); + // let addr_and_offset = builder.ins().iadd(offset_val, addr); builder .ins() .call_indirect(check_load_sig, check_load, &[vmctx, num_bytes, addr, offset_val]); } } - } else { - fn before_load(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { - // aren't using check_load, avoiding warnings - let _ = self.builtin_function_signatures.check_load(builder.func); - } - } - } - cfg_if! { - if #[cfg(feature = "valgrind")] { fn before_store(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { if self.valgrind { let check_store_sig = self.builtin_function_signatures.check_store(builder.func); @@ -2368,17 +2347,8 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m .ins() .call_indirect(check_store_sig, check_store, &[vmctx, num_bytes, addr, offset_val]); } - } - } else { - fn before_store(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { - let _ = self.builtin_function_signatures.check_store(builder.func); - } - } - } - cfg_if! { - if #[cfg(feature = "valgrind")] { fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) { if self.valgrind { if global_index == 0 { @@ -2393,7 +2363,21 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } } } + } else { + fn handle_before_return(&mut self, _retvals: &[Value], builder: &mut FunctionBuilder) { + let _ = self.builtin_function_signatures.check_malloc(builder.func); + let _ = self.builtin_function_signatures.check_free(builder.func); + } + + fn before_load(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { + let _ = self.builtin_function_signatures.check_load(builder.func); + } + + fn before_store(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { + let _ = self.builtin_function_signatures.check_store(builder.func); + } + fn update_global(&mut self, builder: &mut FunctionBuilder, _global_index: u32, _value: ir::Value) { let _ = self.builtin_function_signatures.update_stack_pointer(builder.func); } diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 9460a67a44ae..b1a9ae37ee0f 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -51,19 +51,19 @@ macro_rules! foreach_builtin_function { out_of_gas(vmctx: vmctx); /// Invoked when we reach a new epoch. new_epoch(vmctx: vmctx) -> i64; - /// Memcheck invoked when malloc is called. + /// Invoked before malloc returns. check_malloc(vmctx: vmctx, addr: i32, len: i32) -> i32; - /// Memcheck invoked when free is called. + /// Invoked before the free returns. check_free(vmctx: vmctx, addr: i32) -> i32; - /// + /// Invoked before a load is executed. check_load(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32) -> i32; - /// + /// Invoked before a store is executed. check_store(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32) -> i32; - /// + /// Invoked after malloc is called. malloc_start(vmctx: vmctx); - /// + /// Invoked after free is called. free_start(vmctx: vmctx); - /// + /// Invoked when wasm stack pointer is updated. update_stack_pointer(vmctx: vmctx, value: i32); } }; diff --git a/crates/environ/src/compilation.rs b/crates/environ/src/compilation.rs index 0c73aa2f8bd0..265a9b5ec7da 100644 --- a/crates/environ/src/compilation.rs +++ b/crates/environ/src/compilation.rs @@ -125,7 +125,7 @@ pub trait CompilerBuilder: Send + Sync + fmt::Debug { /// Builds a new [`Compiler`] object from this configuration. fn build(&self) -> Result>; - /// + /// Enables or disables valgrind during runtime according to the valgrind CLI flag. fn valgrind(&mut self, enable: bool) {} } diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index 351a8949d937..2dc0fc2257b9 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -194,11 +194,11 @@ impl Instance { #[cfg(feature = "valgrind")] valgrind_state: { if req.valgrind { - const MiB: usize = 1024 * 1024; // 1 MiB + const MIB: usize = 1024 * 1024; // 1 MiB // ad-hoc testing seems to show... // TODO: how do we determine this more consistently? // const C_STACK_SIZE: usize = 70863; - Some(Valgrind::new(128 * MiB)) + Some(Valgrind::new(128 * MIB)) } else { None } diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 78b5653fba6a..5432367f5acf 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -493,8 +493,8 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { cfg_if! { if #[cfg(feature = "valgrind")] { + // Hook for validating malloc using valgrind_state. unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { - //safe to unwrap bc function will never be called when valgrind_state == None if let Some(valgrind_state) = &mut instance.valgrind_state { let result = valgrind_state.malloc(addr as usize, len as usize); valgrind_state.memcheck_on(); @@ -503,10 +503,10 @@ cfg_if! { return Ok(0); } Err(DoubleMalloc { addr, len }) => { - bail!("Double malloc at addr {} of size {}", addr, len) + bail!("Double malloc at addr {:#x} of size {}", addr, len) } Err(OutOfBounds { addr, len }) => { - bail!("Malloc out of bounds at addr {} of size {}", addr, len); + bail!("Malloc out of bounds at addr {:#x} of size {}", addr, len); } _ => { panic!("unreachable") @@ -515,15 +515,8 @@ cfg_if! { } Ok(0) } - } else { - unsafe fn check_malloc(_instance: &mut Instance, _addr: u32, _len: u32) -> Result { - Ok(0) - } - } -} -cfg_if! { - if #[cfg(feature = "valgrind")] { + // Hook for validating free using valgrind_state. unsafe fn check_free(instance: &mut Instance, addr: u32) -> Result { if let Some(valgrind_state) = &mut instance.valgrind_state { let result = valgrind_state.free(addr as usize); @@ -542,16 +535,8 @@ cfg_if! { } Ok(0) } - } else { - unsafe fn check_free(_instance: &mut Instance, _addr: u32) -> Result { - Ok(0) - } - } -} -//should be returning result? error propogation? -cfg_if! { - if #[cfg(feature = "valgrind")] { + // Hook for validating load using valgrind_state. fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) -> Result { if let Some(valgrind_state) = &mut instance.valgrind_state { let result = valgrind_state.read(addr as usize + offset as usize, num_bytes as usize); @@ -560,10 +545,10 @@ cfg_if! { return Ok(0); } Err(InvalidRead { addr, len }) => { - bail!("Invalid load at addr {} of size {}", addr, len); + bail!("Invalid load at addr {:#x} of size {}", addr, len); } Err(OutOfBounds { addr, len }) => { - bail!("Load out of bounds at addr {} of size {}", addr, len); + bail!("Load out of bounds at addr {:#x} of size {}", addr, len); } _ => { panic!("unreachable") @@ -572,15 +557,8 @@ cfg_if! { } Ok(0) } - } else { - fn check_load(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) -> Result { - Ok(0) - } - } -} -cfg_if! { - if #[cfg(feature = "valgrind")] { + // Hook for validating store using valgrind_state. fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) -> Result { if let Some(valgrind_state) = &mut instance.valgrind_state { let result = valgrind_state.write(addr as usize + offset as usize, num_bytes as usize); @@ -589,10 +567,10 @@ cfg_if! { return Ok(0); } Err(InvalidWrite { addr, len }) => { - bail!("Invalid store at addr {} of size {}", addr, len) + bail!("Invalid store at addr {:#x} of size {}", addr, len) } Err(OutOfBounds { addr, len }) => { - bail!("Store out of bounds at addr {} of size {}", addr, len) + bail!("Store out of bounds at addr {:#x} of size {}", addr, len) } _ => { panic!("unreachable") @@ -601,45 +579,41 @@ cfg_if! { } Ok(0) } - } else { - fn check_store(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) -> Result { - Ok(0) - } - } -} -cfg_if! { - if #[cfg(feature = "valgrind")] { + // Hook for turning valgrind load/store validation off when entering a malloc function. fn malloc_start(instance: &mut Instance) { if let Some(valgrind_state) = &mut instance.valgrind_state { valgrind_state.memcheck_off(); } } - } else { - fn malloc_start(_instance: &mut Instance) {} - } -} -cfg_if! { - if #[cfg(feature = "valgrind")] { + // Hook for turning valgrind load/store validation off when entering a free function. fn free_start(instance: &mut Instance) { if let Some(valgrind_state) = &mut instance.valgrind_state { valgrind_state.memcheck_off(); } } - } else { - fn free_start(_instance: &mut Instance) {} - } -} -cfg_if! { - if #[cfg(feature = "valgrind")] { + // Hook for tracking wasm stack updates using valgrind_state. fn update_stack_pointer(instance: &mut Instance, value: u32) { if let Some(valgrind_state) = &mut instance.valgrind_state { // instance.valgrind_state.update_stack_pointer(value as usize); } } } else { + // No-op for all valgrind hooks. + unsafe fn check_malloc(_instance: &mut Instance, _addr: u32, _len: u32) -> Result { Ok(0) } + + unsafe fn check_free(_instance: &mut Instance, _addr: u32) -> Result { Ok(0) } + + fn check_load(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) -> Result { Ok(0) } + + fn check_store(_instance: &mut Instance, _num_bytes: u32, _addr: u32, _offset: u32) -> Result { Ok(0) } + + fn malloc_start(_instance: &mut Instance) {} + + fn free_start(_instance: &mut Instance) {} + fn update_stack_pointer(_instance: &mut Instance, _value: u32) {} } } diff --git a/crates/valgrind/src/lib.rs b/crates/valgrind/src/lib.rs index 4002f5c8a61a..1e7ff09d2d16 100644 --- a/crates/valgrind/src/lib.rs +++ b/crates/valgrind/src/lib.rs @@ -1,13 +1,9 @@ -/* -The following implementation assumes that the stack sits at the bottom of memory. -*/ - use std::cmp::*; use std::collections::HashMap; pub struct Valgrind { metadata: Vec, - mallocs: HashMap, // start addr, len + mallocs: HashMap, pub stack_pointer: usize, max_stack_size: usize, pub flag: bool, From 3e9e823fc47fd3c4a06da141aca31ca4b318334b Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Tue, 8 Aug 2023 10:50:09 -0700 Subject: [PATCH 21/34] added memory grow hook + fixed access size handling --- cranelift/wasm/src/code_translator.rs | 11 +- cranelift/wasm/src/environ/spec.rs | 7 +- crates/cranelift/src/func_environ.rs | 27 +- crates/environ/src/builtin.rs | 2 + crates/runtime/src/instance.rs | 12 +- crates/runtime/src/instance/allocator.rs | 2 +- crates/runtime/src/libcalls.rs | 11 + crates/valgrind/src/lib.rs | 17 +- malloc_twice.wat | 10465 +++++++++++++++++++++ test.wasm | Bin 0 -> 4756 bytes 10 files changed, 10533 insertions(+), 21 deletions(-) create mode 100644 malloc_twice.wat create mode 100644 test.wasm diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index a17479d4ee18..e359418e2491 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -686,6 +686,7 @@ pub fn translate_operator( let heap_index = MemoryIndex::from_u32(*mem); let heap = state.get_heap(builder.func, *mem, environ)?; let val = state.pop1(); + environ.before_memory_grow(builder, val); state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?) } Operator::MemorySize { mem, mem_byte: _ } => { @@ -2806,9 +2807,10 @@ fn translate_load( state: &mut FuncTranslationState, environ: &mut FE, ) -> WasmResult> { + let mem_op_size = mem_op_size(opcode, result_ty); let (flags, wasm_index, base) = match prepare_addr( memarg, - mem_op_size(opcode, result_ty), + mem_op_size, builder, state, environ, @@ -2817,7 +2819,7 @@ fn translate_load( Reachability::Reachable((f, i, b)) => (f, i, b), }; - environ.before_load(builder, result_ty, wasm_index, memarg.offset); + environ.before_load(builder, mem_op_size, wasm_index, memarg.offset); let (load, dfg) = builder .ins() @@ -2836,13 +2838,14 @@ fn translate_store( ) -> WasmResult<()> { let val = state.pop1(); let val_ty = builder.func.dfg.value_type(val); + let mem_op_size = mem_op_size(opcode, val_ty); let (flags, wasm_index, base) = unwrap_or_return_unreachable_state!( state, - prepare_addr(memarg, mem_op_size(opcode, val_ty), builder, state, environ)? + prepare_addr(memarg, mem_op_size, builder, state, environ)? ); - environ.before_store(builder, val_ty, wasm_index, memarg.offset); + environ.before_store(builder, mem_op_size, wasm_index, memarg.offset); builder .ins() diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index da3faf97d1e7..3aafb679a7c4 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -592,13 +592,16 @@ pub trait FuncEnvironment: TargetEnvironment { fn handle_before_return(&mut self, retvals: &[ir::Value], builder: &mut FunctionBuilder) {} /// - fn before_load(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) {} + fn before_load(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) {} /// - fn before_store(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) {} + fn before_store(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) {} /// fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) {} + + /// + fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, num_bytes: ir::Value) {} } /// An object satisfying the `ModuleEnvironment` trait can be passed as argument to the diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 6b2be60a9215..30b257d9cff6 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -2299,8 +2299,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m builder: &mut FunctionBuilder, ) { if self.valgrind { - let block = builder.func.layout.entry_block().unwrap(); - let args = builder.func.dfg.block_params(block); let func_index = match &builder.func.name { UserFuncName::User(user) => { FuncIndex::from_u32(user.index) @@ -2318,30 +2316,29 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } } - fn before_load(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { + fn before_load(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) { if self.valgrind { let check_load_sig = self.builtin_function_signatures.check_load(builder.func); let (vmctx, check_load) = self.translate_load_builtin_function_address( &mut builder.cursor(), BuiltinFunctionIndex::check_load(), ); - let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); + let num_bytes = builder.ins().iconst(I32, val_size as i64); let offset_val = builder.ins().iconst(I64, offset as i64); - // let addr_and_offset = builder.ins().iadd(offset_val, addr); builder .ins() .call_indirect(check_load_sig, check_load, &[vmctx, num_bytes, addr, offset_val]); } } - fn before_store(&mut self, builder: &mut FunctionBuilder, val_type: Type, addr: ir::Value, offset: u64) { + fn before_store(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) { if self.valgrind { let check_store_sig = self.builtin_function_signatures.check_store(builder.func); let (vmctx, check_store) = self.translate_load_builtin_function_address( &mut builder.cursor(), BuiltinFunctionIndex::check_store(), ); - let num_bytes = builder.ins().iconst(I32, val_type.bytes() as i64); + let num_bytes = builder.ins().iconst(I32, val_size as i64); let offset_val = builder.ins().iconst(I64, offset as i64); builder .ins() @@ -2364,6 +2361,18 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } } + fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, num_pages: ir::Value) { + if self.valgrind { + let update_mem_size_sig = self.builtin_function_signatures.update_mem_size(builder.func); + let (vmctx, update_mem_size) = self.translate_load_builtin_function_address( + &mut builder.cursor(), + BuiltinFunctionIndex::update_mem_size(), + ); + builder + .ins() + .call_indirect(update_mem_size_sig, update_mem_size, &[vmctx, num_pages]); + } + } } else { fn handle_before_return(&mut self, _retvals: &[Value], builder: &mut FunctionBuilder) { let _ = self.builtin_function_signatures.check_malloc(builder.func); @@ -2381,6 +2390,10 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m fn update_global(&mut self, builder: &mut FunctionBuilder, _global_index: u32, _value: ir::Value) { let _ = self.builtin_function_signatures.update_stack_pointer(builder.func); } + + fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, _num_pages: Value) { + let _ = self.builtin_function_signatures.update_mem_size(builder.func); + } } } } diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index b1a9ae37ee0f..07a5a03ab5dd 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -65,6 +65,8 @@ macro_rules! foreach_builtin_function { free_start(vmctx: vmctx); /// Invoked when wasm stack pointer is updated. update_stack_pointer(vmctx: vmctx, value: i32); + /// Invoked before memory.grow is called. + update_mem_size(vmctx: vmctx, num_bytes: i32); } }; } diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index 2dc0fc2257b9..6ad973f5dc8a 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -33,6 +33,7 @@ use wasmtime_environ::{ DefinedTableIndex, ElemIndex, EntityIndex, EntityRef, EntitySet, FuncIndex, GlobalIndex, GlobalInit, HostPtr, MemoryIndex, Module, PrimaryMap, SignatureIndex, TableIndex, TableInitialValue, Trap, VMOffsets, WasmHeapType, WasmRefType, WasmType, VMCONTEXT_MAGIC, + MemoryPlan, }; mod allocator; @@ -162,6 +163,7 @@ impl Instance { index: usize, memories: PrimaryMap, tables: PrimaryMap, + memory_plans: &PrimaryMap, ) -> InstanceHandle { // The allocation must be *at least* the size required of `Instance`. let layout = Self::alloc_layout(req.runtime_info.offsets()); @@ -194,16 +196,13 @@ impl Instance { #[cfg(feature = "valgrind")] valgrind_state: { if req.valgrind { - const MIB: usize = 1024 * 1024; // 1 MiB - // ad-hoc testing seems to show... - // TODO: how do we determine this more consistently? - // const C_STACK_SIZE: usize = 70863; - Some(Valgrind::new(128 * MIB)) + let size = memory_plans.iter().next().map(|plan| plan.1.memory.minimum).unwrap_or(0) * 64 * 1024; + println!("this is the size: {}", size); + Some(Valgrind::new(size as usize)) } else { None } }, - // not sure how to access mem & stack size? }, ); @@ -1147,6 +1146,7 @@ impl Instance { GlobalInit::I32Const(x) => { let index = module.global_index(index); if index.index() == 0 { + println!("stack pointer: {}", x); #[cfg(feature = "valgrind")] { if let Some(valgrind) = &mut self.valgrind_state { valgrind.set_stack_size(x as usize); diff --git a/crates/runtime/src/instance/allocator.rs b/crates/runtime/src/instance/allocator.rs index 15163d9fef1e..1893dcffe226 100644 --- a/crates/runtime/src/instance/allocator.rs +++ b/crates/runtime/src/instance/allocator.rs @@ -123,7 +123,7 @@ pub unsafe trait InstanceAllocator { return Err(e); } - unsafe { Ok(Instance::new(req, index, memories, tables)) } + unsafe { Ok(Instance::new(req, index, memories, tables, &module.memory_plans)) } } /// Deallocates the provided instance. diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 5432367f5acf..127dc192f223 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -600,6 +600,15 @@ cfg_if! { // instance.valgrind_state.update_stack_pointer(value as usize); } } + + // Hook updating valgrind_state memory state vector every time memory.grow is called. + fn update_mem_size(instance: &mut Instance, num_pages: u32) { + if let Some(valgrind_state) = &mut instance.valgrind_state { + let kib: usize = 1024; + let num_bytes = num_pages as usize * kib * 64; + valgrind_state.update_mem_size(num_bytes); + } + } } else { // No-op for all valgrind hooks. unsafe fn check_malloc(_instance: &mut Instance, _addr: u32, _len: u32) -> Result { Ok(0) } @@ -615,6 +624,8 @@ cfg_if! { fn free_start(_instance: &mut Instance) {} fn update_stack_pointer(_instance: &mut Instance, _value: u32) {} + + fn update_mem_size(instance: &mut Instance, _num_pages: u32) {} } } diff --git a/crates/valgrind/src/lib.rs b/crates/valgrind/src/lib.rs index 1e7ff09d2d16..2e8875bc25b4 100644 --- a/crates/valgrind/src/lib.rs +++ b/crates/valgrind/src/lib.rs @@ -37,6 +37,7 @@ impl Valgrind { flag: true, } } + pub fn malloc(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { if !self.is_in_bounds_heap(addr, len) { return Err(AccessError::OutOfBounds { @@ -67,6 +68,7 @@ impl Valgrind { self.mallocs.insert(addr, len); Ok(()) } + pub fn read(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { if !self.flag { return Ok(()); @@ -96,6 +98,7 @@ impl Valgrind { } Ok(()) } + pub fn write(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { if !self.flag { return Ok(()); @@ -119,6 +122,7 @@ impl Valgrind { } Ok(()) } + pub fn free(&mut self, addr: usize) -> Result<(), AccessError> { if !self.mallocs.contains_key(&addr) { return Err(AccessError::InvalidFree { addr: addr }); @@ -135,12 +139,15 @@ impl Valgrind { } Ok(()) } + fn is_in_bounds_heap(&self, addr: usize, len: usize) -> bool { self.max_stack_size <= addr && addr + len <= self.metadata.len() } + fn is_in_bounds_stack(&self, addr: usize, len: usize) -> bool { self.stack_pointer <= addr && addr + len < self.max_stack_size } + pub fn update_stack_pointer(&mut self, new_sp: usize) -> Result<(), AccessError> { if new_sp > self.max_stack_size { return Err(AccessError::OutOfBounds { @@ -160,18 +167,26 @@ impl Valgrind { self.stack_pointer = new_sp; Ok(()) } + pub fn memcheck_on(&mut self) { self.flag = true; } + pub fn memcheck_off(&mut self) { self.flag = false; } + pub fn set_stack_size(&mut self, stack_size: usize) { self.max_stack_size = stack_size + 1; //temporary solution to initialize the entire stack //while keeping stack tracing plumbing in place self.stack_pointer = stack_size; - self.update_stack_pointer(0); + let _ = self.update_stack_pointer(0); + } + + pub fn update_mem_size(&mut self, num_bytes: usize) { + let to_append = vec![MemState::Unallocated; num_bytes]; + self.metadata.extend(to_append); } } diff --git a/malloc_twice.wat b/malloc_twice.wat new file mode 100644 index 000000000000..e2e2af5273ca --- /dev/null +++ b/malloc_twice.wat @@ -0,0 +1,10465 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i64 i32) (result i64))) + (type (;2;) (func (param i32) (result i32))) + (type (;3;) (func (param i32 i32) (result i32))) + (type (;4;) (func (param i32 i64 i32 i32) (result i32))) + (type (;5;) (func (param i32 i32 i32 i32) (result i32))) + (type (;6;) (func (param i32))) + (type (;7;) (func)) + (type (;8;) (func (result i32))) + (type (;9;) (func (param f64 i32) (result f64))) + (type (;10;) (func (param i32 i32 i32 i32 i32) (result i32))) + (type (;11;) (func (param i32 i32 i32))) + (type (;12;) (func (param i32 i32 i32 i32 i32))) + (import "wasi_snapshot_preview1" "fd_close" (func $__imported_wasi_snapshot_preview1_fd_close (type 2))) + (import "wasi_snapshot_preview1" "fd_fdstat_get" (func $__imported_wasi_snapshot_preview1_fd_fdstat_get (type 3))) + (import "wasi_snapshot_preview1" "fd_seek" (func $__imported_wasi_snapshot_preview1_fd_seek (type 4))) + (import "wasi_snapshot_preview1" "fd_write" (func $__imported_wasi_snapshot_preview1_fd_write (type 5))) + (import "wasi_snapshot_preview1" "proc_exit" (func $__imported_wasi_snapshot_preview1_proc_exit (type 6))) + (func $__wasm_call_ctors (type 7)) + (func $_start (type 7) + (local i32) + block ;; label = @1 + block ;; label = @2 + i32.const 0 + i32.load offset=3728 + br_if 0 (;@2;) + i32.const 0 + i32.const 1 + i32.store offset=3728 + call $__wasm_call_ctors + call $__original_main + local.set 0 + call $__wasm_call_dtors + local.get 0 + br_if 1 (;@1;) + return + end + unreachable + unreachable + end + local.get 0 + call $__wasi_proc_exit + unreachable) + (func $__original_main (type 8) (result i32) + (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) + global.get $__stack_pointer + local.set 0 + i32.const 48 + local.set 1 + local.get 0 + local.get 1 + i32.sub + local.set 2 + local.get 2 + global.set $__stack_pointer + i32.const 40000 + local.set 3 + local.get 3 + call $malloc + local.set 4 + local.get 2 + local.get 4 + i32.store offset=44 + local.get 2 + i32.load offset=44 + local.set 5 + local.get 2 + local.get 5 + i32.store + i32.const 1115 + local.set 6 + local.get 6 + local.get 2 + call $printf + drop + i32.const 1078 + local.set 7 + i32.const 0 + local.set 8 + local.get 7 + local.get 8 + call $printf + drop + local.get 2 + i32.load offset=44 + local.set 9 + i32.const 1 + local.set 10 + local.get 9 + local.get 10 + i32.store8 + local.get 2 + i32.load offset=44 + local.set 11 + i32.const 2 + local.set 12 + local.get 11 + local.get 12 + i32.store8 offset=1 + local.get 2 + i32.load offset=44 + local.set 13 + local.get 13 + i32.load8_u + local.set 14 + i32.const 24 + local.set 15 + local.get 14 + local.get 15 + i32.shl + local.set 16 + local.get 16 + local.get 15 + i32.shr_s + local.set 17 + local.get 2 + i32.load offset=44 + local.set 18 + local.get 18 + i32.load8_u offset=1 + local.set 19 + i32.const 24 + local.set 20 + local.get 19 + local.get 20 + i32.shl + local.set 21 + local.get 21 + local.get 20 + i32.shr_s + local.set 22 + local.get 2 + local.get 22 + i32.store offset=20 + local.get 2 + local.get 17 + i32.store offset=16 + i32.const 1135 + local.set 23 + i32.const 16 + local.set 24 + local.get 2 + local.get 24 + i32.add + local.set 25 + local.get 23 + local.get 25 + call $printf + drop + i32.const 40000 + local.set 26 + local.get 26 + call $malloc + local.set 27 + local.get 2 + local.get 27 + i32.store offset=40 + local.get 2 + i32.load offset=40 + local.set 28 + local.get 2 + local.get 28 + i32.store offset=32 + i32.const 1098 + local.set 29 + i32.const 32 + local.set 30 + local.get 2 + local.get 30 + i32.add + local.set 31 + local.get 29 + local.get 31 + call $printf + drop + i32.const 0 + local.set 32 + i32.const 48 + local.set 33 + local.get 2 + local.get 33 + i32.add + local.set 34 + local.get 34 + global.set $__stack_pointer + local.get 32 + return) + (func $malloc (type 2) (param i32) (result i32) + local.get 0 + call $dlmalloc) + (func $dlmalloc (type 2) (param i32) (result i32) + (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 1 + global.set $__stack_pointer + block ;; label = @1 + i32.const 0 + i32.load offset=3756 + local.tee 2 + br_if 0 (;@1;) + block ;; label = @2 + block ;; label = @3 + i32.const 0 + i32.load offset=4204 + local.tee 3 + i32.eqz + br_if 0 (;@3;) + i32.const 0 + i32.load offset=4208 + local.set 4 + br 1 (;@2;) + end + i32.const 0 + i64.const -1 + i64.store offset=4216 align=4 + i32.const 0 + i64.const 281474976776192 + i64.store offset=4208 align=4 + i32.const 0 + local.get 1 + i32.const 8 + i32.add + i32.const -16 + i32.and + i32.const 1431655768 + i32.xor + local.tee 3 + i32.store offset=4204 + i32.const 0 + i32.const 0 + i32.store offset=4224 + i32.const 0 + i32.const 0 + i32.store offset=4176 + i32.const 65536 + local.set 4 + end + i32.const 0 + local.set 2 + i32.const 131072 + i32.const 70864 + local.get 4 + i32.add + i32.const -1 + i32.add + i32.const 0 + local.get 4 + i32.sub + i32.and + i32.const 131072 + select + i32.const 70864 + i32.sub + local.tee 5 + i32.const 89 + i32.lt_u + br_if 0 (;@1;) + i32.const 0 + local.set 4 + i32.const 0 + local.get 5 + i32.store offset=4184 + i32.const 0 + i32.const 70864 + i32.store offset=4180 + i32.const 0 + i32.const 70864 + i32.store offset=3748 + i32.const 0 + local.get 3 + i32.store offset=3768 + i32.const 0 + i32.const -1 + i32.store offset=3764 + loop ;; label = @2 + local.get 4 + i32.const 3792 + i32.add + local.get 4 + i32.const 3780 + i32.add + local.tee 3 + i32.store + local.get 3 + local.get 4 + i32.const 3772 + i32.add + local.tee 6 + i32.store + local.get 4 + i32.const 3784 + i32.add + local.get 6 + i32.store + local.get 4 + i32.const 3800 + i32.add + local.get 4 + i32.const 3788 + i32.add + local.tee 6 + i32.store + local.get 6 + local.get 3 + i32.store + local.get 4 + i32.const 3808 + i32.add + local.get 4 + i32.const 3796 + i32.add + local.tee 3 + i32.store + local.get 3 + local.get 6 + i32.store + local.get 4 + i32.const 3804 + i32.add + local.get 3 + i32.store + local.get 4 + i32.const 32 + i32.add + local.tee 4 + i32.const 256 + i32.ne + br_if 0 (;@2;) + end + i32.const 70864 + i32.const -8 + i32.const 70864 + i32.sub + i32.const 15 + i32.and + i32.const 0 + i32.const 70864 + i32.const 8 + i32.add + i32.const 15 + i32.and + select + local.tee 4 + i32.add + local.tee 2 + i32.const 4 + i32.add + local.get 5 + i32.const -56 + i32.add + local.tee 3 + local.get 4 + i32.sub + local.tee 4 + i32.const 1 + i32.or + i32.store + i32.const 0 + i32.const 0 + i32.load offset=4220 + i32.store offset=3760 + i32.const 0 + local.get 4 + i32.store offset=3744 + i32.const 0 + local.get 2 + i32.store offset=3756 + i32.const 70864 + local.get 3 + i32.add + i32.const 56 + i32.store offset=4 + end + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + block ;; label = @6 + block ;; label = @7 + block ;; label = @8 + block ;; label = @9 + block ;; label = @10 + block ;; label = @11 + block ;; label = @12 + local.get 0 + i32.const 236 + i32.gt_u + br_if 0 (;@12;) + block ;; label = @13 + i32.const 0 + i32.load offset=3732 + local.tee 7 + i32.const 16 + local.get 0 + i32.const 19 + i32.add + i32.const -16 + i32.and + local.get 0 + i32.const 11 + i32.lt_u + select + local.tee 5 + i32.const 3 + i32.shr_u + local.tee 3 + i32.shr_u + local.tee 4 + i32.const 3 + i32.and + i32.eqz + br_if 0 (;@13;) + block ;; label = @14 + block ;; label = @15 + local.get 4 + i32.const 1 + i32.and + local.get 3 + i32.or + i32.const 1 + i32.xor + local.tee 6 + i32.const 3 + i32.shl + local.tee 3 + i32.const 3772 + i32.add + local.tee 4 + local.get 3 + i32.const 3780 + i32.add + i32.load + local.tee 3 + i32.load offset=8 + local.tee 5 + i32.ne + br_if 0 (;@15;) + i32.const 0 + local.get 7 + i32.const -2 + local.get 6 + i32.rotl + i32.and + i32.store offset=3732 + br 1 (;@14;) + end + local.get 4 + local.get 5 + i32.store offset=8 + local.get 5 + local.get 4 + i32.store offset=12 + end + local.get 3 + i32.const 8 + i32.add + local.set 4 + local.get 3 + local.get 6 + i32.const 3 + i32.shl + local.tee 6 + i32.const 3 + i32.or + i32.store offset=4 + local.get 3 + local.get 6 + i32.add + local.tee 3 + local.get 3 + i32.load offset=4 + i32.const 1 + i32.or + i32.store offset=4 + br 12 (;@1;) + end + local.get 5 + i32.const 0 + i32.load offset=3740 + local.tee 8 + i32.le_u + br_if 1 (;@11;) + block ;; label = @13 + local.get 4 + i32.eqz + br_if 0 (;@13;) + block ;; label = @14 + block ;; label = @15 + local.get 4 + local.get 3 + i32.shl + i32.const 2 + local.get 3 + i32.shl + local.tee 4 + i32.const 0 + local.get 4 + i32.sub + i32.or + i32.and + local.tee 4 + i32.const 0 + local.get 4 + i32.sub + i32.and + i32.ctz + local.tee 3 + i32.const 3 + i32.shl + local.tee 4 + i32.const 3772 + i32.add + local.tee 6 + local.get 4 + i32.const 3780 + i32.add + i32.load + local.tee 4 + i32.load offset=8 + local.tee 0 + i32.ne + br_if 0 (;@15;) + i32.const 0 + local.get 7 + i32.const -2 + local.get 3 + i32.rotl + i32.and + local.tee 7 + i32.store offset=3732 + br 1 (;@14;) + end + local.get 6 + local.get 0 + i32.store offset=8 + local.get 0 + local.get 6 + i32.store offset=12 + end + local.get 4 + local.get 5 + i32.const 3 + i32.or + i32.store offset=4 + local.get 4 + local.get 3 + i32.const 3 + i32.shl + local.tee 3 + i32.add + local.get 3 + local.get 5 + i32.sub + local.tee 6 + i32.store + local.get 4 + local.get 5 + i32.add + local.tee 0 + local.get 6 + i32.const 1 + i32.or + i32.store offset=4 + block ;; label = @14 + local.get 8 + i32.eqz + br_if 0 (;@14;) + local.get 8 + i32.const -8 + i32.and + i32.const 3772 + i32.add + local.set 5 + i32.const 0 + i32.load offset=3752 + local.set 3 + block ;; label = @15 + block ;; label = @16 + local.get 7 + i32.const 1 + local.get 8 + i32.const 3 + i32.shr_u + i32.shl + local.tee 9 + i32.and + br_if 0 (;@16;) + i32.const 0 + local.get 7 + local.get 9 + i32.or + i32.store offset=3732 + local.get 5 + local.set 9 + br 1 (;@15;) + end + local.get 5 + i32.load offset=8 + local.set 9 + end + local.get 9 + local.get 3 + i32.store offset=12 + local.get 5 + local.get 3 + i32.store offset=8 + local.get 3 + local.get 5 + i32.store offset=12 + local.get 3 + local.get 9 + i32.store offset=8 + end + local.get 4 + i32.const 8 + i32.add + local.set 4 + i32.const 0 + local.get 0 + i32.store offset=3752 + i32.const 0 + local.get 6 + i32.store offset=3740 + br 12 (;@1;) + end + i32.const 0 + i32.load offset=3736 + local.tee 10 + i32.eqz + br_if 1 (;@11;) + local.get 10 + i32.const 0 + local.get 10 + i32.sub + i32.and + i32.ctz + i32.const 2 + i32.shl + i32.const 4036 + i32.add + i32.load + local.tee 0 + i32.load offset=4 + i32.const -8 + i32.and + local.get 5 + i32.sub + local.set 3 + local.get 0 + local.set 6 + block ;; label = @13 + loop ;; label = @14 + block ;; label = @15 + local.get 6 + i32.load offset=16 + local.tee 4 + br_if 0 (;@15;) + local.get 6 + i32.const 20 + i32.add + i32.load + local.tee 4 + i32.eqz + br_if 2 (;@13;) + end + local.get 4 + i32.load offset=4 + i32.const -8 + i32.and + local.get 5 + i32.sub + local.tee 6 + local.get 3 + local.get 6 + local.get 3 + i32.lt_u + local.tee 6 + select + local.set 3 + local.get 4 + local.get 0 + local.get 6 + select + local.set 0 + local.get 4 + local.set 6 + br 0 (;@14;) + end + end + local.get 0 + i32.load offset=24 + local.set 11 + block ;; label = @13 + local.get 0 + i32.load offset=12 + local.tee 9 + local.get 0 + i32.eq + br_if 0 (;@13;) + local.get 0 + i32.load offset=8 + local.tee 4 + i32.const 0 + i32.load offset=3748 + i32.lt_u + drop + local.get 9 + local.get 4 + i32.store offset=8 + local.get 4 + local.get 9 + i32.store offset=12 + br 11 (;@2;) + end + block ;; label = @13 + local.get 0 + i32.const 20 + i32.add + local.tee 6 + i32.load + local.tee 4 + br_if 0 (;@13;) + local.get 0 + i32.load offset=16 + local.tee 4 + i32.eqz + br_if 3 (;@10;) + local.get 0 + i32.const 16 + i32.add + local.set 6 + end + loop ;; label = @13 + local.get 6 + local.set 2 + local.get 4 + local.tee 9 + i32.const 20 + i32.add + local.tee 6 + i32.load + local.tee 4 + br_if 0 (;@13;) + local.get 9 + i32.const 16 + i32.add + local.set 6 + local.get 9 + i32.load offset=16 + local.tee 4 + br_if 0 (;@13;) + end + local.get 2 + i32.const 0 + i32.store + br 10 (;@2;) + end + i32.const -1 + local.set 5 + local.get 0 + i32.const -65 + i32.gt_u + br_if 0 (;@11;) + local.get 0 + i32.const 19 + i32.add + local.tee 4 + i32.const -16 + i32.and + local.set 5 + i32.const 0 + i32.load offset=3736 + local.tee 10 + i32.eqz + br_if 0 (;@11;) + i32.const 0 + local.set 8 + block ;; label = @12 + local.get 5 + i32.const 256 + i32.lt_u + br_if 0 (;@12;) + i32.const 31 + local.set 8 + local.get 5 + i32.const 16777215 + i32.gt_u + br_if 0 (;@12;) + local.get 5 + i32.const 38 + local.get 4 + i32.const 8 + i32.shr_u + i32.clz + local.tee 4 + i32.sub + i32.shr_u + i32.const 1 + i32.and + local.get 4 + i32.const 1 + i32.shl + i32.sub + i32.const 62 + i32.add + local.set 8 + end + i32.const 0 + local.get 5 + i32.sub + local.set 3 + block ;; label = @12 + block ;; label = @13 + block ;; label = @14 + block ;; label = @15 + local.get 8 + i32.const 2 + i32.shl + i32.const 4036 + i32.add + i32.load + local.tee 6 + br_if 0 (;@15;) + i32.const 0 + local.set 4 + i32.const 0 + local.set 9 + br 1 (;@14;) + end + i32.const 0 + local.set 4 + local.get 5 + i32.const 0 + i32.const 25 + local.get 8 + i32.const 1 + i32.shr_u + i32.sub + local.get 8 + i32.const 31 + i32.eq + select + i32.shl + local.set 0 + i32.const 0 + local.set 9 + loop ;; label = @15 + block ;; label = @16 + local.get 6 + i32.load offset=4 + i32.const -8 + i32.and + local.get 5 + i32.sub + local.tee 7 + local.get 3 + i32.ge_u + br_if 0 (;@16;) + local.get 7 + local.set 3 + local.get 6 + local.set 9 + local.get 7 + br_if 0 (;@16;) + i32.const 0 + local.set 3 + local.get 6 + local.set 9 + local.get 6 + local.set 4 + br 3 (;@13;) + end + local.get 4 + local.get 6 + i32.const 20 + i32.add + i32.load + local.tee 7 + local.get 7 + local.get 6 + local.get 0 + i32.const 29 + i32.shr_u + i32.const 4 + i32.and + i32.add + i32.const 16 + i32.add + i32.load + local.tee 6 + i32.eq + select + local.get 4 + local.get 7 + select + local.set 4 + local.get 0 + i32.const 1 + i32.shl + local.set 0 + local.get 6 + br_if 0 (;@15;) + end + end + block ;; label = @14 + local.get 4 + local.get 9 + i32.or + br_if 0 (;@14;) + i32.const 0 + local.set 9 + i32.const 2 + local.get 8 + i32.shl + local.tee 4 + i32.const 0 + local.get 4 + i32.sub + i32.or + local.get 10 + i32.and + local.tee 4 + i32.eqz + br_if 3 (;@11;) + local.get 4 + i32.const 0 + local.get 4 + i32.sub + i32.and + i32.ctz + i32.const 2 + i32.shl + i32.const 4036 + i32.add + i32.load + local.set 4 + end + local.get 4 + i32.eqz + br_if 1 (;@12;) + end + loop ;; label = @13 + local.get 4 + i32.load offset=4 + i32.const -8 + i32.and + local.get 5 + i32.sub + local.tee 7 + local.get 3 + i32.lt_u + local.set 0 + block ;; label = @14 + local.get 4 + i32.load offset=16 + local.tee 6 + br_if 0 (;@14;) + local.get 4 + i32.const 20 + i32.add + i32.load + local.set 6 + end + local.get 7 + local.get 3 + local.get 0 + select + local.set 3 + local.get 4 + local.get 9 + local.get 0 + select + local.set 9 + local.get 6 + local.set 4 + local.get 6 + br_if 0 (;@13;) + end + end + local.get 9 + i32.eqz + br_if 0 (;@11;) + local.get 3 + i32.const 0 + i32.load offset=3740 + local.get 5 + i32.sub + i32.ge_u + br_if 0 (;@11;) + local.get 9 + i32.load offset=24 + local.set 2 + block ;; label = @12 + local.get 9 + i32.load offset=12 + local.tee 0 + local.get 9 + i32.eq + br_if 0 (;@12;) + local.get 9 + i32.load offset=8 + local.tee 4 + i32.const 0 + i32.load offset=3748 + i32.lt_u + drop + local.get 0 + local.get 4 + i32.store offset=8 + local.get 4 + local.get 0 + i32.store offset=12 + br 9 (;@3;) + end + block ;; label = @12 + local.get 9 + i32.const 20 + i32.add + local.tee 6 + i32.load + local.tee 4 + br_if 0 (;@12;) + local.get 9 + i32.load offset=16 + local.tee 4 + i32.eqz + br_if 3 (;@9;) + local.get 9 + i32.const 16 + i32.add + local.set 6 + end + loop ;; label = @12 + local.get 6 + local.set 7 + local.get 4 + local.tee 0 + i32.const 20 + i32.add + local.tee 6 + i32.load + local.tee 4 + br_if 0 (;@12;) + local.get 0 + i32.const 16 + i32.add + local.set 6 + local.get 0 + i32.load offset=16 + local.tee 4 + br_if 0 (;@12;) + end + local.get 7 + i32.const 0 + i32.store + br 8 (;@3;) + end + block ;; label = @11 + i32.const 0 + i32.load offset=3740 + local.tee 4 + local.get 5 + i32.lt_u + br_if 0 (;@11;) + i32.const 0 + i32.load offset=3752 + local.set 3 + block ;; label = @12 + block ;; label = @13 + local.get 4 + local.get 5 + i32.sub + local.tee 6 + i32.const 16 + i32.lt_u + br_if 0 (;@13;) + local.get 3 + local.get 5 + i32.add + local.tee 0 + local.get 6 + i32.const 1 + i32.or + i32.store offset=4 + local.get 3 + local.get 4 + i32.add + local.get 6 + i32.store + local.get 3 + local.get 5 + i32.const 3 + i32.or + i32.store offset=4 + br 1 (;@12;) + end + local.get 3 + local.get 4 + i32.const 3 + i32.or + i32.store offset=4 + local.get 3 + local.get 4 + i32.add + local.tee 4 + local.get 4 + i32.load offset=4 + i32.const 1 + i32.or + i32.store offset=4 + i32.const 0 + local.set 0 + i32.const 0 + local.set 6 + end + i32.const 0 + local.get 6 + i32.store offset=3740 + i32.const 0 + local.get 0 + i32.store offset=3752 + local.get 3 + i32.const 8 + i32.add + local.set 4 + br 10 (;@1;) + end + block ;; label = @11 + i32.const 0 + i32.load offset=3744 + local.tee 6 + local.get 5 + i32.le_u + br_if 0 (;@11;) + local.get 2 + local.get 5 + i32.add + local.tee 4 + local.get 6 + local.get 5 + i32.sub + local.tee 3 + i32.const 1 + i32.or + i32.store offset=4 + i32.const 0 + local.get 4 + i32.store offset=3756 + i32.const 0 + local.get 3 + i32.store offset=3744 + local.get 2 + local.get 5 + i32.const 3 + i32.or + i32.store offset=4 + local.get 2 + i32.const 8 + i32.add + local.set 4 + br 10 (;@1;) + end + block ;; label = @11 + block ;; label = @12 + i32.const 0 + i32.load offset=4204 + i32.eqz + br_if 0 (;@12;) + i32.const 0 + i32.load offset=4212 + local.set 3 + br 1 (;@11;) + end + i32.const 0 + i64.const -1 + i64.store offset=4216 align=4 + i32.const 0 + i64.const 281474976776192 + i64.store offset=4208 align=4 + i32.const 0 + local.get 1 + i32.const 12 + i32.add + i32.const -16 + i32.and + i32.const 1431655768 + i32.xor + i32.store offset=4204 + i32.const 0 + i32.const 0 + i32.store offset=4224 + i32.const 0 + i32.const 0 + i32.store offset=4176 + i32.const 65536 + local.set 3 + end + i32.const 0 + local.set 4 + block ;; label = @11 + local.get 3 + local.get 5 + i32.const 71 + i32.add + local.tee 8 + i32.add + local.tee 0 + i32.const 0 + local.get 3 + i32.sub + local.tee 7 + i32.and + local.tee 9 + local.get 5 + i32.gt_u + br_if 0 (;@11;) + i32.const 0 + i32.const 48 + i32.store offset=4228 + br 10 (;@1;) + end + block ;; label = @11 + i32.const 0 + i32.load offset=4172 + local.tee 4 + i32.eqz + br_if 0 (;@11;) + block ;; label = @12 + i32.const 0 + i32.load offset=4164 + local.tee 3 + local.get 9 + i32.add + local.tee 10 + local.get 3 + i32.le_u + br_if 0 (;@12;) + local.get 10 + local.get 4 + i32.le_u + br_if 1 (;@11;) + end + i32.const 0 + local.set 4 + i32.const 0 + i32.const 48 + i32.store offset=4228 + br 10 (;@1;) + end + i32.const 0 + i32.load8_u offset=4176 + i32.const 4 + i32.and + br_if 4 (;@6;) + block ;; label = @11 + block ;; label = @12 + block ;; label = @13 + local.get 2 + i32.eqz + br_if 0 (;@13;) + i32.const 4180 + local.set 4 + loop ;; label = @14 + block ;; label = @15 + local.get 4 + i32.load + local.tee 3 + local.get 2 + i32.gt_u + br_if 0 (;@15;) + local.get 3 + local.get 4 + i32.load offset=4 + i32.add + local.get 2 + i32.gt_u + br_if 3 (;@12;) + end + local.get 4 + i32.load offset=8 + local.tee 4 + br_if 0 (;@14;) + end + end + i32.const 0 + call $sbrk + local.tee 0 + i32.const -1 + i32.eq + br_if 5 (;@7;) + local.get 9 + local.set 7 + block ;; label = @13 + i32.const 0 + i32.load offset=4208 + local.tee 4 + i32.const -1 + i32.add + local.tee 3 + local.get 0 + i32.and + i32.eqz + br_if 0 (;@13;) + local.get 9 + local.get 0 + i32.sub + local.get 3 + local.get 0 + i32.add + i32.const 0 + local.get 4 + i32.sub + i32.and + i32.add + local.set 7 + end + local.get 7 + local.get 5 + i32.le_u + br_if 5 (;@7;) + local.get 7 + i32.const 2147483646 + i32.gt_u + br_if 5 (;@7;) + block ;; label = @13 + i32.const 0 + i32.load offset=4172 + local.tee 4 + i32.eqz + br_if 0 (;@13;) + i32.const 0 + i32.load offset=4164 + local.tee 3 + local.get 7 + i32.add + local.tee 6 + local.get 3 + i32.le_u + br_if 6 (;@7;) + local.get 6 + local.get 4 + i32.gt_u + br_if 6 (;@7;) + end + local.get 7 + call $sbrk + local.tee 4 + local.get 0 + i32.ne + br_if 1 (;@11;) + br 7 (;@5;) + end + local.get 0 + local.get 6 + i32.sub + local.get 7 + i32.and + local.tee 7 + i32.const 2147483646 + i32.gt_u + br_if 4 (;@7;) + local.get 7 + call $sbrk + local.tee 0 + local.get 4 + i32.load + local.get 4 + i32.load offset=4 + i32.add + i32.eq + br_if 3 (;@8;) + local.get 0 + local.set 4 + end + block ;; label = @11 + local.get 4 + i32.const -1 + i32.eq + br_if 0 (;@11;) + local.get 5 + i32.const 72 + i32.add + local.get 7 + i32.le_u + br_if 0 (;@11;) + block ;; label = @12 + local.get 8 + local.get 7 + i32.sub + i32.const 0 + i32.load offset=4212 + local.tee 3 + i32.add + i32.const 0 + local.get 3 + i32.sub + i32.and + local.tee 3 + i32.const 2147483646 + i32.le_u + br_if 0 (;@12;) + local.get 4 + local.set 0 + br 7 (;@5;) + end + block ;; label = @12 + local.get 3 + call $sbrk + i32.const -1 + i32.eq + br_if 0 (;@12;) + local.get 3 + local.get 7 + i32.add + local.set 7 + local.get 4 + local.set 0 + br 7 (;@5;) + end + i32.const 0 + local.get 7 + i32.sub + call $sbrk + drop + br 4 (;@7;) + end + local.get 4 + local.set 0 + local.get 4 + i32.const -1 + i32.ne + br_if 5 (;@5;) + br 3 (;@7;) + end + i32.const 0 + local.set 9 + br 7 (;@2;) + end + i32.const 0 + local.set 0 + br 5 (;@3;) + end + local.get 0 + i32.const -1 + i32.ne + br_if 2 (;@5;) + end + i32.const 0 + i32.const 0 + i32.load offset=4176 + i32.const 4 + i32.or + i32.store offset=4176 + end + local.get 9 + i32.const 2147483646 + i32.gt_u + br_if 1 (;@4;) + local.get 9 + call $sbrk + local.set 0 + i32.const 0 + call $sbrk + local.set 4 + local.get 0 + i32.const -1 + i32.eq + br_if 1 (;@4;) + local.get 4 + i32.const -1 + i32.eq + br_if 1 (;@4;) + local.get 0 + local.get 4 + i32.ge_u + br_if 1 (;@4;) + local.get 4 + local.get 0 + i32.sub + local.tee 7 + local.get 5 + i32.const 56 + i32.add + i32.le_u + br_if 1 (;@4;) + end + i32.const 0 + i32.const 0 + i32.load offset=4164 + local.get 7 + i32.add + local.tee 4 + i32.store offset=4164 + block ;; label = @5 + local.get 4 + i32.const 0 + i32.load offset=4168 + i32.le_u + br_if 0 (;@5;) + i32.const 0 + local.get 4 + i32.store offset=4168 + end + block ;; label = @5 + block ;; label = @6 + block ;; label = @7 + block ;; label = @8 + i32.const 0 + i32.load offset=3756 + local.tee 3 + i32.eqz + br_if 0 (;@8;) + i32.const 4180 + local.set 4 + loop ;; label = @9 + local.get 0 + local.get 4 + i32.load + local.tee 6 + local.get 4 + i32.load offset=4 + local.tee 9 + i32.add + i32.eq + br_if 2 (;@7;) + local.get 4 + i32.load offset=8 + local.tee 4 + br_if 0 (;@9;) + br 3 (;@6;) + end + end + block ;; label = @8 + block ;; label = @9 + i32.const 0 + i32.load offset=3748 + local.tee 4 + i32.eqz + br_if 0 (;@9;) + local.get 0 + local.get 4 + i32.ge_u + br_if 1 (;@8;) + end + i32.const 0 + local.get 0 + i32.store offset=3748 + end + i32.const 0 + local.set 4 + i32.const 0 + local.get 7 + i32.store offset=4184 + i32.const 0 + local.get 0 + i32.store offset=4180 + i32.const 0 + i32.const -1 + i32.store offset=3764 + i32.const 0 + i32.const 0 + i32.load offset=4204 + i32.store offset=3768 + i32.const 0 + i32.const 0 + i32.store offset=4192 + loop ;; label = @8 + local.get 4 + i32.const 3792 + i32.add + local.get 4 + i32.const 3780 + i32.add + local.tee 3 + i32.store + local.get 3 + local.get 4 + i32.const 3772 + i32.add + local.tee 6 + i32.store + local.get 4 + i32.const 3784 + i32.add + local.get 6 + i32.store + local.get 4 + i32.const 3800 + i32.add + local.get 4 + i32.const 3788 + i32.add + local.tee 6 + i32.store + local.get 6 + local.get 3 + i32.store + local.get 4 + i32.const 3808 + i32.add + local.get 4 + i32.const 3796 + i32.add + local.tee 3 + i32.store + local.get 3 + local.get 6 + i32.store + local.get 4 + i32.const 3804 + i32.add + local.get 3 + i32.store + local.get 4 + i32.const 32 + i32.add + local.tee 4 + i32.const 256 + i32.ne + br_if 0 (;@8;) + end + local.get 0 + i32.const -8 + local.get 0 + i32.sub + i32.const 15 + i32.and + i32.const 0 + local.get 0 + i32.const 8 + i32.add + i32.const 15 + i32.and + select + local.tee 4 + i32.add + local.tee 3 + local.get 7 + i32.const -56 + i32.add + local.tee 6 + local.get 4 + i32.sub + local.tee 4 + i32.const 1 + i32.or + i32.store offset=4 + i32.const 0 + i32.const 0 + i32.load offset=4220 + i32.store offset=3760 + i32.const 0 + local.get 4 + i32.store offset=3744 + i32.const 0 + local.get 3 + i32.store offset=3756 + local.get 0 + local.get 6 + i32.add + i32.const 56 + i32.store offset=4 + br 2 (;@5;) + end + local.get 4 + i32.load8_u offset=12 + i32.const 8 + i32.and + br_if 0 (;@6;) + local.get 3 + local.get 6 + i32.lt_u + br_if 0 (;@6;) + local.get 3 + local.get 0 + i32.ge_u + br_if 0 (;@6;) + local.get 3 + i32.const -8 + local.get 3 + i32.sub + i32.const 15 + i32.and + i32.const 0 + local.get 3 + i32.const 8 + i32.add + i32.const 15 + i32.and + select + local.tee 6 + i32.add + local.tee 0 + i32.const 0 + i32.load offset=3744 + local.get 7 + i32.add + local.tee 2 + local.get 6 + i32.sub + local.tee 6 + i32.const 1 + i32.or + i32.store offset=4 + local.get 4 + local.get 9 + local.get 7 + i32.add + i32.store offset=4 + i32.const 0 + i32.const 0 + i32.load offset=4220 + i32.store offset=3760 + i32.const 0 + local.get 6 + i32.store offset=3744 + i32.const 0 + local.get 0 + i32.store offset=3756 + local.get 3 + local.get 2 + i32.add + i32.const 56 + i32.store offset=4 + br 1 (;@5;) + end + block ;; label = @6 + local.get 0 + i32.const 0 + i32.load offset=3748 + local.tee 9 + i32.ge_u + br_if 0 (;@6;) + i32.const 0 + local.get 0 + i32.store offset=3748 + local.get 0 + local.set 9 + end + local.get 0 + local.get 7 + i32.add + local.set 6 + i32.const 4180 + local.set 4 + block ;; label = @6 + block ;; label = @7 + block ;; label = @8 + block ;; label = @9 + block ;; label = @10 + block ;; label = @11 + block ;; label = @12 + loop ;; label = @13 + local.get 4 + i32.load + local.get 6 + i32.eq + br_if 1 (;@12;) + local.get 4 + i32.load offset=8 + local.tee 4 + br_if 0 (;@13;) + br 2 (;@11;) + end + end + local.get 4 + i32.load8_u offset=12 + i32.const 8 + i32.and + i32.eqz + br_if 1 (;@10;) + end + i32.const 4180 + local.set 4 + loop ;; label = @11 + block ;; label = @12 + local.get 4 + i32.load + local.tee 6 + local.get 3 + i32.gt_u + br_if 0 (;@12;) + local.get 6 + local.get 4 + i32.load offset=4 + i32.add + local.tee 6 + local.get 3 + i32.gt_u + br_if 3 (;@9;) + end + local.get 4 + i32.load offset=8 + local.set 4 + br 0 (;@11;) + end + end + local.get 4 + local.get 0 + i32.store + local.get 4 + local.get 4 + i32.load offset=4 + local.get 7 + i32.add + i32.store offset=4 + local.get 0 + i32.const -8 + local.get 0 + i32.sub + i32.const 15 + i32.and + i32.const 0 + local.get 0 + i32.const 8 + i32.add + i32.const 15 + i32.and + select + i32.add + local.tee 2 + local.get 5 + i32.const 3 + i32.or + i32.store offset=4 + local.get 6 + i32.const -8 + local.get 6 + i32.sub + i32.const 15 + i32.and + i32.const 0 + local.get 6 + i32.const 8 + i32.add + i32.const 15 + i32.and + select + i32.add + local.tee 7 + local.get 2 + local.get 5 + i32.add + local.tee 5 + i32.sub + local.set 4 + block ;; label = @10 + local.get 7 + local.get 3 + i32.ne + br_if 0 (;@10;) + i32.const 0 + local.get 5 + i32.store offset=3756 + i32.const 0 + i32.const 0 + i32.load offset=3744 + local.get 4 + i32.add + local.tee 4 + i32.store offset=3744 + local.get 5 + local.get 4 + i32.const 1 + i32.or + i32.store offset=4 + br 3 (;@7;) + end + block ;; label = @10 + local.get 7 + i32.const 0 + i32.load offset=3752 + i32.ne + br_if 0 (;@10;) + i32.const 0 + local.get 5 + i32.store offset=3752 + i32.const 0 + i32.const 0 + i32.load offset=3740 + local.get 4 + i32.add + local.tee 4 + i32.store offset=3740 + local.get 5 + local.get 4 + i32.const 1 + i32.or + i32.store offset=4 + local.get 5 + local.get 4 + i32.add + local.get 4 + i32.store + br 3 (;@7;) + end + block ;; label = @10 + local.get 7 + i32.load offset=4 + local.tee 3 + i32.const 3 + i32.and + i32.const 1 + i32.ne + br_if 0 (;@10;) + local.get 3 + i32.const -8 + i32.and + local.set 8 + block ;; label = @11 + block ;; label = @12 + local.get 3 + i32.const 255 + i32.gt_u + br_if 0 (;@12;) + local.get 7 + i32.load offset=8 + local.tee 6 + local.get 3 + i32.const 3 + i32.shr_u + local.tee 9 + i32.const 3 + i32.shl + i32.const 3772 + i32.add + local.tee 0 + i32.eq + drop + block ;; label = @13 + local.get 7 + i32.load offset=12 + local.tee 3 + local.get 6 + i32.ne + br_if 0 (;@13;) + i32.const 0 + i32.const 0 + i32.load offset=3732 + i32.const -2 + local.get 9 + i32.rotl + i32.and + i32.store offset=3732 + br 2 (;@11;) + end + local.get 3 + local.get 0 + i32.eq + drop + local.get 3 + local.get 6 + i32.store offset=8 + local.get 6 + local.get 3 + i32.store offset=12 + br 1 (;@11;) + end + local.get 7 + i32.load offset=24 + local.set 10 + block ;; label = @12 + block ;; label = @13 + local.get 7 + i32.load offset=12 + local.tee 0 + local.get 7 + i32.eq + br_if 0 (;@13;) + local.get 7 + i32.load offset=8 + local.tee 3 + local.get 9 + i32.lt_u + drop + local.get 0 + local.get 3 + i32.store offset=8 + local.get 3 + local.get 0 + i32.store offset=12 + br 1 (;@12;) + end + block ;; label = @13 + local.get 7 + i32.const 20 + i32.add + local.tee 3 + i32.load + local.tee 6 + br_if 0 (;@13;) + local.get 7 + i32.const 16 + i32.add + local.tee 3 + i32.load + local.tee 6 + br_if 0 (;@13;) + i32.const 0 + local.set 0 + br 1 (;@12;) + end + loop ;; label = @13 + local.get 3 + local.set 9 + local.get 6 + local.tee 0 + i32.const 20 + i32.add + local.tee 3 + i32.load + local.tee 6 + br_if 0 (;@13;) + local.get 0 + i32.const 16 + i32.add + local.set 3 + local.get 0 + i32.load offset=16 + local.tee 6 + br_if 0 (;@13;) + end + local.get 9 + i32.const 0 + i32.store + end + local.get 10 + i32.eqz + br_if 0 (;@11;) + block ;; label = @12 + block ;; label = @13 + local.get 7 + local.get 7 + i32.load offset=28 + local.tee 6 + i32.const 2 + i32.shl + i32.const 4036 + i32.add + local.tee 3 + i32.load + i32.ne + br_if 0 (;@13;) + local.get 3 + local.get 0 + i32.store + local.get 0 + br_if 1 (;@12;) + i32.const 0 + i32.const 0 + i32.load offset=3736 + i32.const -2 + local.get 6 + i32.rotl + i32.and + i32.store offset=3736 + br 2 (;@11;) + end + local.get 10 + i32.const 16 + i32.const 20 + local.get 10 + i32.load offset=16 + local.get 7 + i32.eq + select + i32.add + local.get 0 + i32.store + local.get 0 + i32.eqz + br_if 1 (;@11;) + end + local.get 0 + local.get 10 + i32.store offset=24 + block ;; label = @12 + local.get 7 + i32.load offset=16 + local.tee 3 + i32.eqz + br_if 0 (;@12;) + local.get 0 + local.get 3 + i32.store offset=16 + local.get 3 + local.get 0 + i32.store offset=24 + end + local.get 7 + i32.load offset=20 + local.tee 3 + i32.eqz + br_if 0 (;@11;) + local.get 0 + i32.const 20 + i32.add + local.get 3 + i32.store + local.get 3 + local.get 0 + i32.store offset=24 + end + local.get 8 + local.get 4 + i32.add + local.set 4 + local.get 7 + local.get 8 + i32.add + local.tee 7 + i32.load offset=4 + local.set 3 + end + local.get 7 + local.get 3 + i32.const -2 + i32.and + i32.store offset=4 + local.get 5 + local.get 4 + i32.add + local.get 4 + i32.store + local.get 5 + local.get 4 + i32.const 1 + i32.or + i32.store offset=4 + block ;; label = @10 + local.get 4 + i32.const 255 + i32.gt_u + br_if 0 (;@10;) + local.get 4 + i32.const -8 + i32.and + i32.const 3772 + i32.add + local.set 3 + block ;; label = @11 + block ;; label = @12 + i32.const 0 + i32.load offset=3732 + local.tee 6 + i32.const 1 + local.get 4 + i32.const 3 + i32.shr_u + i32.shl + local.tee 4 + i32.and + br_if 0 (;@12;) + i32.const 0 + local.get 6 + local.get 4 + i32.or + i32.store offset=3732 + local.get 3 + local.set 4 + br 1 (;@11;) + end + local.get 3 + i32.load offset=8 + local.set 4 + end + local.get 4 + local.get 5 + i32.store offset=12 + local.get 3 + local.get 5 + i32.store offset=8 + local.get 5 + local.get 3 + i32.store offset=12 + local.get 5 + local.get 4 + i32.store offset=8 + br 3 (;@7;) + end + i32.const 31 + local.set 3 + block ;; label = @10 + local.get 4 + i32.const 16777215 + i32.gt_u + br_if 0 (;@10;) + local.get 4 + i32.const 38 + local.get 4 + i32.const 8 + i32.shr_u + i32.clz + local.tee 3 + i32.sub + i32.shr_u + i32.const 1 + i32.and + local.get 3 + i32.const 1 + i32.shl + i32.sub + i32.const 62 + i32.add + local.set 3 + end + local.get 5 + local.get 3 + i32.store offset=28 + local.get 5 + i64.const 0 + i64.store offset=16 align=4 + local.get 3 + i32.const 2 + i32.shl + i32.const 4036 + i32.add + local.set 6 + block ;; label = @10 + i32.const 0 + i32.load offset=3736 + local.tee 0 + i32.const 1 + local.get 3 + i32.shl + local.tee 9 + i32.and + br_if 0 (;@10;) + local.get 6 + local.get 5 + i32.store + i32.const 0 + local.get 0 + local.get 9 + i32.or + i32.store offset=3736 + local.get 5 + local.get 6 + i32.store offset=24 + local.get 5 + local.get 5 + i32.store offset=8 + local.get 5 + local.get 5 + i32.store offset=12 + br 3 (;@7;) + end + local.get 4 + i32.const 0 + i32.const 25 + local.get 3 + i32.const 1 + i32.shr_u + i32.sub + local.get 3 + i32.const 31 + i32.eq + select + i32.shl + local.set 3 + local.get 6 + i32.load + local.set 0 + loop ;; label = @10 + local.get 0 + local.tee 6 + i32.load offset=4 + i32.const -8 + i32.and + local.get 4 + i32.eq + br_if 2 (;@8;) + local.get 3 + i32.const 29 + i32.shr_u + local.set 0 + local.get 3 + i32.const 1 + i32.shl + local.set 3 + local.get 6 + local.get 0 + i32.const 4 + i32.and + i32.add + i32.const 16 + i32.add + local.tee 9 + i32.load + local.tee 0 + br_if 0 (;@10;) + end + local.get 9 + local.get 5 + i32.store + local.get 5 + local.get 6 + i32.store offset=24 + local.get 5 + local.get 5 + i32.store offset=12 + local.get 5 + local.get 5 + i32.store offset=8 + br 2 (;@7;) + end + local.get 0 + i32.const -8 + local.get 0 + i32.sub + i32.const 15 + i32.and + i32.const 0 + local.get 0 + i32.const 8 + i32.add + i32.const 15 + i32.and + select + local.tee 4 + i32.add + local.tee 2 + local.get 7 + i32.const -56 + i32.add + local.tee 9 + local.get 4 + i32.sub + local.tee 4 + i32.const 1 + i32.or + i32.store offset=4 + local.get 0 + local.get 9 + i32.add + i32.const 56 + i32.store offset=4 + local.get 3 + local.get 6 + i32.const 55 + local.get 6 + i32.sub + i32.const 15 + i32.and + i32.const 0 + local.get 6 + i32.const -55 + i32.add + i32.const 15 + i32.and + select + i32.add + i32.const -63 + i32.add + local.tee 9 + local.get 9 + local.get 3 + i32.const 16 + i32.add + i32.lt_u + select + local.tee 9 + i32.const 35 + i32.store offset=4 + i32.const 0 + i32.const 0 + i32.load offset=4220 + i32.store offset=3760 + i32.const 0 + local.get 4 + i32.store offset=3744 + i32.const 0 + local.get 2 + i32.store offset=3756 + local.get 9 + i32.const 16 + i32.add + i32.const 0 + i64.load offset=4188 align=4 + i64.store align=4 + local.get 9 + i32.const 0 + i64.load offset=4180 align=4 + i64.store offset=8 align=4 + i32.const 0 + local.get 9 + i32.const 8 + i32.add + i32.store offset=4188 + i32.const 0 + local.get 7 + i32.store offset=4184 + i32.const 0 + local.get 0 + i32.store offset=4180 + i32.const 0 + i32.const 0 + i32.store offset=4192 + local.get 9 + i32.const 36 + i32.add + local.set 4 + loop ;; label = @9 + local.get 4 + i32.const 7 + i32.store + local.get 4 + i32.const 4 + i32.add + local.tee 4 + local.get 6 + i32.lt_u + br_if 0 (;@9;) + end + local.get 9 + local.get 3 + i32.eq + br_if 3 (;@5;) + local.get 9 + local.get 9 + i32.load offset=4 + i32.const -2 + i32.and + i32.store offset=4 + local.get 9 + local.get 9 + local.get 3 + i32.sub + local.tee 0 + i32.store + local.get 3 + local.get 0 + i32.const 1 + i32.or + i32.store offset=4 + block ;; label = @9 + local.get 0 + i32.const 255 + i32.gt_u + br_if 0 (;@9;) + local.get 0 + i32.const -8 + i32.and + i32.const 3772 + i32.add + local.set 4 + block ;; label = @10 + block ;; label = @11 + i32.const 0 + i32.load offset=3732 + local.tee 6 + i32.const 1 + local.get 0 + i32.const 3 + i32.shr_u + i32.shl + local.tee 0 + i32.and + br_if 0 (;@11;) + i32.const 0 + local.get 6 + local.get 0 + i32.or + i32.store offset=3732 + local.get 4 + local.set 6 + br 1 (;@10;) + end + local.get 4 + i32.load offset=8 + local.set 6 + end + local.get 6 + local.get 3 + i32.store offset=12 + local.get 4 + local.get 3 + i32.store offset=8 + local.get 3 + local.get 4 + i32.store offset=12 + local.get 3 + local.get 6 + i32.store offset=8 + br 4 (;@5;) + end + i32.const 31 + local.set 4 + block ;; label = @9 + local.get 0 + i32.const 16777215 + i32.gt_u + br_if 0 (;@9;) + local.get 0 + i32.const 38 + local.get 0 + i32.const 8 + i32.shr_u + i32.clz + local.tee 4 + i32.sub + i32.shr_u + i32.const 1 + i32.and + local.get 4 + i32.const 1 + i32.shl + i32.sub + i32.const 62 + i32.add + local.set 4 + end + local.get 3 + local.get 4 + i32.store offset=28 + local.get 3 + i64.const 0 + i64.store offset=16 align=4 + local.get 4 + i32.const 2 + i32.shl + i32.const 4036 + i32.add + local.set 6 + block ;; label = @9 + i32.const 0 + i32.load offset=3736 + local.tee 9 + i32.const 1 + local.get 4 + i32.shl + local.tee 7 + i32.and + br_if 0 (;@9;) + local.get 6 + local.get 3 + i32.store + i32.const 0 + local.get 9 + local.get 7 + i32.or + i32.store offset=3736 + local.get 3 + local.get 6 + i32.store offset=24 + local.get 3 + local.get 3 + i32.store offset=8 + local.get 3 + local.get 3 + i32.store offset=12 + br 4 (;@5;) + end + local.get 0 + i32.const 0 + i32.const 25 + local.get 4 + i32.const 1 + i32.shr_u + i32.sub + local.get 4 + i32.const 31 + i32.eq + select + i32.shl + local.set 4 + local.get 6 + i32.load + local.set 9 + loop ;; label = @9 + local.get 9 + local.tee 6 + i32.load offset=4 + i32.const -8 + i32.and + local.get 0 + i32.eq + br_if 3 (;@6;) + local.get 4 + i32.const 29 + i32.shr_u + local.set 9 + local.get 4 + i32.const 1 + i32.shl + local.set 4 + local.get 6 + local.get 9 + i32.const 4 + i32.and + i32.add + i32.const 16 + i32.add + local.tee 7 + i32.load + local.tee 9 + br_if 0 (;@9;) + end + local.get 7 + local.get 3 + i32.store + local.get 3 + local.get 6 + i32.store offset=24 + local.get 3 + local.get 3 + i32.store offset=12 + local.get 3 + local.get 3 + i32.store offset=8 + br 3 (;@5;) + end + local.get 6 + i32.load offset=8 + local.tee 4 + local.get 5 + i32.store offset=12 + local.get 6 + local.get 5 + i32.store offset=8 + local.get 5 + i32.const 0 + i32.store offset=24 + local.get 5 + local.get 6 + i32.store offset=12 + local.get 5 + local.get 4 + i32.store offset=8 + end + local.get 2 + i32.const 8 + i32.add + local.set 4 + br 5 (;@1;) + end + local.get 6 + i32.load offset=8 + local.tee 4 + local.get 3 + i32.store offset=12 + local.get 6 + local.get 3 + i32.store offset=8 + local.get 3 + i32.const 0 + i32.store offset=24 + local.get 3 + local.get 6 + i32.store offset=12 + local.get 3 + local.get 4 + i32.store offset=8 + end + i32.const 0 + i32.load offset=3744 + local.tee 4 + local.get 5 + i32.le_u + br_if 0 (;@4;) + i32.const 0 + i32.load offset=3756 + local.tee 3 + local.get 5 + i32.add + local.tee 6 + local.get 4 + local.get 5 + i32.sub + local.tee 4 + i32.const 1 + i32.or + i32.store offset=4 + i32.const 0 + local.get 4 + i32.store offset=3744 + i32.const 0 + local.get 6 + i32.store offset=3756 + local.get 3 + local.get 5 + i32.const 3 + i32.or + i32.store offset=4 + local.get 3 + i32.const 8 + i32.add + local.set 4 + br 3 (;@1;) + end + i32.const 0 + local.set 4 + i32.const 0 + i32.const 48 + i32.store offset=4228 + br 2 (;@1;) + end + block ;; label = @3 + local.get 2 + i32.eqz + br_if 0 (;@3;) + block ;; label = @4 + block ;; label = @5 + local.get 9 + local.get 9 + i32.load offset=28 + local.tee 6 + i32.const 2 + i32.shl + i32.const 4036 + i32.add + local.tee 4 + i32.load + i32.ne + br_if 0 (;@5;) + local.get 4 + local.get 0 + i32.store + local.get 0 + br_if 1 (;@4;) + i32.const 0 + local.get 10 + i32.const -2 + local.get 6 + i32.rotl + i32.and + local.tee 10 + i32.store offset=3736 + br 2 (;@3;) + end + local.get 2 + i32.const 16 + i32.const 20 + local.get 2 + i32.load offset=16 + local.get 9 + i32.eq + select + i32.add + local.get 0 + i32.store + local.get 0 + i32.eqz + br_if 1 (;@3;) + end + local.get 0 + local.get 2 + i32.store offset=24 + block ;; label = @4 + local.get 9 + i32.load offset=16 + local.tee 4 + i32.eqz + br_if 0 (;@4;) + local.get 0 + local.get 4 + i32.store offset=16 + local.get 4 + local.get 0 + i32.store offset=24 + end + local.get 9 + i32.const 20 + i32.add + i32.load + local.tee 4 + i32.eqz + br_if 0 (;@3;) + local.get 0 + i32.const 20 + i32.add + local.get 4 + i32.store + local.get 4 + local.get 0 + i32.store offset=24 + end + block ;; label = @3 + block ;; label = @4 + local.get 3 + i32.const 15 + i32.gt_u + br_if 0 (;@4;) + local.get 9 + local.get 3 + local.get 5 + i32.add + local.tee 4 + i32.const 3 + i32.or + i32.store offset=4 + local.get 9 + local.get 4 + i32.add + local.tee 4 + local.get 4 + i32.load offset=4 + i32.const 1 + i32.or + i32.store offset=4 + br 1 (;@3;) + end + local.get 9 + local.get 5 + i32.add + local.tee 0 + local.get 3 + i32.const 1 + i32.or + i32.store offset=4 + local.get 9 + local.get 5 + i32.const 3 + i32.or + i32.store offset=4 + local.get 0 + local.get 3 + i32.add + local.get 3 + i32.store + block ;; label = @4 + local.get 3 + i32.const 255 + i32.gt_u + br_if 0 (;@4;) + local.get 3 + i32.const -8 + i32.and + i32.const 3772 + i32.add + local.set 4 + block ;; label = @5 + block ;; label = @6 + i32.const 0 + i32.load offset=3732 + local.tee 6 + i32.const 1 + local.get 3 + i32.const 3 + i32.shr_u + i32.shl + local.tee 3 + i32.and + br_if 0 (;@6;) + i32.const 0 + local.get 6 + local.get 3 + i32.or + i32.store offset=3732 + local.get 4 + local.set 3 + br 1 (;@5;) + end + local.get 4 + i32.load offset=8 + local.set 3 + end + local.get 3 + local.get 0 + i32.store offset=12 + local.get 4 + local.get 0 + i32.store offset=8 + local.get 0 + local.get 4 + i32.store offset=12 + local.get 0 + local.get 3 + i32.store offset=8 + br 1 (;@3;) + end + i32.const 31 + local.set 4 + block ;; label = @4 + local.get 3 + i32.const 16777215 + i32.gt_u + br_if 0 (;@4;) + local.get 3 + i32.const 38 + local.get 3 + i32.const 8 + i32.shr_u + i32.clz + local.tee 4 + i32.sub + i32.shr_u + i32.const 1 + i32.and + local.get 4 + i32.const 1 + i32.shl + i32.sub + i32.const 62 + i32.add + local.set 4 + end + local.get 0 + local.get 4 + i32.store offset=28 + local.get 0 + i64.const 0 + i64.store offset=16 align=4 + local.get 4 + i32.const 2 + i32.shl + i32.const 4036 + i32.add + local.set 6 + block ;; label = @4 + local.get 10 + i32.const 1 + local.get 4 + i32.shl + local.tee 5 + i32.and + br_if 0 (;@4;) + local.get 6 + local.get 0 + i32.store + i32.const 0 + local.get 10 + local.get 5 + i32.or + i32.store offset=3736 + local.get 0 + local.get 6 + i32.store offset=24 + local.get 0 + local.get 0 + i32.store offset=8 + local.get 0 + local.get 0 + i32.store offset=12 + br 1 (;@3;) + end + local.get 3 + i32.const 0 + i32.const 25 + local.get 4 + i32.const 1 + i32.shr_u + i32.sub + local.get 4 + i32.const 31 + i32.eq + select + i32.shl + local.set 4 + local.get 6 + i32.load + local.set 5 + block ;; label = @4 + loop ;; label = @5 + local.get 5 + local.tee 6 + i32.load offset=4 + i32.const -8 + i32.and + local.get 3 + i32.eq + br_if 1 (;@4;) + local.get 4 + i32.const 29 + i32.shr_u + local.set 5 + local.get 4 + i32.const 1 + i32.shl + local.set 4 + local.get 6 + local.get 5 + i32.const 4 + i32.and + i32.add + i32.const 16 + i32.add + local.tee 7 + i32.load + local.tee 5 + br_if 0 (;@5;) + end + local.get 7 + local.get 0 + i32.store + local.get 0 + local.get 6 + i32.store offset=24 + local.get 0 + local.get 0 + i32.store offset=12 + local.get 0 + local.get 0 + i32.store offset=8 + br 1 (;@3;) + end + local.get 6 + i32.load offset=8 + local.tee 4 + local.get 0 + i32.store offset=12 + local.get 6 + local.get 0 + i32.store offset=8 + local.get 0 + i32.const 0 + i32.store offset=24 + local.get 0 + local.get 6 + i32.store offset=12 + local.get 0 + local.get 4 + i32.store offset=8 + end + local.get 9 + i32.const 8 + i32.add + local.set 4 + br 1 (;@1;) + end + block ;; label = @2 + local.get 11 + i32.eqz + br_if 0 (;@2;) + block ;; label = @3 + block ;; label = @4 + local.get 0 + local.get 0 + i32.load offset=28 + local.tee 6 + i32.const 2 + i32.shl + i32.const 4036 + i32.add + local.tee 4 + i32.load + i32.ne + br_if 0 (;@4;) + local.get 4 + local.get 9 + i32.store + local.get 9 + br_if 1 (;@3;) + i32.const 0 + local.get 10 + i32.const -2 + local.get 6 + i32.rotl + i32.and + i32.store offset=3736 + br 2 (;@2;) + end + local.get 11 + i32.const 16 + i32.const 20 + local.get 11 + i32.load offset=16 + local.get 0 + i32.eq + select + i32.add + local.get 9 + i32.store + local.get 9 + i32.eqz + br_if 1 (;@2;) + end + local.get 9 + local.get 11 + i32.store offset=24 + block ;; label = @3 + local.get 0 + i32.load offset=16 + local.tee 4 + i32.eqz + br_if 0 (;@3;) + local.get 9 + local.get 4 + i32.store offset=16 + local.get 4 + local.get 9 + i32.store offset=24 + end + local.get 0 + i32.const 20 + i32.add + i32.load + local.tee 4 + i32.eqz + br_if 0 (;@2;) + local.get 9 + i32.const 20 + i32.add + local.get 4 + i32.store + local.get 4 + local.get 9 + i32.store offset=24 + end + block ;; label = @2 + block ;; label = @3 + local.get 3 + i32.const 15 + i32.gt_u + br_if 0 (;@3;) + local.get 0 + local.get 3 + local.get 5 + i32.add + local.tee 4 + i32.const 3 + i32.or + i32.store offset=4 + local.get 0 + local.get 4 + i32.add + local.tee 4 + local.get 4 + i32.load offset=4 + i32.const 1 + i32.or + i32.store offset=4 + br 1 (;@2;) + end + local.get 0 + local.get 5 + i32.add + local.tee 6 + local.get 3 + i32.const 1 + i32.or + i32.store offset=4 + local.get 0 + local.get 5 + i32.const 3 + i32.or + i32.store offset=4 + local.get 6 + local.get 3 + i32.add + local.get 3 + i32.store + block ;; label = @3 + local.get 8 + i32.eqz + br_if 0 (;@3;) + local.get 8 + i32.const -8 + i32.and + i32.const 3772 + i32.add + local.set 5 + i32.const 0 + i32.load offset=3752 + local.set 4 + block ;; label = @4 + block ;; label = @5 + i32.const 1 + local.get 8 + i32.const 3 + i32.shr_u + i32.shl + local.tee 9 + local.get 7 + i32.and + br_if 0 (;@5;) + i32.const 0 + local.get 9 + local.get 7 + i32.or + i32.store offset=3732 + local.get 5 + local.set 9 + br 1 (;@4;) + end + local.get 5 + i32.load offset=8 + local.set 9 + end + local.get 9 + local.get 4 + i32.store offset=12 + local.get 5 + local.get 4 + i32.store offset=8 + local.get 4 + local.get 5 + i32.store offset=12 + local.get 4 + local.get 9 + i32.store offset=8 + end + i32.const 0 + local.get 6 + i32.store offset=3752 + i32.const 0 + local.get 3 + i32.store offset=3740 + end + local.get 0 + i32.const 8 + i32.add + local.set 4 + end + local.get 1 + i32.const 16 + i32.add + global.set $__stack_pointer + local.get 4) + (func $__wasi_fd_close (type 2) (param i32) (result i32) + local.get 0 + call $__imported_wasi_snapshot_preview1_fd_close + i32.const 65535 + i32.and) + (func $__wasi_fd_fdstat_get (type 3) (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $__imported_wasi_snapshot_preview1_fd_fdstat_get + i32.const 65535 + i32.and) + (func $__wasi_fd_seek (type 4) (param i32 i64 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + call $__imported_wasi_snapshot_preview1_fd_seek + i32.const 65535 + i32.and) + (func $__wasi_fd_write (type 5) (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + call $__imported_wasi_snapshot_preview1_fd_write + i32.const 65535 + i32.and) + (func $__wasi_proc_exit (type 6) (param i32) + local.get 0 + call $__imported_wasi_snapshot_preview1_proc_exit + unreachable) + (func $abort (type 7) + unreachable + unreachable) + (func $sbrk (type 2) (param i32) (result i32) + block ;; label = @1 + local.get 0 + br_if 0 (;@1;) + memory.size + i32.const 16 + i32.shl + return + end + block ;; label = @1 + local.get 0 + i32.const 65535 + i32.and + br_if 0 (;@1;) + local.get 0 + i32.const -1 + i32.le_s + br_if 0 (;@1;) + block ;; label = @2 + local.get 0 + i32.const 16 + i32.shr_u + memory.grow + local.tee 0 + i32.const -1 + i32.ne + br_if 0 (;@2;) + i32.const 0 + i32.const 48 + i32.store offset=4228 + i32.const -1 + return + end + local.get 0 + i32.const 16 + i32.shl + return + end + call $abort + unreachable) + (func $dummy (type 7)) + (func $__wasm_call_dtors (type 7) + call $dummy + call $__stdio_exit) + (func $printf (type 3) (param i32 i32) (result i32) + (local i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 2 + global.set $__stack_pointer + local.get 2 + local.get 1 + i32.store offset=12 + i32.const 3488 + local.get 0 + local.get 1 + call $vfprintf + local.set 1 + local.get 2 + i32.const 16 + i32.add + global.set $__stack_pointer + local.get 1) + (func $close (type 2) (param i32) (result i32) + block ;; label = @1 + local.get 0 + call $__wasi_fd_close + local.tee 0 + br_if 0 (;@1;) + i32.const 0 + return + end + i32.const 0 + local.get 0 + i32.store offset=4228 + i32.const -1) + (func $__stdio_close (type 2) (param i32) (result i32) + local.get 0 + i32.load offset=56 + call $close) + (func $writev (type 0) (param i32 i32 i32) (result i32) + (local i32 i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 3 + global.set $__stack_pointer + i32.const -1 + local.set 4 + block ;; label = @1 + block ;; label = @2 + local.get 2 + i32.const -1 + i32.gt_s + br_if 0 (;@2;) + i32.const 0 + i32.const 28 + i32.store offset=4228 + br 1 (;@1;) + end + block ;; label = @2 + local.get 0 + local.get 1 + local.get 2 + local.get 3 + i32.const 12 + i32.add + call $__wasi_fd_write + local.tee 2 + i32.eqz + br_if 0 (;@2;) + i32.const 0 + local.get 2 + i32.store offset=4228 + i32.const -1 + local.set 4 + br 1 (;@1;) + end + local.get 3 + i32.load offset=12 + local.set 4 + end + local.get 3 + i32.const 16 + i32.add + global.set $__stack_pointer + local.get 4) + (func $__stdio_write (type 0) (param i32 i32 i32) (result i32) + (local i32 i32 i32 i32 i32 i32 i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 3 + global.set $__stack_pointer + local.get 3 + local.get 2 + i32.store offset=12 + local.get 3 + local.get 1 + i32.store offset=8 + local.get 3 + local.get 0 + i32.load offset=24 + local.tee 1 + i32.store + local.get 3 + local.get 0 + i32.load offset=20 + local.get 1 + i32.sub + local.tee 1 + i32.store offset=4 + i32.const 2 + local.set 4 + block ;; label = @1 + block ;; label = @2 + local.get 1 + local.get 2 + i32.add + local.tee 5 + local.get 0 + i32.load offset=56 + local.get 3 + i32.const 2 + call $writev + local.tee 1 + i32.eq + br_if 0 (;@2;) + local.get 3 + local.set 6 + loop ;; label = @3 + block ;; label = @4 + local.get 1 + i32.const -1 + i32.gt_s + br_if 0 (;@4;) + i32.const 0 + local.set 1 + local.get 0 + i32.const 0 + i32.store offset=24 + local.get 0 + i64.const 0 + i64.store offset=16 + local.get 0 + local.get 0 + i32.load + i32.const 32 + i32.or + i32.store + local.get 4 + i32.const 2 + i32.eq + br_if 3 (;@1;) + local.get 2 + local.get 6 + i32.load offset=4 + i32.sub + local.set 1 + br 3 (;@1;) + end + local.get 6 + local.get 1 + local.get 6 + i32.load offset=4 + local.tee 7 + i32.gt_u + local.tee 8 + i32.const 3 + i32.shl + i32.add + local.tee 9 + local.get 9 + i32.load + local.get 1 + local.get 7 + i32.const 0 + local.get 8 + select + i32.sub + local.tee 7 + i32.add + i32.store + local.get 6 + i32.const 12 + i32.const 4 + local.get 8 + select + i32.add + local.tee 6 + local.get 6 + i32.load + local.get 7 + i32.sub + i32.store + local.get 9 + local.set 6 + local.get 5 + local.get 1 + i32.sub + local.tee 5 + local.get 0 + i32.load offset=56 + local.get 9 + local.get 4 + local.get 8 + i32.sub + local.tee 4 + call $writev + local.tee 1 + i32.ne + br_if 0 (;@3;) + end + end + local.get 0 + local.get 0 + i32.load offset=40 + local.tee 1 + i32.store offset=24 + local.get 0 + local.get 1 + i32.store offset=20 + local.get 0 + local.get 1 + local.get 0 + i32.load offset=44 + i32.add + i32.store offset=16 + local.get 2 + local.set 1 + end + local.get 3 + i32.const 16 + i32.add + global.set $__stack_pointer + local.get 1) + (func $__isatty (type 2) (param i32) (result i32) + (local i32 i32) + global.get $__stack_pointer + i32.const 32 + i32.sub + local.tee 1 + global.set $__stack_pointer + block ;; label = @1 + block ;; label = @2 + local.get 0 + local.get 1 + i32.const 8 + i32.add + call $__wasi_fd_fdstat_get + local.tee 0 + br_if 0 (;@2;) + i32.const 59 + local.set 0 + local.get 1 + i32.load8_u offset=8 + i32.const 2 + i32.ne + br_if 0 (;@2;) + local.get 1 + i32.load8_u offset=16 + i32.const 36 + i32.and + br_if 0 (;@2;) + i32.const 1 + local.set 2 + br 1 (;@1;) + end + i32.const 0 + local.set 2 + i32.const 0 + local.get 0 + i32.store offset=4228 + end + local.get 1 + i32.const 32 + i32.add + global.set $__stack_pointer + local.get 2) + (func $__stdout_write (type 0) (param i32 i32 i32) (result i32) + local.get 0 + i32.const 1 + i32.store offset=32 + block ;; label = @1 + local.get 0 + i32.load8_u + i32.const 64 + i32.and + br_if 0 (;@1;) + local.get 0 + i32.load offset=56 + call $__isatty + br_if 0 (;@1;) + local.get 0 + i32.const -1 + i32.store offset=64 + end + local.get 0 + local.get 1 + local.get 2 + call $__stdio_write) + (func $__lseek (type 1) (param i32 i64 i32) (result i64) + (local i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 3 + global.set $__stack_pointer + block ;; label = @1 + block ;; label = @2 + local.get 0 + local.get 1 + local.get 2 + i32.const 255 + i32.and + local.get 3 + i32.const 8 + i32.add + call $__wasi_fd_seek + local.tee 2 + i32.eqz + br_if 0 (;@2;) + i32.const 0 + i32.const 70 + local.get 2 + local.get 2 + i32.const 76 + i32.eq + select + i32.store offset=4228 + i64.const -1 + local.set 1 + br 1 (;@1;) + end + local.get 3 + i64.load offset=8 + local.set 1 + end + local.get 3 + i32.const 16 + i32.add + global.set $__stack_pointer + local.get 1) + (func $__stdio_seek (type 1) (param i32 i64 i32) (result i64) + local.get 0 + i32.load offset=56 + local.get 1 + local.get 2 + call $__lseek) + (func $__ofl_lock (type 8) (result i32) + i32.const 5272) + (func $__stdio_exit (type 7) + (local i32 i32 i32) + block ;; label = @1 + call $__ofl_lock + i32.load + local.tee 0 + i32.eqz + br_if 0 (;@1;) + loop ;; label = @2 + block ;; label = @3 + local.get 0 + i32.load offset=20 + local.get 0 + i32.load offset=24 + i32.eq + br_if 0 (;@3;) + local.get 0 + i32.const 0 + i32.const 0 + local.get 0 + i32.load offset=32 + call_indirect (type 0) + drop + end + block ;; label = @3 + local.get 0 + i32.load offset=4 + local.tee 1 + local.get 0 + i32.load offset=8 + local.tee 2 + i32.eq + br_if 0 (;@3;) + local.get 0 + local.get 1 + local.get 2 + i32.sub + i64.extend_i32_s + i32.const 1 + local.get 0 + i32.load offset=36 + call_indirect (type 1) + drop + end + local.get 0 + i32.load offset=52 + local.tee 0 + br_if 0 (;@2;) + end + end + block ;; label = @1 + i32.const 0 + i32.load offset=5276 + local.tee 0 + i32.eqz + br_if 0 (;@1;) + block ;; label = @2 + local.get 0 + i32.load offset=20 + local.get 0 + i32.load offset=24 + i32.eq + br_if 0 (;@2;) + local.get 0 + i32.const 0 + i32.const 0 + local.get 0 + i32.load offset=32 + call_indirect (type 0) + drop + end + local.get 0 + i32.load offset=4 + local.tee 1 + local.get 0 + i32.load offset=8 + local.tee 2 + i32.eq + br_if 0 (;@1;) + local.get 0 + local.get 1 + local.get 2 + i32.sub + i64.extend_i32_s + i32.const 1 + local.get 0 + i32.load offset=36 + call_indirect (type 1) + drop + end + block ;; label = @1 + i32.const 0 + i32.load offset=3600 + local.tee 0 + i32.eqz + br_if 0 (;@1;) + block ;; label = @2 + local.get 0 + i32.load offset=20 + local.get 0 + i32.load offset=24 + i32.eq + br_if 0 (;@2;) + local.get 0 + i32.const 0 + i32.const 0 + local.get 0 + i32.load offset=32 + call_indirect (type 0) + drop + end + local.get 0 + i32.load offset=4 + local.tee 1 + local.get 0 + i32.load offset=8 + local.tee 2 + i32.eq + br_if 0 (;@1;) + local.get 0 + local.get 1 + local.get 2 + i32.sub + i64.extend_i32_s + i32.const 1 + local.get 0 + i32.load offset=36 + call_indirect (type 1) + drop + end + block ;; label = @1 + i32.const 0 + i32.load offset=3720 + local.tee 0 + i32.eqz + br_if 0 (;@1;) + block ;; label = @2 + local.get 0 + i32.load offset=20 + local.get 0 + i32.load offset=24 + i32.eq + br_if 0 (;@2;) + local.get 0 + i32.const 0 + i32.const 0 + local.get 0 + i32.load offset=32 + call_indirect (type 0) + drop + end + local.get 0 + i32.load offset=4 + local.tee 1 + local.get 0 + i32.load offset=8 + local.tee 2 + i32.eq + br_if 0 (;@1;) + local.get 0 + local.get 1 + local.get 2 + i32.sub + i64.extend_i32_s + i32.const 1 + local.get 0 + i32.load offset=36 + call_indirect (type 1) + drop + end) + (func $__towrite (type 2) (param i32) (result i32) + (local i32) + local.get 0 + local.get 0 + i32.load offset=60 + local.tee 1 + i32.const -1 + i32.add + local.get 1 + i32.or + i32.store offset=60 + block ;; label = @1 + local.get 0 + i32.load + local.tee 1 + i32.const 8 + i32.and + i32.eqz + br_if 0 (;@1;) + local.get 0 + local.get 1 + i32.const 32 + i32.or + i32.store + i32.const -1 + return + end + local.get 0 + i64.const 0 + i64.store offset=4 align=4 + local.get 0 + local.get 0 + i32.load offset=40 + local.tee 1 + i32.store offset=24 + local.get 0 + local.get 1 + i32.store offset=20 + local.get 0 + local.get 1 + local.get 0 + i32.load offset=44 + i32.add + i32.store offset=16 + i32.const 0) + (func $__fwritex (type 0) (param i32 i32 i32) (result i32) + (local i32 i32 i32 i32 i32) + block ;; label = @1 + block ;; label = @2 + local.get 2 + i32.load offset=16 + local.tee 3 + br_if 0 (;@2;) + i32.const 0 + local.set 4 + local.get 2 + call $__towrite + br_if 1 (;@1;) + local.get 2 + i32.load offset=16 + local.set 3 + end + block ;; label = @2 + local.get 3 + local.get 2 + i32.load offset=20 + local.tee 5 + i32.sub + local.get 1 + i32.ge_u + br_if 0 (;@2;) + local.get 2 + local.get 0 + local.get 1 + local.get 2 + i32.load offset=32 + call_indirect (type 0) + return + end + i32.const 0 + local.set 6 + block ;; label = @2 + local.get 2 + i32.load offset=64 + i32.const 0 + i32.lt_s + br_if 0 (;@2;) + i32.const 0 + local.set 6 + local.get 0 + local.set 4 + i32.const 0 + local.set 3 + loop ;; label = @3 + local.get 1 + local.get 3 + i32.eq + br_if 1 (;@2;) + local.get 3 + i32.const 1 + i32.add + local.set 3 + local.get 4 + i32.const -1 + i32.add + local.tee 4 + local.get 1 + i32.add + local.tee 7 + i32.load8_u + i32.const 10 + i32.ne + br_if 0 (;@3;) + end + local.get 2 + local.get 0 + local.get 1 + local.get 3 + i32.sub + i32.const 1 + i32.add + local.tee 6 + local.get 2 + i32.load offset=32 + call_indirect (type 0) + local.tee 4 + local.get 6 + i32.lt_u + br_if 1 (;@1;) + local.get 3 + i32.const -1 + i32.add + local.set 1 + local.get 7 + i32.const 1 + i32.add + local.set 0 + local.get 2 + i32.load offset=20 + local.set 5 + end + local.get 5 + local.get 0 + local.get 1 + call $memcpy + drop + local.get 2 + local.get 2 + i32.load offset=20 + local.get 1 + i32.add + i32.store offset=20 + local.get 6 + local.get 1 + i32.add + local.set 4 + end + local.get 4) + (func $fwrite (type 5) (param i32 i32 i32 i32) (result i32) + (local i32 i32 i32 i32 i32 i32) + local.get 2 + local.get 1 + i32.mul + local.set 4 + block ;; label = @1 + block ;; label = @2 + local.get 3 + i32.load offset=16 + local.tee 5 + br_if 0 (;@2;) + i32.const 0 + local.set 6 + local.get 3 + call $__towrite + br_if 1 (;@1;) + local.get 3 + i32.load offset=16 + local.set 5 + end + block ;; label = @2 + local.get 5 + local.get 3 + i32.load offset=20 + local.tee 7 + i32.sub + local.get 4 + i32.ge_u + br_if 0 (;@2;) + local.get 3 + local.get 0 + local.get 4 + local.get 3 + i32.load offset=32 + call_indirect (type 0) + local.set 6 + br 1 (;@1;) + end + i32.const 0 + local.set 8 + block ;; label = @2 + block ;; label = @3 + local.get 3 + i32.load offset=64 + i32.const 0 + i32.ge_s + br_if 0 (;@3;) + local.get 4 + local.set 5 + br 1 (;@2;) + end + local.get 0 + local.get 4 + i32.add + local.set 6 + i32.const 0 + local.set 8 + i32.const 0 + local.set 5 + loop ;; label = @3 + block ;; label = @4 + local.get 4 + local.get 5 + i32.add + br_if 0 (;@4;) + local.get 4 + local.set 5 + br 2 (;@2;) + end + local.get 5 + i32.const -1 + i32.add + local.tee 5 + local.get 6 + i32.add + local.tee 9 + i32.load8_u + i32.const 10 + i32.ne + br_if 0 (;@3;) + end + local.get 3 + local.get 0 + local.get 4 + local.get 5 + i32.add + i32.const 1 + i32.add + local.tee 8 + local.get 3 + i32.load offset=32 + call_indirect (type 0) + local.tee 6 + local.get 8 + i32.lt_u + br_if 1 (;@1;) + local.get 5 + i32.const -1 + i32.xor + local.set 5 + local.get 9 + i32.const 1 + i32.add + local.set 0 + local.get 3 + i32.load offset=20 + local.set 7 + end + local.get 7 + local.get 0 + local.get 5 + call $memcpy + drop + local.get 3 + local.get 3 + i32.load offset=20 + local.get 5 + i32.add + i32.store offset=20 + local.get 8 + local.get 5 + i32.add + local.set 6 + end + block ;; label = @1 + local.get 6 + local.get 4 + i32.ne + br_if 0 (;@1;) + local.get 2 + i32.const 0 + local.get 1 + select + return + end + local.get 6 + local.get 1 + i32.div_u) + (func $dummy.1 (type 3) (param i32 i32) (result i32) + local.get 0) + (func $__lctrans (type 3) (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $dummy.1) + (func $strerror (type 2) (param i32) (result i32) + (local i32) + block ;; label = @1 + i32.const 0 + i32.load offset=5304 + local.tee 1 + br_if 0 (;@1;) + i32.const 5280 + local.set 1 + i32.const 0 + i32.const 5280 + i32.store offset=5304 + end + i32.const 0 + local.get 0 + local.get 0 + i32.const 76 + i32.gt_u + select + i32.const 1 + i32.shl + i32.const 2848 + i32.add + i32.load16_u + i32.const 1291 + i32.add + local.get 1 + i32.load offset=20 + call $__lctrans) + (func $wcrtomb (type 0) (param i32 i32 i32) (result i32) + (local i32) + i32.const 1 + local.set 3 + block ;; label = @1 + local.get 0 + i32.eqz + br_if 0 (;@1;) + block ;; label = @2 + local.get 1 + i32.const 127 + i32.gt_u + br_if 0 (;@2;) + local.get 0 + local.get 1 + i32.store8 + i32.const 1 + return + end + block ;; label = @2 + block ;; label = @3 + i32.const 0 + i32.load offset=5280 + br_if 0 (;@3;) + block ;; label = @4 + local.get 1 + i32.const -128 + i32.and + i32.const 57216 + i32.eq + br_if 0 (;@4;) + i32.const 0 + i32.const 25 + i32.store offset=4228 + br 2 (;@2;) + end + local.get 0 + local.get 1 + i32.store8 + i32.const 1 + return + end + block ;; label = @3 + local.get 1 + i32.const 2047 + i32.gt_u + br_if 0 (;@3;) + local.get 0 + local.get 1 + i32.const 63 + i32.and + i32.const 128 + i32.or + i32.store8 offset=1 + local.get 0 + local.get 1 + i32.const 6 + i32.shr_u + i32.const 192 + i32.or + i32.store8 + i32.const 2 + return + end + block ;; label = @3 + block ;; label = @4 + local.get 1 + i32.const 55296 + i32.lt_u + br_if 0 (;@4;) + local.get 1 + i32.const -8192 + i32.and + i32.const 57344 + i32.ne + br_if 1 (;@3;) + end + local.get 0 + local.get 1 + i32.const 63 + i32.and + i32.const 128 + i32.or + i32.store8 offset=2 + local.get 0 + local.get 1 + i32.const 12 + i32.shr_u + i32.const 224 + i32.or + i32.store8 + local.get 0 + local.get 1 + i32.const 6 + i32.shr_u + i32.const 63 + i32.and + i32.const 128 + i32.or + i32.store8 offset=1 + i32.const 3 + return + end + block ;; label = @3 + local.get 1 + i32.const -65536 + i32.add + i32.const 1048575 + i32.gt_u + br_if 0 (;@3;) + local.get 0 + local.get 1 + i32.const 63 + i32.and + i32.const 128 + i32.or + i32.store8 offset=3 + local.get 0 + local.get 1 + i32.const 18 + i32.shr_u + i32.const 240 + i32.or + i32.store8 + local.get 0 + local.get 1 + i32.const 6 + i32.shr_u + i32.const 63 + i32.and + i32.const 128 + i32.or + i32.store8 offset=2 + local.get 0 + local.get 1 + i32.const 12 + i32.shr_u + i32.const 63 + i32.and + i32.const 128 + i32.or + i32.store8 offset=1 + i32.const 4 + return + end + i32.const 0 + i32.const 25 + i32.store offset=4228 + end + i32.const -1 + local.set 3 + end + local.get 3) + (func $wctomb (type 3) (param i32 i32) (result i32) + block ;; label = @1 + local.get 0 + br_if 0 (;@1;) + i32.const 0 + return + end + local.get 0 + local.get 1 + i32.const 0 + call $wcrtomb) + (func $frexp (type 9) (param f64 i32) (result f64) + (local i64 i32) + block ;; label = @1 + local.get 0 + i64.reinterpret_f64 + local.tee 2 + i64.const 52 + i64.shr_u + i32.wrap_i64 + i32.const 2047 + i32.and + local.tee 3 + i32.const 2047 + i32.eq + br_if 0 (;@1;) + block ;; label = @2 + local.get 3 + br_if 0 (;@2;) + block ;; label = @3 + local.get 0 + f64.const 0x0p+0 (;=0;) + f64.ne + br_if 0 (;@3;) + local.get 1 + i32.const 0 + i32.store + local.get 0 + return + end + local.get 0 + f64.const 0x1p+64 (;=1.84467e+19;) + f64.mul + local.get 1 + call $frexp + local.set 0 + local.get 1 + local.get 1 + i32.load + i32.const -64 + i32.add + i32.store + local.get 0 + return + end + local.get 1 + local.get 3 + i32.const -1022 + i32.add + i32.store + local.get 2 + i64.const -9218868437227405313 + i64.and + i64.const 4602678819172646912 + i64.or + f64.reinterpret_i64 + local.set 0 + end + local.get 0) + (func $fputs (type 3) (param i32 i32) (result i32) + (local i32) + local.get 0 + call $strlen + local.set 2 + i32.const -1 + i32.const 0 + local.get 2 + local.get 0 + i32.const 1 + local.get 2 + local.get 1 + call $fwrite + i32.ne + select) + (func $vfprintf (type 0) (param i32 i32 i32) (result i32) + (local i32 i32 i32) + global.get $__stack_pointer + i32.const 208 + i32.sub + local.tee 3 + global.set $__stack_pointer + local.get 3 + local.get 2 + i32.store offset=204 + local.get 3 + i32.const 160 + i32.add + i32.const 32 + i32.add + i64.const 0 + i64.store + local.get 3 + i32.const 184 + i32.add + i64.const 0 + i64.store + local.get 3 + i32.const 176 + i32.add + i64.const 0 + i64.store + local.get 3 + i64.const 0 + i64.store offset=168 + local.get 3 + i64.const 0 + i64.store offset=160 + local.get 3 + local.get 2 + i32.store offset=200 + block ;; label = @1 + block ;; label = @2 + i32.const 0 + local.get 1 + local.get 3 + i32.const 200 + i32.add + local.get 3 + i32.const 80 + i32.add + local.get 3 + i32.const 160 + i32.add + call $printf_core + i32.const 0 + i32.ge_s + br_if 0 (;@2;) + i32.const -1 + local.set 0 + br 1 (;@1;) + end + local.get 0 + i32.load + local.set 4 + block ;; label = @2 + local.get 0 + i32.load offset=60 + i32.const 0 + i32.gt_s + br_if 0 (;@2;) + local.get 0 + local.get 4 + i32.const -33 + i32.and + i32.store + end + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + local.get 0 + i32.load offset=44 + br_if 0 (;@5;) + local.get 0 + i32.const 80 + i32.store offset=44 + local.get 0 + i32.const 0 + i32.store offset=24 + local.get 0 + i64.const 0 + i64.store offset=16 + local.get 0 + i32.load offset=40 + local.set 5 + local.get 0 + local.get 3 + i32.store offset=40 + br 1 (;@4;) + end + i32.const 0 + local.set 5 + local.get 0 + i32.load offset=16 + br_if 1 (;@3;) + end + i32.const -1 + local.set 2 + local.get 0 + call $__towrite + br_if 1 (;@2;) + end + local.get 0 + local.get 1 + local.get 3 + i32.const 200 + i32.add + local.get 3 + i32.const 80 + i32.add + local.get 3 + i32.const 160 + i32.add + call $printf_core + local.set 2 + end + local.get 4 + i32.const 32 + i32.and + local.set 1 + block ;; label = @2 + local.get 5 + i32.eqz + br_if 0 (;@2;) + local.get 0 + i32.const 0 + i32.const 0 + local.get 0 + i32.load offset=32 + call_indirect (type 0) + drop + local.get 0 + i32.const 0 + i32.store offset=44 + local.get 0 + local.get 5 + i32.store offset=40 + local.get 0 + i32.const 0 + i32.store offset=24 + local.get 0 + i32.load offset=20 + local.set 5 + local.get 0 + i64.const 0 + i64.store offset=16 + local.get 2 + i32.const -1 + local.get 5 + select + local.set 2 + end + local.get 0 + local.get 0 + i32.load + local.tee 5 + local.get 1 + i32.or + i32.store + i32.const -1 + local.get 2 + local.get 5 + i32.const 32 + i32.and + select + local.set 0 + end + local.get 3 + i32.const 208 + i32.add + global.set $__stack_pointer + local.get 0) + (func $printf_core (type 10) (param i32 i32 i32 i32 i32) (result i32) + (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i64 i64 f64 i32 i32 i32 i32 i32 i32 i32 i32 f64) + global.get $__stack_pointer + i32.const 880 + i32.sub + local.tee 5 + global.set $__stack_pointer + local.get 5 + i32.const 68 + i32.add + i32.const 12 + i32.add + local.set 6 + i32.const 0 + local.get 5 + i32.const 112 + i32.add + i32.sub + local.set 7 + local.get 5 + i32.const -3988 + i32.add + local.set 8 + local.get 5 + i32.const 55 + i32.add + local.set 9 + local.get 5 + i32.const 80 + i32.add + i32.const -2 + i32.xor + local.set 10 + local.get 5 + i32.const 68 + i32.add + i32.const 11 + i32.add + local.set 11 + local.get 5 + i32.const 80 + i32.add + i32.const 8 + i32.or + local.set 12 + local.get 5 + i32.const 80 + i32.add + i32.const 9 + i32.or + local.set 13 + i32.const -10 + local.get 5 + i32.const 68 + i32.add + i32.sub + local.set 14 + local.get 5 + i32.const 68 + i32.add + i32.const 10 + i32.add + local.set 15 + local.get 5 + i32.const 56 + i32.add + local.set 16 + i32.const 0 + local.set 17 + i32.const 0 + local.set 18 + i32.const 0 + local.set 19 + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + loop ;; label = @4 + local.get 1 + local.set 20 + local.get 19 + local.get 18 + i32.const 2147483647 + i32.xor + i32.gt_s + br_if 1 (;@3;) + local.get 19 + local.get 18 + i32.add + local.set 18 + block ;; label = @5 + block ;; label = @6 + block ;; label = @7 + block ;; label = @8 + block ;; label = @9 + block ;; label = @10 + block ;; label = @11 + block ;; label = @12 + block ;; label = @13 + local.get 20 + i32.load8_u + local.tee 19 + i32.eqz + br_if 0 (;@13;) + local.get 20 + local.set 1 + loop ;; label = @14 + block ;; label = @15 + block ;; label = @16 + block ;; label = @17 + local.get 19 + i32.const 255 + i32.and + local.tee 19 + i32.eqz + br_if 0 (;@17;) + local.get 19 + i32.const 37 + i32.ne + br_if 2 (;@15;) + local.get 1 + local.set 21 + local.get 1 + local.set 19 + loop ;; label = @18 + block ;; label = @19 + local.get 19 + i32.load8_u offset=1 + i32.const 37 + i32.eq + br_if 0 (;@19;) + local.get 19 + local.set 1 + br 3 (;@16;) + end + local.get 21 + i32.const 1 + i32.add + local.set 21 + local.get 19 + i32.load8_u offset=2 + local.set 22 + local.get 19 + i32.const 2 + i32.add + local.tee 1 + local.set 19 + local.get 22 + i32.const 37 + i32.eq + br_if 0 (;@18;) + br 2 (;@16;) + end + end + local.get 1 + local.set 21 + end + local.get 21 + local.get 20 + i32.sub + local.tee 19 + local.get 18 + i32.const 2147483647 + i32.xor + local.tee 21 + i32.gt_s + br_if 12 (;@3;) + block ;; label = @16 + local.get 0 + i32.eqz + br_if 0 (;@16;) + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@16;) + local.get 20 + local.get 19 + local.get 0 + call $__fwritex + drop + end + local.get 19 + br_if 11 (;@4;) + local.get 1 + i32.const 1 + i32.add + local.set 19 + i32.const -1 + local.set 23 + block ;; label = @16 + local.get 1 + i32.load8_s offset=1 + local.tee 24 + i32.const -48 + i32.add + local.tee 22 + i32.const 9 + i32.gt_u + br_if 0 (;@16;) + local.get 1 + i32.load8_u offset=2 + i32.const 36 + i32.ne + br_if 0 (;@16;) + local.get 1 + i32.const 3 + i32.add + local.set 19 + local.get 1 + i32.load8_s offset=3 + local.set 24 + i32.const 1 + local.set 17 + local.get 22 + local.set 23 + end + i32.const 0 + local.set 25 + block ;; label = @16 + local.get 24 + i32.const -32 + i32.add + local.tee 1 + i32.const 31 + i32.gt_u + br_if 0 (;@16;) + i32.const 1 + local.get 1 + i32.shl + local.tee 1 + i32.const 75913 + i32.and + i32.eqz + br_if 0 (;@16;) + local.get 19 + i32.const 1 + i32.add + local.set 22 + i32.const 0 + local.set 25 + loop ;; label = @17 + local.get 1 + local.get 25 + i32.or + local.set 25 + local.get 22 + local.tee 19 + i32.load8_s + local.tee 24 + i32.const -32 + i32.add + local.tee 1 + i32.const 32 + i32.ge_u + br_if 1 (;@16;) + local.get 19 + i32.const 1 + i32.add + local.set 22 + i32.const 1 + local.get 1 + i32.shl + local.tee 1 + i32.const 75913 + i32.and + br_if 0 (;@17;) + end + end + block ;; label = @16 + local.get 24 + i32.const 42 + i32.ne + br_if 0 (;@16;) + block ;; label = @17 + block ;; label = @18 + local.get 19 + i32.load8_s offset=1 + i32.const -48 + i32.add + local.tee 1 + i32.const 9 + i32.gt_u + br_if 0 (;@18;) + local.get 19 + i32.load8_u offset=2 + i32.const 36 + i32.ne + br_if 0 (;@18;) + local.get 4 + local.get 1 + i32.const 2 + i32.shl + i32.add + i32.const 10 + i32.store + local.get 19 + i32.const 3 + i32.add + local.set 22 + local.get 19 + i32.load8_s offset=1 + i32.const 3 + i32.shl + local.get 3 + i32.add + i32.const -384 + i32.add + i32.load + local.set 26 + i32.const 1 + local.set 17 + br 1 (;@17;) + end + local.get 17 + br_if 6 (;@11;) + local.get 19 + i32.const 1 + i32.add + local.set 22 + block ;; label = @18 + local.get 0 + br_if 0 (;@18;) + i32.const 0 + local.set 17 + i32.const 0 + local.set 26 + br 6 (;@12;) + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 1 + i32.load + local.set 26 + i32.const 0 + local.set 17 + end + local.get 26 + i32.const -1 + i32.gt_s + br_if 4 (;@12;) + i32.const 0 + local.get 26 + i32.sub + local.set 26 + local.get 25 + i32.const 8192 + i32.or + local.set 25 + br 4 (;@12;) + end + i32.const 0 + local.set 26 + block ;; label = @16 + local.get 24 + i32.const -48 + i32.add + local.tee 1 + i32.const 9 + i32.le_u + br_if 0 (;@16;) + local.get 19 + local.set 22 + br 4 (;@12;) + end + i32.const 0 + local.set 26 + loop ;; label = @16 + block ;; label = @17 + local.get 26 + i32.const 214748364 + i32.gt_u + br_if 0 (;@17;) + i32.const -1 + local.get 26 + i32.const 10 + i32.mul + local.tee 22 + local.get 1 + i32.add + local.get 1 + local.get 22 + i32.const 2147483647 + i32.xor + i32.gt_u + select + local.set 26 + local.get 19 + i32.load8_s offset=1 + local.set 1 + local.get 19 + i32.const 1 + i32.add + local.tee 22 + local.set 19 + local.get 1 + i32.const -48 + i32.add + local.tee 1 + i32.const 10 + i32.lt_u + br_if 1 (;@16;) + local.get 26 + i32.const 0 + i32.lt_s + br_if 14 (;@3;) + br 5 (;@12;) + end + local.get 19 + i32.load8_s offset=1 + local.set 1 + i32.const -1 + local.set 26 + local.get 19 + i32.const 1 + i32.add + local.set 19 + local.get 1 + i32.const -48 + i32.add + local.tee 1 + i32.const 10 + i32.lt_u + br_if 0 (;@16;) + br 13 (;@3;) + end + end + local.get 1 + i32.load8_u offset=1 + local.set 19 + local.get 1 + i32.const 1 + i32.add + local.set 1 + br 0 (;@14;) + end + end + local.get 0 + br_if 11 (;@1;) + block ;; label = @13 + local.get 17 + br_if 0 (;@13;) + i32.const 0 + local.set 18 + br 12 (;@1;) + end + block ;; label = @13 + block ;; label = @14 + local.get 4 + i32.load offset=4 + local.tee 1 + br_if 0 (;@14;) + i32.const 1 + local.set 1 + br 1 (;@13;) + end + local.get 3 + i32.const 8 + i32.add + local.get 1 + local.get 2 + call $pop_arg + block ;; label = @14 + local.get 4 + i32.load offset=8 + local.tee 1 + br_if 0 (;@14;) + i32.const 2 + local.set 1 + br 1 (;@13;) + end + local.get 3 + i32.const 16 + i32.add + local.get 1 + local.get 2 + call $pop_arg + block ;; label = @14 + local.get 4 + i32.load offset=12 + local.tee 1 + br_if 0 (;@14;) + i32.const 3 + local.set 1 + br 1 (;@13;) + end + local.get 3 + i32.const 24 + i32.add + local.get 1 + local.get 2 + call $pop_arg + block ;; label = @14 + local.get 4 + i32.load offset=16 + local.tee 1 + br_if 0 (;@14;) + i32.const 4 + local.set 1 + br 1 (;@13;) + end + local.get 3 + i32.const 32 + i32.add + local.get 1 + local.get 2 + call $pop_arg + block ;; label = @14 + local.get 4 + i32.load offset=20 + local.tee 1 + br_if 0 (;@14;) + i32.const 5 + local.set 1 + br 1 (;@13;) + end + local.get 3 + i32.const 40 + i32.add + local.get 1 + local.get 2 + call $pop_arg + block ;; label = @14 + local.get 4 + i32.load offset=24 + local.tee 1 + br_if 0 (;@14;) + i32.const 6 + local.set 1 + br 1 (;@13;) + end + local.get 3 + i32.const 48 + i32.add + local.get 1 + local.get 2 + call $pop_arg + block ;; label = @14 + local.get 4 + i32.load offset=28 + local.tee 1 + br_if 0 (;@14;) + i32.const 7 + local.set 1 + br 1 (;@13;) + end + local.get 3 + i32.const 56 + i32.add + local.get 1 + local.get 2 + call $pop_arg + block ;; label = @14 + local.get 4 + i32.load offset=32 + local.tee 1 + br_if 0 (;@14;) + i32.const 8 + local.set 1 + br 1 (;@13;) + end + local.get 3 + i32.const 64 + i32.add + local.get 1 + local.get 2 + call $pop_arg + block ;; label = @14 + local.get 4 + i32.load offset=36 + local.tee 1 + br_if 0 (;@14;) + i32.const 9 + local.set 1 + br 1 (;@13;) + end + local.get 3 + i32.const 72 + i32.add + local.get 1 + local.get 2 + call $pop_arg + i32.const 1 + local.set 18 + br 12 (;@1;) + end + local.get 1 + i32.const 2 + i32.shl + local.set 1 + loop ;; label = @13 + local.get 4 + local.get 1 + i32.add + i32.load + br_if 2 (;@11;) + local.get 1 + i32.const 4 + i32.add + local.tee 1 + i32.const 40 + i32.ne + br_if 0 (;@13;) + end + i32.const 1 + local.set 18 + br 11 (;@1;) + end + i32.const 0 + local.set 19 + i32.const -1 + local.set 24 + block ;; label = @12 + block ;; label = @13 + local.get 22 + i32.load8_u + i32.const 46 + i32.eq + br_if 0 (;@13;) + local.get 22 + local.set 1 + i32.const 0 + local.set 27 + br 1 (;@12;) + end + block ;; label = @13 + local.get 22 + i32.load8_s offset=1 + local.tee 24 + i32.const 42 + i32.ne + br_if 0 (;@13;) + block ;; label = @14 + block ;; label = @15 + local.get 22 + i32.load8_s offset=2 + i32.const -48 + i32.add + local.tee 1 + i32.const 9 + i32.gt_u + br_if 0 (;@15;) + local.get 22 + i32.load8_u offset=3 + i32.const 36 + i32.ne + br_if 0 (;@15;) + local.get 4 + local.get 1 + i32.const 2 + i32.shl + i32.add + i32.const 10 + i32.store + local.get 22 + i32.const 4 + i32.add + local.set 1 + local.get 22 + i32.load8_s offset=2 + i32.const 3 + i32.shl + local.get 3 + i32.add + i32.const -384 + i32.add + i32.load + local.set 24 + br 1 (;@14;) + end + local.get 17 + br_if 3 (;@11;) + local.get 22 + i32.const 2 + i32.add + local.set 1 + block ;; label = @15 + local.get 0 + br_if 0 (;@15;) + i32.const 0 + local.set 24 + br 1 (;@14;) + end + local.get 2 + local.get 2 + i32.load + local.tee 22 + i32.const 4 + i32.add + i32.store + local.get 22 + i32.load + local.set 24 + end + local.get 24 + i32.const -1 + i32.xor + i32.const 31 + i32.shr_u + local.set 27 + br 1 (;@12;) + end + local.get 22 + i32.const 1 + i32.add + local.set 1 + block ;; label = @13 + local.get 24 + i32.const -48 + i32.add + local.tee 28 + i32.const 9 + i32.le_u + br_if 0 (;@13;) + i32.const 1 + local.set 27 + i32.const 0 + local.set 24 + br 1 (;@12;) + end + i32.const 0 + local.set 29 + local.get 1 + local.set 22 + loop ;; label = @13 + i32.const -1 + local.set 24 + block ;; label = @14 + local.get 29 + i32.const 214748364 + i32.gt_u + br_if 0 (;@14;) + i32.const -1 + local.get 29 + i32.const 10 + i32.mul + local.tee 1 + local.get 28 + i32.add + local.get 28 + local.get 1 + i32.const 2147483647 + i32.xor + i32.gt_u + select + local.set 24 + end + i32.const 1 + local.set 27 + local.get 22 + i32.load8_s offset=1 + local.set 28 + local.get 24 + local.set 29 + local.get 22 + i32.const 1 + i32.add + local.tee 1 + local.set 22 + local.get 28 + i32.const -48 + i32.add + local.tee 28 + i32.const 10 + i32.lt_u + br_if 0 (;@13;) + end + end + loop ;; label = @12 + local.get 19 + local.set 22 + local.get 1 + i32.load8_s + local.tee 19 + i32.const -123 + i32.add + i32.const -58 + i32.lt_u + br_if 1 (;@11;) + local.get 1 + i32.const 1 + i32.add + local.set 1 + local.get 19 + local.get 22 + i32.const 58 + i32.mul + i32.add + i32.const 2943 + i32.add + i32.load8_u + local.tee 19 + i32.const -1 + i32.add + i32.const 8 + i32.lt_u + br_if 0 (;@12;) + end + block ;; label = @12 + block ;; label = @13 + block ;; label = @14 + local.get 19 + i32.const 27 + i32.eq + br_if 0 (;@14;) + local.get 19 + i32.eqz + br_if 3 (;@11;) + block ;; label = @15 + local.get 23 + i32.const 0 + i32.lt_s + br_if 0 (;@15;) + local.get 4 + local.get 23 + i32.const 2 + i32.shl + i32.add + local.get 19 + i32.store + local.get 5 + local.get 3 + local.get 23 + i32.const 3 + i32.shl + i32.add + i64.load + i64.store offset=56 + br 2 (;@13;) + end + block ;; label = @15 + local.get 0 + br_if 0 (;@15;) + i32.const 0 + local.set 18 + br 14 (;@1;) + end + local.get 5 + i32.const 56 + i32.add + local.get 19 + local.get 2 + call $pop_arg + br 2 (;@12;) + end + local.get 23 + i32.const -1 + i32.gt_s + br_if 2 (;@11;) + end + i32.const 0 + local.set 19 + local.get 0 + i32.eqz + br_if 8 (;@4;) + end + local.get 25 + i32.const -65537 + i32.and + local.tee 29 + local.get 25 + local.get 25 + i32.const 8192 + i32.and + select + local.set 30 + block ;; label = @12 + block ;; label = @13 + block ;; label = @14 + block ;; label = @15 + block ;; label = @16 + block ;; label = @17 + block ;; label = @18 + block ;; label = @19 + block ;; label = @20 + block ;; label = @21 + block ;; label = @22 + block ;; label = @23 + block ;; label = @24 + block ;; label = @25 + block ;; label = @26 + block ;; label = @27 + block ;; label = @28 + local.get 1 + i32.const -1 + i32.add + i32.load8_s + local.tee 19 + i32.const -33 + i32.and + local.get 19 + local.get 19 + i32.const 15 + i32.and + i32.const 3 + i32.eq + select + local.get 19 + local.get 22 + select + local.tee 31 + i32.const -65 + i32.add + br_table 16 (;@12;) 18 (;@10;) 13 (;@15;) 18 (;@10;) 16 (;@12;) 16 (;@12;) 16 (;@12;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 12 (;@16;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 3 (;@25;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 16 (;@12;) 18 (;@10;) 8 (;@20;) 5 (;@23;) 16 (;@12;) 16 (;@12;) 16 (;@12;) 18 (;@10;) 5 (;@23;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 9 (;@19;) 1 (;@27;) 4 (;@24;) 2 (;@26;) 18 (;@10;) 18 (;@10;) 10 (;@18;) 18 (;@10;) 0 (;@28;) 18 (;@10;) 18 (;@10;) 3 (;@25;) 18 (;@10;) + end + i32.const 0 + local.set 28 + i32.const 1024 + local.set 23 + local.get 5 + i64.load offset=56 + local.set 32 + br 5 (;@22;) + end + i32.const 0 + local.set 19 + block ;; label = @27 + block ;; label = @28 + block ;; label = @29 + block ;; label = @30 + block ;; label = @31 + block ;; label = @32 + block ;; label = @33 + local.get 22 + i32.const 255 + i32.and + br_table 0 (;@33;) 1 (;@32;) 2 (;@31;) 3 (;@30;) 4 (;@29;) 29 (;@4;) 5 (;@28;) 6 (;@27;) 29 (;@4;) + end + local.get 5 + i32.load offset=56 + local.get 18 + i32.store + br 28 (;@4;) + end + local.get 5 + i32.load offset=56 + local.get 18 + i32.store + br 27 (;@4;) + end + local.get 5 + i32.load offset=56 + local.get 18 + i64.extend_i32_s + i64.store + br 26 (;@4;) + end + local.get 5 + i32.load offset=56 + local.get 18 + i32.store16 + br 25 (;@4;) + end + local.get 5 + i32.load offset=56 + local.get 18 + i32.store8 + br 24 (;@4;) + end + local.get 5 + i32.load offset=56 + local.get 18 + i32.store + br 23 (;@4;) + end + local.get 5 + i32.load offset=56 + local.get 18 + i64.extend_i32_s + i64.store + br 22 (;@4;) + end + local.get 24 + i32.const 8 + local.get 24 + i32.const 8 + i32.gt_u + select + local.set 24 + local.get 30 + i32.const 8 + i32.or + local.set 30 + i32.const 120 + local.set 31 + end + i32.const 0 + local.set 28 + i32.const 1024 + local.set 23 + block ;; label = @25 + local.get 5 + i64.load offset=56 + local.tee 32 + i64.eqz + i32.eqz + br_if 0 (;@25;) + local.get 16 + local.set 20 + br 4 (;@21;) + end + local.get 31 + i32.const 32 + i32.and + local.set 22 + local.get 16 + local.set 20 + loop ;; label = @25 + local.get 20 + i32.const -1 + i32.add + local.tee 20 + local.get 32 + i32.wrap_i64 + i32.const 15 + i32.and + i32.const 3472 + i32.add + i32.load8_u + local.get 22 + i32.or + i32.store8 + local.get 32 + i64.const 15 + i64.gt_u + local.set 19 + local.get 32 + i64.const 4 + i64.shr_u + local.set 32 + local.get 19 + br_if 0 (;@25;) + end + local.get 30 + i32.const 8 + i32.and + i32.eqz + br_if 3 (;@21;) + local.get 31 + i32.const 4 + i32.shr_s + i32.const 1024 + i32.add + local.set 23 + i32.const 2 + local.set 28 + br 3 (;@21;) + end + local.get 16 + local.set 20 + block ;; label = @24 + local.get 5 + i64.load offset=56 + local.tee 32 + i64.eqz + br_if 0 (;@24;) + local.get 16 + local.set 20 + loop ;; label = @25 + local.get 20 + i32.const -1 + i32.add + local.tee 20 + local.get 32 + i32.wrap_i64 + i32.const 7 + i32.and + i32.const 48 + i32.or + i32.store8 + local.get 32 + i64.const 7 + i64.gt_u + local.set 19 + local.get 32 + i64.const 3 + i64.shr_u + local.set 32 + local.get 19 + br_if 0 (;@25;) + end + end + i32.const 0 + local.set 28 + i32.const 1024 + local.set 23 + local.get 30 + i32.const 8 + i32.and + i32.eqz + br_if 2 (;@21;) + local.get 24 + local.get 16 + local.get 20 + i32.sub + local.tee 19 + i32.const 1 + i32.add + local.get 24 + local.get 19 + i32.gt_s + select + local.set 24 + br 2 (;@21;) + end + block ;; label = @23 + local.get 5 + i64.load offset=56 + local.tee 32 + i64.const -1 + i64.gt_s + br_if 0 (;@23;) + local.get 5 + i64.const 0 + local.get 32 + i64.sub + local.tee 32 + i64.store offset=56 + i32.const 1 + local.set 28 + i32.const 1024 + local.set 23 + br 1 (;@22;) + end + block ;; label = @23 + local.get 30 + i32.const 2048 + i32.and + i32.eqz + br_if 0 (;@23;) + i32.const 1 + local.set 28 + i32.const 1025 + local.set 23 + br 1 (;@22;) + end + i32.const 1026 + i32.const 1024 + local.get 30 + i32.const 1 + i32.and + local.tee 28 + select + local.set 23 + end + block ;; label = @22 + block ;; label = @23 + local.get 32 + i64.const 4294967296 + i64.ge_u + br_if 0 (;@23;) + local.get 32 + local.set 33 + local.get 16 + local.set 20 + br 1 (;@22;) + end + local.get 16 + local.set 20 + loop ;; label = @23 + local.get 20 + i32.const -1 + i32.add + local.tee 20 + local.get 32 + local.get 32 + i64.const 10 + i64.div_u + local.tee 33 + i64.const 10 + i64.mul + i64.sub + i32.wrap_i64 + i32.const 48 + i32.or + i32.store8 + local.get 32 + i64.const 42949672959 + i64.gt_u + local.set 19 + local.get 33 + local.set 32 + local.get 19 + br_if 0 (;@23;) + end + end + local.get 33 + i32.wrap_i64 + local.tee 19 + i32.eqz + br_if 0 (;@21;) + loop ;; label = @22 + local.get 20 + i32.const -1 + i32.add + local.tee 20 + local.get 19 + local.get 19 + i32.const 10 + i32.div_u + local.tee 22 + i32.const 10 + i32.mul + i32.sub + i32.const 48 + i32.or + i32.store8 + local.get 19 + i32.const 9 + i32.gt_u + local.set 25 + local.get 22 + local.set 19 + local.get 25 + br_if 0 (;@22;) + end + end + block ;; label = @21 + local.get 27 + i32.eqz + br_if 0 (;@21;) + local.get 24 + i32.const 0 + i32.lt_s + br_if 18 (;@3;) + end + local.get 30 + i32.const -65537 + i32.and + local.get 30 + local.get 27 + select + local.set 29 + block ;; label = @21 + local.get 5 + i64.load offset=56 + local.tee 32 + i64.const 0 + i64.ne + br_if 0 (;@21;) + i32.const 0 + local.set 25 + local.get 24 + br_if 0 (;@21;) + local.get 16 + local.set 20 + local.get 16 + local.set 19 + br 12 (;@9;) + end + local.get 24 + local.get 16 + local.get 20 + i32.sub + local.get 32 + i64.eqz + i32.add + local.tee 19 + local.get 24 + local.get 19 + i32.gt_s + select + local.set 25 + local.get 16 + local.set 19 + br 11 (;@9;) + end + local.get 5 + local.get 5 + i64.load offset=56 + i64.store8 offset=55 + i32.const 0 + local.set 28 + i32.const 1024 + local.set 23 + i32.const 1 + local.set 25 + local.get 9 + local.set 20 + local.get 16 + local.set 19 + br 10 (;@9;) + end + i32.const 4228 + i32.load + call $strerror + local.set 20 + br 1 (;@17;) + end + local.get 5 + i32.load offset=56 + local.tee 19 + i32.const 1071 + local.get 19 + select + local.set 20 + end + local.get 20 + local.get 20 + local.get 24 + i32.const 2147483647 + local.get 24 + i32.const 2147483647 + i32.lt_u + select + call $strnlen + local.tee 25 + i32.add + local.set 19 + i32.const 0 + local.set 28 + i32.const 1024 + local.set 23 + local.get 24 + i32.const -1 + i32.gt_s + br_if 7 (;@9;) + local.get 19 + i32.load8_u + i32.eqz + br_if 7 (;@9;) + br 13 (;@3;) + end + local.get 5 + i32.load offset=56 + local.set 20 + local.get 24 + br_if 1 (;@14;) + i32.const 0 + local.set 19 + br 2 (;@13;) + end + local.get 5 + i32.const 0 + i32.store offset=12 + local.get 5 + local.get 5 + i64.load offset=56 + i64.store32 offset=8 + local.get 5 + local.get 5 + i32.const 8 + i32.add + i32.store offset=56 + local.get 5 + i32.const 8 + i32.add + local.set 20 + i32.const -1 + local.set 24 + end + i32.const 0 + local.set 19 + local.get 20 + local.set 21 + block ;; label = @14 + loop ;; label = @15 + local.get 21 + i32.load + local.tee 22 + i32.eqz + br_if 1 (;@14;) + block ;; label = @16 + local.get 5 + i32.const 4 + i32.add + local.get 22 + call $wctomb + local.tee 22 + i32.const 0 + i32.lt_s + local.tee 25 + br_if 0 (;@16;) + local.get 22 + local.get 24 + local.get 19 + i32.sub + i32.gt_u + br_if 0 (;@16;) + local.get 21 + i32.const 4 + i32.add + local.set 21 + local.get 24 + local.get 22 + local.get 19 + i32.add + local.tee 19 + i32.gt_u + br_if 1 (;@15;) + br 2 (;@14;) + end + end + local.get 25 + br_if 12 (;@2;) + end + local.get 19 + i32.const 0 + i32.lt_s + br_if 10 (;@3;) + end + block ;; label = @13 + local.get 30 + i32.const 73728 + i32.and + local.tee 25 + br_if 0 (;@13;) + local.get 26 + local.get 19 + i32.le_s + br_if 0 (;@13;) + local.get 5 + i32.const 112 + i32.add + i32.const 32 + local.get 26 + local.get 19 + i32.sub + local.tee 21 + i32.const 256 + local.get 21 + i32.const 256 + i32.lt_u + local.tee 22 + select + call $memset + drop + block ;; label = @14 + local.get 22 + br_if 0 (;@14;) + loop ;; label = @15 + block ;; label = @16 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@16;) + local.get 5 + i32.const 112 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 21 + i32.const -256 + i32.add + local.tee 21 + i32.const 255 + i32.gt_u + br_if 0 (;@15;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@13;) + local.get 5 + i32.const 112 + i32.add + local.get 21 + local.get 0 + call $__fwritex + drop + end + block ;; label = @13 + local.get 19 + i32.eqz + br_if 0 (;@13;) + i32.const 0 + local.set 21 + loop ;; label = @14 + local.get 20 + i32.load + local.tee 22 + i32.eqz + br_if 1 (;@13;) + local.get 5 + i32.const 4 + i32.add + local.get 22 + call $wctomb + local.tee 22 + local.get 21 + i32.add + local.tee 21 + local.get 19 + i32.gt_u + br_if 1 (;@13;) + block ;; label = @15 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@15;) + local.get 5 + i32.const 4 + i32.add + local.get 22 + local.get 0 + call $__fwritex + drop + end + local.get 20 + i32.const 4 + i32.add + local.set 20 + local.get 21 + local.get 19 + i32.lt_u + br_if 0 (;@14;) + end + end + block ;; label = @13 + local.get 25 + i32.const 8192 + i32.ne + br_if 0 (;@13;) + local.get 26 + local.get 19 + i32.le_s + br_if 0 (;@13;) + local.get 5 + i32.const 112 + i32.add + i32.const 32 + local.get 26 + local.get 19 + i32.sub + local.tee 21 + i32.const 256 + local.get 21 + i32.const 256 + i32.lt_u + local.tee 22 + select + call $memset + drop + block ;; label = @14 + local.get 22 + br_if 0 (;@14;) + loop ;; label = @15 + block ;; label = @16 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@16;) + local.get 5 + i32.const 112 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 21 + i32.const -256 + i32.add + local.tee 21 + i32.const 255 + i32.gt_u + br_if 0 (;@15;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@13;) + local.get 5 + i32.const 112 + i32.add + local.get 21 + local.get 0 + call $__fwritex + drop + end + local.get 26 + local.get 19 + local.get 26 + local.get 19 + i32.gt_s + select + local.set 19 + br 8 (;@4;) + end + block ;; label = @12 + local.get 27 + i32.eqz + br_if 0 (;@12;) + local.get 24 + i32.const 0 + i32.lt_s + br_if 9 (;@3;) + end + local.get 5 + f64.load offset=56 + local.set 34 + local.get 5 + i32.const 0 + i32.store offset=108 + block ;; label = @12 + block ;; label = @13 + local.get 34 + i64.reinterpret_f64 + i64.const -1 + i64.gt_s + br_if 0 (;@13;) + local.get 34 + f64.neg + local.set 34 + i32.const 1 + local.set 35 + i32.const 0 + local.set 36 + i32.const 1034 + local.set 37 + br 1 (;@12;) + end + block ;; label = @13 + local.get 30 + i32.const 2048 + i32.and + i32.eqz + br_if 0 (;@13;) + i32.const 1 + local.set 35 + i32.const 0 + local.set 36 + i32.const 1037 + local.set 37 + br 1 (;@12;) + end + i32.const 1040 + i32.const 1035 + local.get 30 + i32.const 1 + i32.and + local.tee 35 + select + local.set 37 + local.get 35 + i32.eqz + local.set 36 + end + block ;; label = @12 + local.get 34 + f64.abs + f64.const inf (;=inf;) + f64.lt + br_if 0 (;@12;) + local.get 35 + i32.const 3 + i32.add + local.set 21 + block ;; label = @13 + local.get 30 + i32.const 8192 + i32.and + br_if 0 (;@13;) + local.get 26 + local.get 21 + i32.le_s + br_if 0 (;@13;) + local.get 5 + i32.const 624 + i32.add + i32.const 32 + local.get 26 + local.get 21 + i32.sub + local.tee 19 + i32.const 256 + local.get 19 + i32.const 256 + i32.lt_u + local.tee 22 + select + call $memset + drop + block ;; label = @14 + local.get 22 + br_if 0 (;@14;) + loop ;; label = @15 + block ;; label = @16 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@16;) + local.get 5 + i32.const 624 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const -256 + i32.add + local.tee 19 + i32.const 255 + i32.gt_u + br_if 0 (;@15;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@13;) + local.get 5 + i32.const 624 + i32.add + local.get 19 + local.get 0 + call $__fwritex + drop + end + block ;; label = @13 + local.get 0 + i32.load + local.tee 19 + i32.const 32 + i32.and + br_if 0 (;@13;) + local.get 37 + local.get 35 + local.get 0 + call $__fwritex + drop + local.get 0 + i32.load + local.set 19 + end + block ;; label = @13 + local.get 19 + i32.const 32 + i32.and + br_if 0 (;@13;) + i32.const 1053 + i32.const 1061 + local.get 31 + i32.const 32 + i32.and + local.tee 19 + select + i32.const 1057 + i32.const 1065 + local.get 19 + select + local.get 34 + local.get 34 + f64.ne + select + i32.const 3 + local.get 0 + call $__fwritex + drop + end + block ;; label = @13 + local.get 30 + i32.const 73728 + i32.and + i32.const 8192 + i32.ne + br_if 0 (;@13;) + local.get 26 + local.get 21 + i32.le_s + br_if 0 (;@13;) + local.get 5 + i32.const 624 + i32.add + i32.const 32 + local.get 26 + local.get 21 + i32.sub + local.tee 19 + i32.const 256 + local.get 19 + i32.const 256 + i32.lt_u + local.tee 22 + select + call $memset + drop + block ;; label = @14 + local.get 22 + br_if 0 (;@14;) + loop ;; label = @15 + block ;; label = @16 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@16;) + local.get 5 + i32.const 624 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const -256 + i32.add + local.tee 19 + i32.const 255 + i32.gt_u + br_if 0 (;@15;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@13;) + local.get 5 + i32.const 624 + i32.add + local.get 19 + local.get 0 + call $__fwritex + drop + end + local.get 21 + local.get 26 + local.get 21 + local.get 26 + i32.gt_s + select + local.set 19 + br 8 (;@4;) + end + block ;; label = @12 + block ;; label = @13 + block ;; label = @14 + local.get 34 + local.get 5 + i32.const 108 + i32.add + call $frexp + local.tee 34 + local.get 34 + f64.add + local.tee 34 + f64.const 0x0p+0 (;=0;) + f64.eq + br_if 0 (;@14;) + local.get 5 + local.get 5 + i32.load offset=108 + local.tee 19 + i32.const -1 + i32.add + i32.store offset=108 + local.get 31 + i32.const 32 + i32.or + local.tee 38 + i32.const 97 + i32.ne + br_if 1 (;@13;) + br 8 (;@6;) + end + local.get 31 + i32.const 32 + i32.or + local.tee 38 + i32.const 97 + i32.eq + br_if 7 (;@6;) + i32.const 6 + local.get 24 + local.get 24 + i32.const 0 + i32.lt_s + select + local.set 27 + local.get 5 + i32.load offset=108 + local.set 20 + br 1 (;@12;) + end + local.get 5 + local.get 19 + i32.const -29 + i32.add + local.tee 20 + i32.store offset=108 + i32.const 6 + local.get 24 + local.get 24 + i32.const 0 + i32.lt_s + select + local.set 27 + local.get 34 + f64.const 0x1p+28 (;=2.68435e+08;) + f64.mul + local.set 34 + end + local.get 5 + i32.const 112 + i32.add + i32.const 0 + i32.const 72 + local.get 20 + i32.const 0 + i32.lt_s + local.tee 39 + select + i32.const 2 + i32.shl + local.tee 40 + i32.add + local.tee 23 + local.set 21 + loop ;; label = @12 + block ;; label = @13 + block ;; label = @14 + local.get 34 + f64.const 0x1p+32 (;=4.29497e+09;) + f64.lt + local.get 34 + f64.const 0x0p+0 (;=0;) + f64.ge + i32.and + i32.eqz + br_if 0 (;@14;) + local.get 34 + i32.trunc_f64_u + local.set 19 + br 1 (;@13;) + end + i32.const 0 + local.set 19 + end + local.get 21 + local.get 19 + i32.store + local.get 21 + i32.const 4 + i32.add + local.set 21 + local.get 34 + local.get 19 + f64.convert_i32_u + f64.sub + f64.const 0x1.dcd65p+29 (;=1e+09;) + f64.mul + local.tee 34 + f64.const 0x0p+0 (;=0;) + f64.ne + br_if 0 (;@12;) + end + block ;; label = @12 + block ;; label = @13 + local.get 20 + i32.const 1 + i32.ge_s + br_if 0 (;@13;) + local.get 21 + local.set 19 + local.get 23 + local.set 22 + br 1 (;@12;) + end + local.get 23 + local.set 22 + loop ;; label = @13 + local.get 20 + i32.const 29 + local.get 20 + i32.const 29 + i32.lt_s + select + local.set 20 + block ;; label = @14 + local.get 21 + i32.const -4 + i32.add + local.tee 19 + local.get 22 + i32.lt_u + br_if 0 (;@14;) + local.get 20 + i64.extend_i32_u + local.set 33 + i64.const 0 + local.set 32 + loop ;; label = @15 + local.get 19 + local.get 19 + i64.load32_u + local.get 33 + i64.shl + local.get 32 + i64.const 4294967295 + i64.and + i64.add + local.tee 32 + local.get 32 + i64.const 1000000000 + i64.div_u + local.tee 32 + i64.const 1000000000 + i64.mul + i64.sub + i64.store32 + local.get 19 + i32.const -4 + i32.add + local.tee 19 + local.get 22 + i32.ge_u + br_if 0 (;@15;) + end + local.get 32 + i32.wrap_i64 + local.tee 19 + i32.eqz + br_if 0 (;@14;) + local.get 22 + i32.const -4 + i32.add + local.tee 22 + local.get 19 + i32.store + end + block ;; label = @14 + loop ;; label = @15 + local.get 21 + local.tee 19 + local.get 22 + i32.le_u + br_if 1 (;@14;) + local.get 19 + i32.const -4 + i32.add + local.tee 21 + i32.load + i32.eqz + br_if 0 (;@15;) + end + end + local.get 5 + local.get 5 + i32.load offset=108 + local.get 20 + i32.sub + local.tee 20 + i32.store offset=108 + local.get 19 + local.set 21 + local.get 20 + i32.const 0 + i32.gt_s + br_if 0 (;@13;) + end + end + block ;; label = @12 + local.get 20 + i32.const -1 + i32.gt_s + br_if 0 (;@12;) + local.get 27 + i32.const 25 + i32.add + i32.const 9 + i32.div_u + i32.const 1 + i32.add + local.set 41 + loop ;; label = @13 + i32.const 0 + local.get 20 + i32.sub + local.tee 21 + i32.const 9 + local.get 21 + i32.const 9 + i32.lt_s + select + local.set 24 + block ;; label = @14 + block ;; label = @15 + local.get 22 + local.get 19 + i32.lt_u + br_if 0 (;@15;) + local.get 22 + i32.load + local.set 21 + br 1 (;@14;) + end + i32.const 1000000000 + local.get 24 + i32.shr_u + local.set 29 + i32.const -1 + local.get 24 + i32.shl + i32.const -1 + i32.xor + local.set 28 + i32.const 0 + local.set 20 + local.get 22 + local.set 21 + loop ;; label = @15 + local.get 21 + local.get 21 + i32.load + local.tee 25 + local.get 24 + i32.shr_u + local.get 20 + i32.add + i32.store + local.get 25 + local.get 28 + i32.and + local.get 29 + i32.mul + local.set 20 + local.get 21 + i32.const 4 + i32.add + local.tee 21 + local.get 19 + i32.lt_u + br_if 0 (;@15;) + end + local.get 22 + i32.load + local.set 21 + local.get 20 + i32.eqz + br_if 0 (;@14;) + local.get 19 + local.get 20 + i32.store + local.get 19 + i32.const 4 + i32.add + local.set 19 + end + local.get 5 + local.get 5 + i32.load offset=108 + local.get 24 + i32.add + local.tee 20 + i32.store offset=108 + local.get 23 + local.get 22 + local.get 21 + i32.eqz + i32.const 2 + i32.shl + i32.add + local.tee 22 + local.get 38 + i32.const 102 + i32.eq + select + local.tee 21 + local.get 41 + i32.const 2 + i32.shl + i32.add + local.get 19 + local.get 19 + local.get 21 + i32.sub + i32.const 2 + i32.shr_s + local.get 41 + i32.gt_s + select + local.set 19 + local.get 20 + i32.const 0 + i32.lt_s + br_if 0 (;@13;) + end + end + i32.const 0 + local.set 25 + block ;; label = @12 + local.get 22 + local.get 19 + i32.ge_u + br_if 0 (;@12;) + local.get 23 + local.get 22 + i32.sub + i32.const 2 + i32.shr_s + i32.const 9 + i32.mul + local.set 25 + local.get 22 + i32.load + local.tee 20 + i32.const 10 + i32.lt_u + br_if 0 (;@12;) + i32.const 10 + local.set 21 + loop ;; label = @13 + local.get 25 + i32.const 1 + i32.add + local.set 25 + local.get 20 + local.get 21 + i32.const 10 + i32.mul + local.tee 21 + i32.ge_u + br_if 0 (;@13;) + end + end + block ;; label = @12 + local.get 27 + i32.const 0 + local.get 25 + local.get 38 + i32.const 102 + i32.eq + select + i32.sub + local.get 27 + i32.const 0 + i32.ne + local.get 38 + i32.const 103 + i32.eq + local.tee 28 + i32.and + i32.sub + local.tee 21 + local.get 19 + local.get 23 + i32.sub + i32.const 2 + i32.shr_s + i32.const 9 + i32.mul + i32.const -9 + i32.add + i32.ge_s + br_if 0 (;@12;) + local.get 21 + i32.const 9216 + i32.add + local.tee 20 + i32.const 9 + i32.div_s + local.tee 24 + i32.const 2 + i32.shl + local.tee 42 + local.get 5 + i32.const 112 + i32.add + i32.const 1 + i32.const 73 + local.get 39 + select + i32.const 2 + i32.shl + local.tee 39 + i32.add + i32.add + i32.const -4096 + i32.add + local.set 29 + i32.const 10 + local.set 21 + block ;; label = @13 + local.get 20 + local.get 24 + i32.const 9 + i32.mul + i32.sub + local.tee 24 + i32.const 7 + i32.gt_s + br_if 0 (;@13;) + i32.const 8 + local.get 24 + i32.sub + local.tee 41 + i32.const 7 + i32.and + local.set 20 + i32.const 10 + local.set 21 + block ;; label = @14 + local.get 24 + i32.const -1 + i32.add + i32.const 7 + i32.lt_u + br_if 0 (;@14;) + local.get 41 + i32.const -8 + i32.and + local.set 24 + i32.const 10 + local.set 21 + loop ;; label = @15 + local.get 21 + i32.const 100000000 + i32.mul + local.set 21 + local.get 24 + i32.const -8 + i32.add + local.tee 24 + br_if 0 (;@15;) + end + end + local.get 20 + i32.eqz + br_if 0 (;@13;) + loop ;; label = @14 + local.get 21 + i32.const 10 + i32.mul + local.set 21 + local.get 20 + i32.const -1 + i32.add + local.tee 20 + br_if 0 (;@14;) + end + end + local.get 29 + i32.const 4 + i32.add + local.set 41 + block ;; label = @13 + block ;; label = @14 + local.get 29 + i32.load + local.tee 20 + local.get 20 + local.get 21 + i32.div_u + local.tee 38 + local.get 21 + i32.mul + i32.sub + local.tee 24 + br_if 0 (;@14;) + local.get 41 + local.get 19 + i32.eq + br_if 1 (;@13;) + end + block ;; label = @14 + block ;; label = @15 + local.get 38 + i32.const 1 + i32.and + br_if 0 (;@15;) + f64.const 0x1p+53 (;=9.0072e+15;) + local.set 34 + local.get 21 + i32.const 1000000000 + i32.ne + br_if 1 (;@14;) + local.get 29 + local.get 22 + i32.le_u + br_if 1 (;@14;) + local.get 29 + i32.const -4 + i32.add + i32.load8_u + i32.const 1 + i32.and + i32.eqz + br_if 1 (;@14;) + end + f64.const 0x1.0000000000001p+53 (;=9.0072e+15;) + local.set 34 + end + f64.const 0x1p-1 (;=0.5;) + f64.const 0x1p+0 (;=1;) + f64.const 0x1.8p+0 (;=1.5;) + local.get 41 + local.get 19 + i32.eq + select + f64.const 0x1.8p+0 (;=1.5;) + local.get 24 + local.get 21 + i32.const 1 + i32.shr_u + local.tee 41 + i32.eq + select + local.get 24 + local.get 41 + i32.lt_u + select + local.set 43 + block ;; label = @14 + local.get 36 + br_if 0 (;@14;) + local.get 37 + i32.load8_u + i32.const 45 + i32.ne + br_if 0 (;@14;) + local.get 43 + f64.neg + local.set 43 + local.get 34 + f64.neg + local.set 34 + end + local.get 29 + local.get 20 + local.get 24 + i32.sub + local.tee 20 + i32.store + local.get 34 + local.get 43 + f64.add + local.get 34 + f64.eq + br_if 0 (;@13;) + local.get 29 + local.get 20 + local.get 21 + i32.add + local.tee 21 + i32.store + block ;; label = @14 + local.get 21 + i32.const 1000000000 + i32.lt_u + br_if 0 (;@14;) + local.get 8 + local.get 39 + local.get 42 + i32.add + i32.add + local.set 21 + loop ;; label = @15 + local.get 21 + i32.const 4 + i32.add + i32.const 0 + i32.store + block ;; label = @16 + local.get 21 + local.get 22 + i32.ge_u + br_if 0 (;@16;) + local.get 22 + i32.const -4 + i32.add + local.tee 22 + i32.const 0 + i32.store + end + local.get 21 + local.get 21 + i32.load + i32.const 1 + i32.add + local.tee 20 + i32.store + local.get 21 + i32.const -4 + i32.add + local.set 21 + local.get 20 + i32.const 999999999 + i32.gt_u + br_if 0 (;@15;) + end + local.get 21 + i32.const 4 + i32.add + local.set 29 + end + local.get 23 + local.get 22 + i32.sub + i32.const 2 + i32.shr_s + i32.const 9 + i32.mul + local.set 25 + local.get 22 + i32.load + local.tee 20 + i32.const 10 + i32.lt_u + br_if 0 (;@13;) + i32.const 10 + local.set 21 + loop ;; label = @14 + local.get 25 + i32.const 1 + i32.add + local.set 25 + local.get 20 + local.get 21 + i32.const 10 + i32.mul + local.tee 21 + i32.ge_u + br_if 0 (;@14;) + end + end + local.get 29 + i32.const 4 + i32.add + local.tee 21 + local.get 19 + local.get 19 + local.get 21 + i32.gt_u + select + local.set 19 + end + local.get 7 + local.get 19 + i32.add + local.get 40 + i32.sub + local.set 21 + block ;; label = @12 + loop ;; label = @13 + local.get 21 + local.set 20 + local.get 19 + local.tee 29 + local.get 22 + i32.le_u + local.tee 24 + br_if 1 (;@12;) + local.get 20 + i32.const -4 + i32.add + local.set 21 + local.get 29 + i32.const -4 + i32.add + local.tee 19 + i32.load + i32.eqz + br_if 0 (;@13;) + end + end + block ;; label = @12 + block ;; label = @13 + local.get 28 + br_if 0 (;@13;) + local.get 30 + i32.const 8 + i32.and + local.set 41 + br 1 (;@12;) + end + local.get 25 + i32.const -1 + i32.xor + i32.const -1 + local.get 27 + i32.const 1 + local.get 27 + select + local.tee 19 + local.get 25 + i32.gt_s + local.get 25 + i32.const -5 + i32.gt_s + i32.and + local.tee 21 + select + local.get 19 + i32.add + local.set 27 + i32.const -1 + i32.const -2 + local.get 21 + select + local.get 31 + i32.add + local.set 31 + local.get 30 + i32.const 8 + i32.and + local.tee 41 + br_if 0 (;@12;) + i32.const -9 + local.set 19 + block ;; label = @13 + local.get 24 + br_if 0 (;@13;) + local.get 29 + i32.const -4 + i32.add + i32.load + local.tee 24 + i32.eqz + br_if 0 (;@13;) + i32.const 0 + local.set 19 + local.get 24 + i32.const 10 + i32.rem_u + br_if 0 (;@13;) + i32.const 10 + local.set 21 + i32.const 0 + local.set 19 + loop ;; label = @14 + local.get 19 + i32.const -1 + i32.add + local.set 19 + local.get 24 + local.get 21 + i32.const 10 + i32.mul + local.tee 21 + i32.rem_u + i32.eqz + br_if 0 (;@14;) + end + end + local.get 20 + i32.const 2 + i32.shr_s + i32.const 9 + i32.mul + i32.const -9 + i32.add + local.set 21 + block ;; label = @13 + local.get 31 + i32.const -33 + i32.and + i32.const 70 + i32.ne + br_if 0 (;@13;) + i32.const 0 + local.set 41 + local.get 27 + local.get 21 + local.get 19 + i32.add + local.tee 19 + i32.const 0 + local.get 19 + i32.const 0 + i32.gt_s + select + local.tee 19 + local.get 27 + local.get 19 + i32.lt_s + select + local.set 27 + br 1 (;@12;) + end + i32.const 0 + local.set 41 + local.get 27 + local.get 21 + local.get 25 + i32.add + local.get 19 + i32.add + local.tee 19 + i32.const 0 + local.get 19 + i32.const 0 + i32.gt_s + select + local.tee 19 + local.get 27 + local.get 19 + i32.lt_s + select + local.set 27 + end + local.get 27 + i32.const 2147483645 + i32.const 2147483646 + local.get 27 + local.get 41 + i32.or + local.tee 36 + select + i32.gt_s + br_if 8 (;@3;) + local.get 27 + local.get 36 + i32.const 0 + i32.ne + i32.add + i32.const 1 + i32.add + local.set 38 + block ;; label = @12 + block ;; label = @13 + local.get 31 + i32.const -33 + i32.and + i32.const 70 + i32.ne + local.tee 39 + br_if 0 (;@13;) + local.get 25 + local.get 38 + i32.const 2147483647 + i32.xor + i32.gt_s + br_if 10 (;@3;) + local.get 25 + i32.const 0 + local.get 25 + i32.const 0 + i32.gt_s + select + local.set 19 + br 1 (;@12;) + end + block ;; label = @13 + block ;; label = @14 + local.get 25 + br_if 0 (;@14;) + local.get 6 + local.set 20 + local.get 6 + local.set 21 + br 1 (;@13;) + end + local.get 25 + local.get 25 + i32.const 31 + i32.shr_s + local.tee 19 + i32.xor + local.get 19 + i32.sub + local.set 19 + local.get 6 + local.set 20 + local.get 6 + local.set 21 + loop ;; label = @14 + local.get 21 + i32.const -1 + i32.add + local.tee 21 + local.get 19 + local.get 19 + i32.const 10 + i32.div_u + local.tee 24 + i32.const 10 + i32.mul + i32.sub + i32.const 48 + i32.or + i32.store8 + local.get 20 + i32.const -1 + i32.add + local.set 20 + local.get 19 + i32.const 9 + i32.gt_u + local.set 28 + local.get 24 + local.set 19 + local.get 28 + br_if 0 (;@14;) + end + end + block ;; label = @13 + local.get 6 + local.get 20 + i32.sub + i32.const 1 + i32.gt_s + br_if 0 (;@13;) + local.get 21 + local.get 15 + local.get 20 + i32.sub + i32.add + local.tee 21 + i32.const 48 + local.get 14 + local.get 20 + i32.add + call $memset + drop + end + local.get 21 + i32.const -2 + i32.add + local.tee 40 + local.get 31 + i32.store8 + local.get 21 + i32.const -1 + i32.add + i32.const 45 + i32.const 43 + local.get 25 + i32.const 0 + i32.lt_s + select + i32.store8 + local.get 6 + local.get 40 + i32.sub + local.tee 19 + local.get 38 + i32.const 2147483647 + i32.xor + i32.gt_s + br_if 9 (;@3;) + end + local.get 19 + local.get 38 + i32.add + local.tee 19 + local.get 35 + i32.const 2147483647 + i32.xor + i32.gt_s + br_if 8 (;@3;) + local.get 19 + local.get 35 + i32.add + local.set 28 + block ;; label = @12 + local.get 30 + i32.const 73728 + i32.and + local.tee 30 + br_if 0 (;@12;) + local.get 26 + local.get 28 + i32.le_s + br_if 0 (;@12;) + local.get 5 + i32.const 624 + i32.add + i32.const 32 + local.get 26 + local.get 28 + i32.sub + local.tee 19 + i32.const 256 + local.get 19 + i32.const 256 + i32.lt_u + local.tee 21 + select + call $memset + drop + block ;; label = @13 + local.get 21 + br_if 0 (;@13;) + loop ;; label = @14 + block ;; label = @15 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@15;) + local.get 5 + i32.const 624 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const -256 + i32.add + local.tee 19 + i32.const 255 + i32.gt_u + br_if 0 (;@14;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@12;) + local.get 5 + i32.const 624 + i32.add + local.get 19 + local.get 0 + call $__fwritex + drop + end + block ;; label = @12 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@12;) + local.get 37 + local.get 35 + local.get 0 + call $__fwritex + drop + end + block ;; label = @12 + local.get 30 + i32.const 65536 + i32.ne + br_if 0 (;@12;) + local.get 26 + local.get 28 + i32.le_s + br_if 0 (;@12;) + local.get 5 + i32.const 624 + i32.add + i32.const 48 + local.get 26 + local.get 28 + i32.sub + local.tee 19 + i32.const 256 + local.get 19 + i32.const 256 + i32.lt_u + local.tee 21 + select + call $memset + drop + block ;; label = @13 + local.get 21 + br_if 0 (;@13;) + loop ;; label = @14 + block ;; label = @15 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@15;) + local.get 5 + i32.const 624 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const -256 + i32.add + local.tee 19 + i32.const 255 + i32.gt_u + br_if 0 (;@14;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@12;) + local.get 5 + i32.const 624 + i32.add + local.get 19 + local.get 0 + call $__fwritex + drop + end + local.get 39 + br_if 3 (;@8;) + local.get 23 + local.get 22 + local.get 22 + local.get 23 + i32.gt_u + select + local.tee 25 + local.set 24 + loop ;; label = @12 + block ;; label = @13 + block ;; label = @14 + block ;; label = @15 + block ;; label = @16 + local.get 24 + i32.load + local.tee 19 + i32.eqz + br_if 0 (;@16;) + i32.const 8 + local.set 21 + loop ;; label = @17 + local.get 5 + i32.const 80 + i32.add + local.get 21 + i32.add + local.get 19 + local.get 19 + i32.const 10 + i32.div_u + local.tee 22 + i32.const 10 + i32.mul + i32.sub + i32.const 48 + i32.or + i32.store8 + local.get 21 + i32.const -1 + i32.add + local.set 21 + local.get 19 + i32.const 9 + i32.gt_u + local.set 20 + local.get 22 + local.set 19 + local.get 20 + br_if 0 (;@17;) + end + local.get 21 + i32.const 1 + i32.add + local.tee 22 + local.get 5 + i32.const 80 + i32.add + i32.add + local.set 19 + block ;; label = @17 + local.get 24 + local.get 25 + i32.eq + br_if 0 (;@17;) + local.get 21 + i32.const 2 + i32.add + i32.const 2 + i32.lt_s + br_if 4 (;@13;) + br 3 (;@14;) + end + local.get 21 + i32.const 8 + i32.ne + br_if 3 (;@13;) + br 1 (;@15;) + end + i32.const 9 + local.set 22 + local.get 24 + local.get 25 + i32.ne + br_if 1 (;@14;) + end + local.get 5 + i32.const 48 + i32.store8 offset=88 + local.get 12 + local.set 19 + br 1 (;@13;) + end + local.get 5 + i32.const 80 + i32.add + local.get 22 + local.get 5 + i32.const 80 + i32.add + i32.add + local.tee 21 + i32.const -1 + i32.add + local.tee 19 + local.get 5 + i32.const 80 + i32.add + local.get 19 + i32.lt_u + select + local.tee 19 + i32.const 48 + local.get 21 + local.get 19 + i32.sub + call $memset + drop + end + block ;; label = @13 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@13;) + local.get 19 + local.get 13 + local.get 19 + i32.sub + local.get 0 + call $__fwritex + drop + end + local.get 24 + i32.const 4 + i32.add + local.tee 24 + local.get 23 + i32.le_u + br_if 0 (;@12;) + end + block ;; label = @12 + local.get 36 + i32.eqz + br_if 0 (;@12;) + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@12;) + i32.const 1069 + i32.const 1 + local.get 0 + call $__fwritex + drop + end + block ;; label = @12 + block ;; label = @13 + local.get 24 + local.get 29 + i32.lt_u + br_if 0 (;@13;) + local.get 27 + local.set 19 + br 1 (;@12;) + end + block ;; label = @13 + local.get 27 + i32.const 1 + i32.ge_s + br_if 0 (;@13;) + local.get 27 + local.set 19 + br 1 (;@12;) + end + loop ;; label = @13 + block ;; label = @14 + block ;; label = @15 + block ;; label = @16 + local.get 24 + i32.load + local.tee 19 + br_if 0 (;@16;) + local.get 13 + local.set 21 + local.get 13 + local.set 22 + br 1 (;@15;) + end + local.get 13 + local.set 22 + local.get 13 + local.set 21 + loop ;; label = @16 + local.get 21 + i32.const -1 + i32.add + local.tee 21 + local.get 19 + local.get 19 + i32.const 10 + i32.div_u + local.tee 20 + i32.const 10 + i32.mul + i32.sub + i32.const 48 + i32.or + i32.store8 + local.get 22 + i32.const -1 + i32.add + local.set 22 + local.get 19 + i32.const 9 + i32.gt_u + local.set 25 + local.get 20 + local.set 19 + local.get 25 + br_if 0 (;@16;) + end + local.get 21 + local.get 5 + i32.const 80 + i32.add + i32.le_u + br_if 1 (;@14;) + end + local.get 21 + local.get 5 + i32.const 80 + i32.add + i32.add + local.get 22 + i32.sub + local.tee 21 + i32.const 48 + local.get 22 + local.get 5 + i32.const 80 + i32.add + i32.sub + call $memset + drop + end + block ;; label = @14 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@14;) + local.get 21 + local.get 27 + i32.const 9 + local.get 27 + i32.const 9 + i32.lt_s + select + local.get 0 + call $__fwritex + drop + end + local.get 27 + i32.const -9 + i32.add + local.set 19 + local.get 24 + i32.const 4 + i32.add + local.tee 24 + local.get 29 + i32.ge_u + br_if 1 (;@12;) + local.get 27 + i32.const 9 + i32.gt_s + local.set 21 + local.get 19 + local.set 27 + local.get 21 + br_if 0 (;@13;) + end + end + local.get 0 + i32.const 48 + local.get 19 + i32.const 9 + i32.add + i32.const 9 + i32.const 0 + call $pad + br 4 (;@7;) + end + i32.const 4228 + i32.const 28 + i32.store + br 8 (;@2;) + end + i32.const 0 + local.set 28 + i32.const 1024 + local.set 23 + local.get 16 + local.set 19 + local.get 30 + local.set 29 + local.get 24 + local.set 25 + end + local.get 25 + local.get 19 + local.get 20 + i32.sub + local.tee 24 + local.get 25 + local.get 24 + i32.gt_s + select + local.tee 27 + local.get 28 + i32.const 2147483647 + i32.xor + i32.gt_s + br_if 5 (;@3;) + local.get 26 + local.get 28 + local.get 27 + i32.add + local.tee 22 + local.get 26 + local.get 22 + i32.gt_s + select + local.tee 19 + local.get 21 + i32.gt_s + br_if 5 (;@3;) + block ;; label = @9 + local.get 29 + i32.const 73728 + i32.and + local.tee 29 + br_if 0 (;@9;) + local.get 22 + local.get 26 + i32.ge_s + br_if 0 (;@9;) + local.get 5 + i32.const 112 + i32.add + i32.const 32 + local.get 19 + local.get 22 + i32.sub + local.tee 21 + i32.const 256 + local.get 21 + i32.const 256 + i32.lt_u + local.tee 30 + select + call $memset + drop + block ;; label = @10 + local.get 30 + br_if 0 (;@10;) + loop ;; label = @11 + block ;; label = @12 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@12;) + local.get 5 + i32.const 112 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 21 + i32.const -256 + i32.add + local.tee 21 + i32.const 255 + i32.gt_u + br_if 0 (;@11;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@9;) + local.get 5 + i32.const 112 + i32.add + local.get 21 + local.get 0 + call $__fwritex + drop + end + block ;; label = @9 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@9;) + local.get 23 + local.get 28 + local.get 0 + call $__fwritex + drop + end + block ;; label = @9 + local.get 29 + i32.const 65536 + i32.ne + br_if 0 (;@9;) + local.get 22 + local.get 26 + i32.ge_s + br_if 0 (;@9;) + local.get 5 + i32.const 112 + i32.add + i32.const 48 + local.get 19 + local.get 22 + i32.sub + local.tee 21 + i32.const 256 + local.get 21 + i32.const 256 + i32.lt_u + local.tee 28 + select + call $memset + drop + block ;; label = @10 + local.get 28 + br_if 0 (;@10;) + loop ;; label = @11 + block ;; label = @12 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@12;) + local.get 5 + i32.const 112 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 21 + i32.const -256 + i32.add + local.tee 21 + i32.const 255 + i32.gt_u + br_if 0 (;@11;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@9;) + local.get 5 + i32.const 112 + i32.add + local.get 21 + local.get 0 + call $__fwritex + drop + end + block ;; label = @9 + local.get 24 + local.get 25 + i32.ge_s + br_if 0 (;@9;) + local.get 5 + i32.const 112 + i32.add + i32.const 48 + local.get 27 + local.get 24 + i32.sub + local.tee 21 + i32.const 256 + local.get 21 + i32.const 256 + i32.lt_u + local.tee 25 + select + call $memset + drop + block ;; label = @10 + local.get 25 + br_if 0 (;@10;) + loop ;; label = @11 + block ;; label = @12 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@12;) + local.get 5 + i32.const 112 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 21 + i32.const -256 + i32.add + local.tee 21 + i32.const 255 + i32.gt_u + br_if 0 (;@11;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@9;) + local.get 5 + i32.const 112 + i32.add + local.get 21 + local.get 0 + call $__fwritex + drop + end + block ;; label = @9 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@9;) + local.get 20 + local.get 24 + local.get 0 + call $__fwritex + drop + end + local.get 29 + i32.const 8192 + i32.ne + br_if 4 (;@4;) + local.get 22 + local.get 26 + i32.ge_s + br_if 4 (;@4;) + local.get 5 + i32.const 112 + i32.add + i32.const 32 + local.get 19 + local.get 22 + i32.sub + local.tee 21 + i32.const 256 + local.get 21 + i32.const 256 + i32.lt_u + local.tee 22 + select + call $memset + drop + block ;; label = @9 + local.get 22 + br_if 0 (;@9;) + loop ;; label = @10 + block ;; label = @11 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@11;) + local.get 5 + i32.const 112 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 21 + i32.const -256 + i32.add + local.tee 21 + i32.const 255 + i32.gt_u + br_if 0 (;@10;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 4 (;@4;) + local.get 5 + i32.const 112 + i32.add + local.get 21 + local.get 0 + call $__fwritex + drop + br 4 (;@4;) + end + block ;; label = @8 + local.get 27 + i32.const 0 + i32.lt_s + br_if 0 (;@8;) + local.get 29 + local.get 22 + i32.const 4 + i32.add + local.get 29 + local.get 22 + i32.gt_u + select + local.set 29 + local.get 22 + local.set 24 + loop ;; label = @9 + block ;; label = @10 + block ;; label = @11 + local.get 24 + i32.load + local.tee 19 + i32.eqz + br_if 0 (;@11;) + i32.const 0 + local.set 21 + loop ;; label = @12 + local.get 5 + i32.const 80 + i32.add + local.get 21 + i32.add + i32.const 8 + i32.add + local.get 19 + local.get 19 + i32.const 10 + i32.div_u + local.tee 20 + i32.const 10 + i32.mul + i32.sub + i32.const 48 + i32.or + i32.store8 + local.get 21 + i32.const -1 + i32.add + local.set 21 + local.get 19 + i32.const 9 + i32.gt_u + local.set 25 + local.get 20 + local.set 19 + local.get 25 + br_if 0 (;@12;) + end + local.get 21 + i32.eqz + br_if 0 (;@11;) + local.get 5 + i32.const 80 + i32.add + local.get 21 + i32.add + i32.const 9 + i32.add + local.set 19 + br 1 (;@10;) + end + local.get 5 + i32.const 48 + i32.store8 offset=88 + local.get 12 + local.set 19 + end + block ;; label = @10 + block ;; label = @11 + local.get 24 + local.get 22 + i32.eq + br_if 0 (;@11;) + local.get 19 + local.get 5 + i32.const 80 + i32.add + i32.le_u + br_if 1 (;@10;) + local.get 5 + i32.const 80 + i32.add + i32.const 48 + local.get 19 + local.get 5 + i32.const 80 + i32.add + i32.sub + call $memset + drop + local.get 5 + i32.const 80 + i32.add + local.set 19 + br 1 (;@10;) + end + block ;; label = @11 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@11;) + local.get 19 + i32.const 1 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const 1 + i32.add + local.set 19 + block ;; label = @11 + local.get 41 + br_if 0 (;@11;) + local.get 27 + i32.const 1 + i32.lt_s + br_if 1 (;@10;) + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@10;) + i32.const 1069 + i32.const 1 + local.get 0 + call $__fwritex + drop + end + local.get 13 + local.get 19 + i32.sub + local.set 21 + block ;; label = @10 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@10;) + local.get 19 + local.get 27 + local.get 21 + local.get 27 + local.get 21 + i32.lt_s + select + local.get 0 + call $__fwritex + drop + end + local.get 27 + local.get 21 + i32.sub + local.set 27 + local.get 24 + i32.const 4 + i32.add + local.tee 24 + local.get 29 + i32.ge_u + br_if 1 (;@8;) + local.get 27 + i32.const -1 + i32.gt_s + br_if 0 (;@9;) + end + end + local.get 0 + i32.const 48 + local.get 27 + i32.const 18 + i32.add + i32.const 18 + i32.const 0 + call $pad + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@7;) + local.get 40 + local.get 6 + local.get 40 + i32.sub + local.get 0 + call $__fwritex + drop + end + local.get 30 + i32.const 8192 + i32.ne + br_if 1 (;@5;) + local.get 26 + local.get 28 + i32.le_s + br_if 1 (;@5;) + local.get 5 + i32.const 624 + i32.add + i32.const 32 + local.get 26 + local.get 28 + i32.sub + local.tee 19 + i32.const 256 + local.get 19 + i32.const 256 + i32.lt_u + local.tee 21 + select + call $memset + drop + block ;; label = @7 + local.get 21 + br_if 0 (;@7;) + loop ;; label = @8 + block ;; label = @9 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@9;) + local.get 5 + i32.const 624 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const -256 + i32.add + local.tee 19 + i32.const 255 + i32.gt_u + br_if 0 (;@8;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 1 (;@5;) + local.get 5 + i32.const 624 + i32.add + local.get 19 + local.get 0 + call $__fwritex + drop + br 1 (;@5;) + end + local.get 37 + local.get 31 + i32.const 26 + i32.shl + i32.const 31 + i32.shr_s + i32.const 9 + i32.and + i32.add + local.set 23 + block ;; label = @6 + local.get 24 + i32.const 11 + i32.gt_u + br_if 0 (;@6;) + block ;; label = @7 + block ;; label = @8 + i32.const 12 + local.get 24 + i32.sub + local.tee 19 + i32.const 7 + i32.and + local.tee 21 + br_if 0 (;@8;) + f64.const 0x1p+4 (;=16;) + local.set 43 + br 1 (;@7;) + end + local.get 24 + i32.const -12 + i32.add + local.set 19 + f64.const 0x1p+4 (;=16;) + local.set 43 + loop ;; label = @8 + local.get 19 + i32.const 1 + i32.add + local.set 19 + local.get 43 + f64.const 0x1p+4 (;=16;) + f64.mul + local.set 43 + local.get 21 + i32.const -1 + i32.add + local.tee 21 + br_if 0 (;@8;) + end + i32.const 0 + local.get 19 + i32.sub + local.set 19 + end + block ;; label = @7 + local.get 24 + i32.const -5 + i32.add + i32.const 7 + i32.lt_u + br_if 0 (;@7;) + loop ;; label = @8 + local.get 43 + f64.const 0x1p+4 (;=16;) + f64.mul + f64.const 0x1p+4 (;=16;) + f64.mul + f64.const 0x1p+4 (;=16;) + f64.mul + f64.const 0x1p+4 (;=16;) + f64.mul + f64.const 0x1p+4 (;=16;) + f64.mul + f64.const 0x1p+4 (;=16;) + f64.mul + f64.const 0x1p+4 (;=16;) + f64.mul + f64.const 0x1p+4 (;=16;) + f64.mul + local.set 43 + local.get 19 + i32.const -8 + i32.add + local.tee 19 + br_if 0 (;@8;) + end + end + block ;; label = @7 + local.get 23 + i32.load8_u + i32.const 45 + i32.ne + br_if 0 (;@7;) + local.get 43 + local.get 34 + f64.neg + local.get 43 + f64.sub + f64.add + f64.neg + local.set 34 + br 1 (;@6;) + end + local.get 34 + local.get 43 + f64.add + local.get 43 + f64.sub + local.set 34 + end + block ;; label = @6 + block ;; label = @7 + local.get 5 + i32.load offset=108 + local.tee 25 + i32.eqz + br_if 0 (;@7;) + local.get 25 + local.get 25 + i32.const 31 + i32.shr_s + local.tee 19 + i32.xor + local.get 19 + i32.sub + local.set 19 + i32.const 0 + local.set 21 + loop ;; label = @8 + local.get 5 + i32.const 68 + i32.add + local.get 21 + i32.add + i32.const 11 + i32.add + local.get 19 + local.get 19 + i32.const 10 + i32.div_u + local.tee 22 + i32.const 10 + i32.mul + i32.sub + i32.const 48 + i32.or + i32.store8 + local.get 21 + i32.const -1 + i32.add + local.set 21 + local.get 19 + i32.const 9 + i32.gt_u + local.set 20 + local.get 22 + local.set 19 + local.get 20 + br_if 0 (;@8;) + end + local.get 21 + i32.eqz + br_if 0 (;@7;) + local.get 5 + i32.const 68 + i32.add + local.get 21 + i32.add + i32.const 12 + i32.add + local.set 19 + br 1 (;@6;) + end + local.get 5 + i32.const 48 + i32.store8 offset=79 + local.get 11 + local.set 19 + end + local.get 35 + i32.const 2 + i32.or + local.set 27 + local.get 31 + i32.const 32 + i32.and + local.set 22 + local.get 19 + i32.const -2 + i32.add + local.tee 29 + local.get 31 + i32.const 15 + i32.add + i32.store8 + local.get 19 + i32.const -1 + i32.add + i32.const 45 + i32.const 43 + local.get 25 + i32.const 0 + i32.lt_s + select + i32.store8 + local.get 30 + i32.const 8 + i32.and + local.set 20 + local.get 5 + i32.const 80 + i32.add + local.set 21 + loop ;; label = @6 + local.get 21 + local.set 19 + block ;; label = @7 + block ;; label = @8 + local.get 34 + f64.abs + f64.const 0x1p+31 (;=2.14748e+09;) + f64.lt + i32.eqz + br_if 0 (;@8;) + local.get 34 + i32.trunc_f64_s + local.set 21 + br 1 (;@7;) + end + i32.const -2147483648 + local.set 21 + end + local.get 19 + local.get 21 + i32.const 3472 + i32.add + i32.load8_u + local.get 22 + i32.or + i32.store8 + local.get 34 + local.get 21 + f64.convert_i32_s + f64.sub + f64.const 0x1p+4 (;=16;) + f64.mul + local.set 34 + block ;; label = @7 + local.get 19 + i32.const 1 + i32.add + local.tee 21 + local.get 5 + i32.const 80 + i32.add + i32.sub + i32.const 1 + i32.ne + br_if 0 (;@7;) + block ;; label = @8 + local.get 20 + br_if 0 (;@8;) + local.get 24 + i32.const 0 + i32.gt_s + br_if 0 (;@8;) + local.get 34 + f64.const 0x0p+0 (;=0;) + f64.eq + br_if 1 (;@7;) + end + local.get 19 + i32.const 46 + i32.store8 offset=1 + local.get 19 + i32.const 2 + i32.add + local.set 21 + end + local.get 34 + f64.const 0x0p+0 (;=0;) + f64.ne + br_if 0 (;@6;) + end + i32.const 2147483645 + local.get 6 + local.get 29 + i32.sub + local.tee 25 + local.get 27 + i32.add + local.tee 19 + i32.sub + local.get 24 + i32.lt_s + br_if 2 (;@3;) + local.get 24 + i32.const 2 + i32.add + local.get 21 + local.get 5 + i32.const 80 + i32.add + i32.sub + local.tee 22 + local.get 10 + local.get 21 + i32.add + local.get 24 + i32.lt_s + select + local.get 22 + local.get 24 + select + local.tee 20 + local.get 19 + i32.add + local.set 28 + block ;; label = @6 + local.get 30 + i32.const 73728 + i32.and + local.tee 21 + br_if 0 (;@6;) + local.get 26 + local.get 28 + i32.le_s + br_if 0 (;@6;) + local.get 5 + i32.const 624 + i32.add + i32.const 32 + local.get 26 + local.get 28 + i32.sub + local.tee 19 + i32.const 256 + local.get 19 + i32.const 256 + i32.lt_u + local.tee 24 + select + call $memset + drop + block ;; label = @7 + local.get 24 + br_if 0 (;@7;) + loop ;; label = @8 + block ;; label = @9 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@9;) + local.get 5 + i32.const 624 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const -256 + i32.add + local.tee 19 + i32.const 255 + i32.gt_u + br_if 0 (;@8;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@6;) + local.get 5 + i32.const 624 + i32.add + local.get 19 + local.get 0 + call $__fwritex + drop + end + block ;; label = @6 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@6;) + local.get 23 + local.get 27 + local.get 0 + call $__fwritex + drop + end + block ;; label = @6 + local.get 21 + i32.const 65536 + i32.ne + br_if 0 (;@6;) + local.get 26 + local.get 28 + i32.le_s + br_if 0 (;@6;) + local.get 5 + i32.const 624 + i32.add + i32.const 48 + local.get 26 + local.get 28 + i32.sub + local.tee 19 + i32.const 256 + local.get 19 + i32.const 256 + i32.lt_u + local.tee 24 + select + call $memset + drop + block ;; label = @7 + local.get 24 + br_if 0 (;@7;) + loop ;; label = @8 + block ;; label = @9 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@9;) + local.get 5 + i32.const 624 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const -256 + i32.add + local.tee 19 + i32.const 255 + i32.gt_u + br_if 0 (;@8;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@6;) + local.get 5 + i32.const 624 + i32.add + local.get 19 + local.get 0 + call $__fwritex + drop + end + block ;; label = @6 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@6;) + local.get 5 + i32.const 80 + i32.add + local.get 22 + local.get 0 + call $__fwritex + drop + end + block ;; label = @6 + local.get 20 + local.get 22 + i32.sub + local.tee 19 + i32.const 1 + i32.lt_s + br_if 0 (;@6;) + local.get 5 + i32.const 624 + i32.add + i32.const 48 + local.get 19 + i32.const 256 + local.get 19 + i32.const 256 + i32.lt_u + local.tee 22 + select + call $memset + drop + block ;; label = @7 + local.get 22 + br_if 0 (;@7;) + loop ;; label = @8 + block ;; label = @9 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@9;) + local.get 5 + i32.const 624 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const -256 + i32.add + local.tee 19 + i32.const 255 + i32.gt_u + br_if 0 (;@8;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@6;) + local.get 5 + i32.const 624 + i32.add + local.get 19 + local.get 0 + call $__fwritex + drop + end + block ;; label = @6 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@6;) + local.get 29 + local.get 25 + local.get 0 + call $__fwritex + drop + end + local.get 21 + i32.const 8192 + i32.ne + br_if 0 (;@5;) + local.get 26 + local.get 28 + i32.le_s + br_if 0 (;@5;) + local.get 5 + i32.const 624 + i32.add + i32.const 32 + local.get 26 + local.get 28 + i32.sub + local.tee 19 + i32.const 256 + local.get 19 + i32.const 256 + i32.lt_u + local.tee 21 + select + call $memset + drop + block ;; label = @6 + local.get 21 + br_if 0 (;@6;) + loop ;; label = @7 + block ;; label = @8 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@8;) + local.get 5 + i32.const 624 + i32.add + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 19 + i32.const -256 + i32.add + local.tee 19 + i32.const 255 + i32.gt_u + br_if 0 (;@7;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@5;) + local.get 5 + i32.const 624 + i32.add + local.get 19 + local.get 0 + call $__fwritex + drop + end + local.get 28 + local.get 26 + local.get 28 + local.get 26 + i32.gt_s + select + local.tee 19 + i32.const 0 + i32.ge_s + br_if 0 (;@4;) + end + end + i32.const 4228 + i32.const 61 + i32.store + end + i32.const -1 + local.set 18 + end + local.get 5 + i32.const 880 + i32.add + global.set $__stack_pointer + local.get 18) + (func $pop_arg (type 11) (param i32 i32 i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + block ;; label = @6 + block ;; label = @7 + block ;; label = @8 + block ;; label = @9 + block ;; label = @10 + block ;; label = @11 + block ;; label = @12 + block ;; label = @13 + block ;; label = @14 + block ;; label = @15 + block ;; label = @16 + block ;; label = @17 + block ;; label = @18 + block ;; label = @19 + local.get 1 + i32.const -9 + i32.add + br_table 17 (;@2;) 0 (;@19;) 1 (;@18;) 4 (;@15;) 2 (;@17;) 3 (;@16;) 5 (;@14;) 6 (;@13;) 7 (;@12;) 8 (;@11;) 9 (;@10;) 10 (;@9;) 11 (;@8;) 12 (;@7;) 13 (;@6;) 14 (;@5;) 15 (;@4;) 16 (;@3;) 18 (;@1;) + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load32_s + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load32_u + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load32_s + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load32_u + i64.store + return + end + local.get 2 + local.get 2 + i32.load + i32.const 7 + i32.add + i32.const -8 + i32.and + local.tee 1 + i32.const 8 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load16_s + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load16_u + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load8_s + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load8_u + i64.store + return + end + local.get 2 + local.get 2 + i32.load + i32.const 7 + i32.add + i32.const -8 + i32.and + local.tee 1 + i32.const 8 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load32_u + i64.store + return + end + local.get 2 + local.get 2 + i32.load + i32.const 7 + i32.add + i32.const -8 + i32.and + local.tee 1 + i32.const 8 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load + i64.store + return + end + local.get 2 + local.get 2 + i32.load + i32.const 7 + i32.add + i32.const -8 + i32.and + local.tee 1 + i32.const 8 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load32_s + i64.store + return + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i64.load32_u + i64.store + return + end + local.get 2 + local.get 2 + i32.load + i32.const 7 + i32.add + i32.const -8 + i32.and + local.tee 1 + i32.const 8 + i32.add + i32.store + local.get 0 + local.get 1 + f64.load + f64.store + return + end + call $long_double_not_supported + unreachable + end + local.get 2 + local.get 2 + i32.load + local.tee 1 + i32.const 4 + i32.add + i32.store + local.get 0 + local.get 1 + i32.load + i32.store + end) + (func $pad (type 12) (param i32 i32 i32 i32 i32) + (local i32) + global.get $__stack_pointer + i32.const 256 + i32.sub + local.tee 5 + global.set $__stack_pointer + block ;; label = @1 + local.get 2 + local.get 3 + i32.le_s + br_if 0 (;@1;) + local.get 4 + i32.const 73728 + i32.and + br_if 0 (;@1;) + local.get 5 + local.get 1 + local.get 2 + local.get 3 + i32.sub + local.tee 3 + i32.const 256 + local.get 3 + i32.const 256 + i32.lt_u + local.tee 4 + select + call $memset + local.set 2 + block ;; label = @2 + local.get 4 + br_if 0 (;@2;) + loop ;; label = @3 + block ;; label = @4 + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@4;) + local.get 2 + i32.const 256 + local.get 0 + call $__fwritex + drop + end + local.get 3 + i32.const -256 + i32.add + local.tee 3 + i32.const 255 + i32.gt_u + br_if 0 (;@3;) + end + end + local.get 0 + i32.load8_u + i32.const 32 + i32.and + br_if 0 (;@1;) + local.get 2 + local.get 3 + local.get 0 + call $__fwritex + drop + end + local.get 5 + i32.const 256 + i32.add + global.set $__stack_pointer) + (func $long_double_not_supported (type 7) + i32.const 1160 + i32.const 3608 + call $fputs + drop + call $abort + unreachable) + (func $memcpy (type 0) (param i32 i32 i32) (result i32) + (local i32 i32 i32 i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 2 + i32.const 32 + i32.gt_u + br_if 0 (;@3;) + local.get 1 + i32.const 3 + i32.and + i32.eqz + br_if 1 (;@2;) + local.get 2 + i32.eqz + br_if 1 (;@2;) + local.get 0 + local.get 1 + i32.load8_u + i32.store8 + local.get 2 + i32.const -1 + i32.add + local.set 3 + local.get 0 + i32.const 1 + i32.add + local.set 4 + local.get 1 + i32.const 1 + i32.add + local.tee 5 + i32.const 3 + i32.and + i32.eqz + br_if 2 (;@1;) + local.get 3 + i32.eqz + br_if 2 (;@1;) + local.get 0 + local.get 1 + i32.load8_u offset=1 + i32.store8 offset=1 + local.get 2 + i32.const -2 + i32.add + local.set 3 + local.get 0 + i32.const 2 + i32.add + local.set 4 + local.get 1 + i32.const 2 + i32.add + local.tee 5 + i32.const 3 + i32.and + i32.eqz + br_if 2 (;@1;) + local.get 3 + i32.eqz + br_if 2 (;@1;) + local.get 0 + local.get 1 + i32.load8_u offset=2 + i32.store8 offset=2 + local.get 2 + i32.const -3 + i32.add + local.set 3 + local.get 0 + i32.const 3 + i32.add + local.set 4 + local.get 1 + i32.const 3 + i32.add + local.tee 5 + i32.const 3 + i32.and + i32.eqz + br_if 2 (;@1;) + local.get 3 + i32.eqz + br_if 2 (;@1;) + local.get 0 + local.get 1 + i32.load8_u offset=3 + i32.store8 offset=3 + local.get 2 + i32.const -4 + i32.add + local.set 3 + local.get 0 + i32.const 4 + i32.add + local.set 4 + local.get 1 + i32.const 4 + i32.add + local.set 5 + br 2 (;@1;) + end + local.get 0 + local.get 1 + local.get 2 + memory.copy + local.get 0 + return + end + local.get 2 + local.set 3 + local.get 0 + local.set 4 + local.get 1 + local.set 5 + end + block ;; label = @1 + block ;; label = @2 + local.get 4 + i32.const 3 + i32.and + local.tee 2 + br_if 0 (;@2;) + block ;; label = @3 + block ;; label = @4 + local.get 3 + i32.const 16 + i32.ge_u + br_if 0 (;@4;) + local.get 3 + local.set 2 + br 1 (;@3;) + end + block ;; label = @4 + local.get 3 + i32.const -16 + i32.add + local.tee 2 + i32.const 16 + i32.and + br_if 0 (;@4;) + local.get 4 + local.get 5 + i64.load align=4 + i64.store align=4 + local.get 4 + local.get 5 + i64.load offset=8 align=4 + i64.store offset=8 align=4 + local.get 4 + i32.const 16 + i32.add + local.set 4 + local.get 5 + i32.const 16 + i32.add + local.set 5 + local.get 2 + local.set 3 + end + local.get 2 + i32.const 16 + i32.lt_u + br_if 0 (;@3;) + local.get 3 + local.set 2 + loop ;; label = @4 + local.get 4 + local.get 5 + i64.load align=4 + i64.store align=4 + local.get 4 + local.get 5 + i64.load offset=8 align=4 + i64.store offset=8 align=4 + local.get 4 + local.get 5 + i64.load offset=16 align=4 + i64.store offset=16 align=4 + local.get 4 + local.get 5 + i64.load offset=24 align=4 + i64.store offset=24 align=4 + local.get 4 + i32.const 32 + i32.add + local.set 4 + local.get 5 + i32.const 32 + i32.add + local.set 5 + local.get 2 + i32.const -32 + i32.add + local.tee 2 + i32.const 15 + i32.gt_u + br_if 0 (;@4;) + end + end + block ;; label = @3 + local.get 2 + i32.const 8 + i32.lt_u + br_if 0 (;@3;) + local.get 4 + local.get 5 + i64.load align=4 + i64.store align=4 + local.get 5 + i32.const 8 + i32.add + local.set 5 + local.get 4 + i32.const 8 + i32.add + local.set 4 + end + block ;; label = @3 + local.get 2 + i32.const 4 + i32.and + i32.eqz + br_if 0 (;@3;) + local.get 4 + local.get 5 + i32.load + i32.store + local.get 5 + i32.const 4 + i32.add + local.set 5 + local.get 4 + i32.const 4 + i32.add + local.set 4 + end + block ;; label = @3 + local.get 2 + i32.const 2 + i32.and + i32.eqz + br_if 0 (;@3;) + local.get 4 + local.get 5 + i32.load16_u align=1 + i32.store16 align=1 + local.get 4 + i32.const 2 + i32.add + local.set 4 + local.get 5 + i32.const 2 + i32.add + local.set 5 + end + local.get 2 + i32.const 1 + i32.and + i32.eqz + br_if 1 (;@1;) + local.get 4 + local.get 5 + i32.load8_u + i32.store8 + local.get 0 + return + end + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + block ;; label = @6 + local.get 3 + i32.const 32 + i32.lt_u + br_if 0 (;@6;) + block ;; label = @7 + block ;; label = @8 + local.get 2 + i32.const -1 + i32.add + br_table 3 (;@5;) 0 (;@8;) 1 (;@7;) 7 (;@1;) + end + local.get 4 + local.get 5 + i32.load + i32.store16 align=1 + local.get 4 + local.get 5 + i32.const 2 + i32.add + i32.load align=2 + i32.store offset=2 + local.get 4 + local.get 5 + i32.const 6 + i32.add + i64.load align=2 + i64.store offset=6 align=4 + local.get 4 + i32.const 18 + i32.add + local.set 2 + local.get 5 + i32.const 18 + i32.add + local.set 1 + i32.const 14 + local.set 6 + local.get 5 + i32.const 14 + i32.add + i32.load align=2 + local.set 5 + i32.const 14 + local.set 3 + br 3 (;@4;) + end + local.get 4 + local.get 5 + i32.load + i32.store8 + local.get 4 + local.get 5 + i32.const 1 + i32.add + i32.load align=1 + i32.store offset=1 + local.get 4 + local.get 5 + i32.const 5 + i32.add + i64.load align=1 + i64.store offset=5 align=4 + local.get 4 + i32.const 17 + i32.add + local.set 2 + local.get 5 + i32.const 17 + i32.add + local.set 1 + i32.const 13 + local.set 6 + local.get 5 + i32.const 13 + i32.add + i32.load align=1 + local.set 5 + i32.const 15 + local.set 3 + br 2 (;@4;) + end + block ;; label = @6 + block ;; label = @7 + local.get 3 + i32.const 16 + i32.ge_u + br_if 0 (;@7;) + local.get 4 + local.set 2 + local.get 5 + local.set 1 + br 1 (;@6;) + end + local.get 4 + local.get 5 + i32.load8_u + i32.store8 + local.get 4 + local.get 5 + i32.load offset=1 align=1 + i32.store offset=1 align=1 + local.get 4 + local.get 5 + i64.load offset=5 align=1 + i64.store offset=5 align=1 + local.get 4 + local.get 5 + i32.load16_u offset=13 align=1 + i32.store16 offset=13 align=1 + local.get 4 + local.get 5 + i32.load8_u offset=15 + i32.store8 offset=15 + local.get 4 + i32.const 16 + i32.add + local.set 2 + local.get 5 + i32.const 16 + i32.add + local.set 1 + end + local.get 3 + i32.const 8 + i32.and + br_if 2 (;@3;) + br 3 (;@2;) + end + local.get 4 + local.get 5 + i32.load + local.tee 2 + i32.store8 + local.get 4 + local.get 2 + i32.const 16 + i32.shr_u + i32.store8 offset=2 + local.get 4 + local.get 2 + i32.const 8 + i32.shr_u + i32.store8 offset=1 + local.get 4 + local.get 5 + i32.const 3 + i32.add + i32.load align=1 + i32.store offset=3 + local.get 4 + local.get 5 + i32.const 7 + i32.add + i64.load align=1 + i64.store offset=7 align=4 + local.get 4 + i32.const 19 + i32.add + local.set 2 + local.get 5 + i32.const 19 + i32.add + local.set 1 + i32.const 15 + local.set 6 + local.get 5 + i32.const 15 + i32.add + i32.load align=1 + local.set 5 + i32.const 13 + local.set 3 + end + local.get 4 + local.get 6 + i32.add + local.get 5 + i32.store + end + local.get 2 + local.get 1 + i64.load align=1 + i64.store align=1 + local.get 2 + i32.const 8 + i32.add + local.set 2 + local.get 1 + i32.const 8 + i32.add + local.set 1 + end + block ;; label = @2 + local.get 3 + i32.const 4 + i32.and + i32.eqz + br_if 0 (;@2;) + local.get 2 + local.get 1 + i32.load align=1 + i32.store align=1 + local.get 2 + i32.const 4 + i32.add + local.set 2 + local.get 1 + i32.const 4 + i32.add + local.set 1 + end + block ;; label = @2 + local.get 3 + i32.const 2 + i32.and + i32.eqz + br_if 0 (;@2;) + local.get 2 + local.get 1 + i32.load16_u align=1 + i32.store16 align=1 + local.get 2 + i32.const 2 + i32.add + local.set 2 + local.get 1 + i32.const 2 + i32.add + local.set 1 + end + local.get 3 + i32.const 1 + i32.and + i32.eqz + br_if 0 (;@1;) + local.get 2 + local.get 1 + i32.load8_u + i32.store8 + end + local.get 0) + (func $memset (type 0) (param i32 i32 i32) (result i32) + (local i32 i32 i32 i64) + block ;; label = @1 + local.get 2 + i32.const 33 + i32.lt_u + br_if 0 (;@1;) + local.get 0 + local.get 1 + local.get 2 + memory.fill + local.get 0 + return + end + block ;; label = @1 + local.get 2 + i32.eqz + br_if 0 (;@1;) + local.get 0 + local.get 1 + i32.store8 + local.get 2 + local.get 0 + i32.add + local.tee 3 + i32.const -1 + i32.add + local.get 1 + i32.store8 + local.get 2 + i32.const 3 + i32.lt_u + br_if 0 (;@1;) + local.get 0 + local.get 1 + i32.store8 offset=2 + local.get 0 + local.get 1 + i32.store8 offset=1 + local.get 3 + i32.const -3 + i32.add + local.get 1 + i32.store8 + local.get 3 + i32.const -2 + i32.add + local.get 1 + i32.store8 + local.get 2 + i32.const 7 + i32.lt_u + br_if 0 (;@1;) + local.get 0 + local.get 1 + i32.store8 offset=3 + local.get 3 + i32.const -4 + i32.add + local.get 1 + i32.store8 + local.get 2 + i32.const 9 + i32.lt_u + br_if 0 (;@1;) + local.get 0 + i32.const 0 + local.get 0 + i32.sub + i32.const 3 + i32.and + local.tee 4 + i32.add + local.tee 5 + local.get 1 + i32.const 255 + i32.and + i32.const 16843009 + i32.mul + local.tee 3 + i32.store + local.get 5 + local.get 2 + local.get 4 + i32.sub + i32.const -4 + i32.and + local.tee 1 + i32.add + local.tee 2 + i32.const -4 + i32.add + local.get 3 + i32.store + local.get 1 + i32.const 9 + i32.lt_u + br_if 0 (;@1;) + local.get 5 + local.get 3 + i32.store offset=8 + local.get 5 + local.get 3 + i32.store offset=4 + local.get 2 + i32.const -8 + i32.add + local.get 3 + i32.store + local.get 2 + i32.const -12 + i32.add + local.get 3 + i32.store + local.get 1 + i32.const 25 + i32.lt_u + br_if 0 (;@1;) + local.get 5 + local.get 3 + i32.store offset=24 + local.get 5 + local.get 3 + i32.store offset=20 + local.get 5 + local.get 3 + i32.store offset=16 + local.get 5 + local.get 3 + i32.store offset=12 + local.get 2 + i32.const -16 + i32.add + local.get 3 + i32.store + local.get 2 + i32.const -20 + i32.add + local.get 3 + i32.store + local.get 2 + i32.const -24 + i32.add + local.get 3 + i32.store + local.get 2 + i32.const -28 + i32.add + local.get 3 + i32.store + local.get 1 + local.get 5 + i32.const 4 + i32.and + i32.const 24 + i32.or + local.tee 2 + i32.sub + local.tee 1 + i32.const 32 + i32.lt_u + br_if 0 (;@1;) + local.get 3 + i64.extend_i32_u + i64.const 4294967297 + i64.mul + local.set 6 + local.get 5 + local.get 2 + i32.add + local.set 2 + loop ;; label = @2 + local.get 2 + local.get 6 + i64.store offset=24 + local.get 2 + local.get 6 + i64.store offset=16 + local.get 2 + local.get 6 + i64.store offset=8 + local.get 2 + local.get 6 + i64.store + local.get 2 + i32.const 32 + i32.add + local.set 2 + local.get 1 + i32.const -32 + i32.add + local.tee 1 + i32.const 31 + i32.gt_u + br_if 0 (;@2;) + end + end + local.get 0) + (func $strlen (type 2) (param i32) (result i32) + (local i32 i32) + local.get 0 + local.set 1 + block ;; label = @1 + block ;; label = @2 + local.get 0 + i32.const 3 + i32.and + i32.eqz + br_if 0 (;@2;) + local.get 0 + local.set 1 + local.get 0 + i32.load8_u + i32.eqz + br_if 1 (;@1;) + local.get 0 + i32.const 1 + i32.add + local.tee 1 + i32.const 3 + i32.and + i32.eqz + br_if 0 (;@2;) + local.get 1 + i32.load8_u + i32.eqz + br_if 1 (;@1;) + local.get 0 + i32.const 2 + i32.add + local.tee 1 + i32.const 3 + i32.and + i32.eqz + br_if 0 (;@2;) + local.get 1 + i32.load8_u + i32.eqz + br_if 1 (;@1;) + local.get 0 + i32.const 3 + i32.add + local.tee 1 + i32.const 3 + i32.and + i32.eqz + br_if 0 (;@2;) + local.get 1 + i32.load8_u + i32.eqz + br_if 1 (;@1;) + local.get 0 + i32.const 4 + i32.add + local.set 1 + end + local.get 1 + i32.const -5 + i32.add + local.set 1 + loop ;; label = @2 + local.get 1 + i32.const 5 + i32.add + local.set 2 + local.get 1 + i32.const 4 + i32.add + local.set 1 + local.get 2 + i32.load + local.tee 2 + i32.const -1 + i32.xor + local.get 2 + i32.const -16843009 + i32.add + i32.and + i32.const -2139062144 + i32.and + i32.eqz + br_if 0 (;@2;) + end + loop ;; label = @2 + local.get 1 + i32.const 1 + i32.add + local.tee 1 + i32.load8_u + br_if 0 (;@2;) + end + end + local.get 1 + local.get 0 + i32.sub) + (func $memchr (type 0) (param i32 i32 i32) (result i32) + (local i32 i32 i32) + local.get 2 + i32.const 0 + i32.ne + local.set 3 + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + local.get 0 + i32.const 3 + i32.and + i32.eqz + br_if 0 (;@4;) + local.get 2 + i32.eqz + br_if 0 (;@4;) + block ;; label = @5 + local.get 0 + i32.load8_u + local.get 1 + i32.const 255 + i32.and + i32.ne + br_if 0 (;@5;) + local.get 0 + local.set 4 + local.get 2 + local.set 5 + br 3 (;@2;) + end + local.get 2 + i32.const -1 + i32.add + local.tee 5 + i32.const 0 + i32.ne + local.set 3 + local.get 0 + i32.const 1 + i32.add + local.tee 4 + i32.const 3 + i32.and + i32.eqz + br_if 1 (;@3;) + local.get 5 + i32.eqz + br_if 1 (;@3;) + local.get 4 + i32.load8_u + local.get 1 + i32.const 255 + i32.and + i32.eq + br_if 2 (;@2;) + local.get 2 + i32.const -2 + i32.add + local.tee 5 + i32.const 0 + i32.ne + local.set 3 + local.get 0 + i32.const 2 + i32.add + local.tee 4 + i32.const 3 + i32.and + i32.eqz + br_if 1 (;@3;) + local.get 5 + i32.eqz + br_if 1 (;@3;) + local.get 4 + i32.load8_u + local.get 1 + i32.const 255 + i32.and + i32.eq + br_if 2 (;@2;) + local.get 2 + i32.const -3 + i32.add + local.tee 5 + i32.const 0 + i32.ne + local.set 3 + local.get 0 + i32.const 3 + i32.add + local.tee 4 + i32.const 3 + i32.and + i32.eqz + br_if 1 (;@3;) + local.get 5 + i32.eqz + br_if 1 (;@3;) + local.get 4 + i32.load8_u + local.get 1 + i32.const 255 + i32.and + i32.eq + br_if 2 (;@2;) + local.get 0 + i32.const 4 + i32.add + local.set 4 + local.get 2 + i32.const -4 + i32.add + local.tee 5 + i32.const 0 + i32.ne + local.set 3 + br 1 (;@3;) + end + local.get 2 + local.set 5 + local.get 0 + local.set 4 + end + local.get 3 + i32.eqz + br_if 1 (;@1;) + block ;; label = @3 + local.get 4 + i32.load8_u + local.get 1 + i32.const 255 + i32.and + i32.eq + br_if 0 (;@3;) + local.get 5 + i32.const 4 + i32.lt_u + br_if 0 (;@3;) + local.get 1 + i32.const 255 + i32.and + i32.const 16843009 + i32.mul + local.set 0 + loop ;; label = @4 + local.get 4 + i32.load + local.get 0 + i32.xor + local.tee 2 + i32.const -1 + i32.xor + local.get 2 + i32.const -16843009 + i32.add + i32.and + i32.const -2139062144 + i32.and + br_if 2 (;@2;) + local.get 4 + i32.const 4 + i32.add + local.set 4 + local.get 5 + i32.const -4 + i32.add + local.tee 5 + i32.const 3 + i32.gt_u + br_if 0 (;@4;) + end + end + local.get 5 + i32.eqz + br_if 1 (;@1;) + end + local.get 1 + i32.const 255 + i32.and + local.set 2 + loop ;; label = @2 + block ;; label = @3 + local.get 4 + i32.load8_u + local.get 2 + i32.ne + br_if 0 (;@3;) + local.get 4 + return + end + local.get 4 + i32.const 1 + i32.add + local.set 4 + local.get 5 + i32.const -1 + i32.add + local.tee 5 + br_if 0 (;@2;) + end + end + i32.const 0) + (func $strnlen (type 3) (param i32 i32) (result i32) + (local i32) + local.get 0 + i32.const 0 + local.get 1 + call $memchr + local.tee 2 + local.get 0 + i32.sub + local.get 1 + local.get 2 + select) + (table (;0;) 5 5 funcref) + (memory (;0;) 2) + (global $__stack_pointer (mut i32) (i32.const 70864)) + (export "memory" (memory 0)) + (export "_start" (func $_start)) + (elem (;0;) (i32.const 1) func $__stdio_write $__stdio_close $__stdout_write $__stdio_seek) + (data $.rodata (i32.const 1024) "-+ 0X0x\00-0X+0X 0X-0x+0x 0x\00nan\00inf\00NAN\00INF\00.\00(null)\00writing to pointer\0a\00malloc again %p\0a\00malloc returned %p\0a\00pointer contains %d, %d\0a\00Support for formatting long double values is currently disabled.\0aTo enable it, add -lc-printscan-long-double to the link command.\0a\00Success\00Illegal byte sequence\00Domain error\00Result not representable\00Not a tty\00Permission denied\00Operation not permitted\00No such file or directory\00No such process\00File exists\00Value too large for data type\00No space left on device\00Out of memory\00Resource busy\00Interrupted system call\00Resource temporarily unavailable\00Invalid seek\00Cross-device link\00Read-only file system\00Directory not empty\00Connection reset by peer\00Operation timed out\00Connection refused\00Host is unreachable\00Address in use\00Broken pipe\00I/O error\00No such device or address\00No such device\00Not a directory\00Is a directory\00Text file busy\00Exec format error\00Invalid argument\00Argument list too long\00Symbolic link loop\00Filename too long\00Too many open files in system\00No file descriptors available\00Bad file descriptor\00No child process\00Bad address\00File too large\00Too many links\00No locks available\00Resource deadlock would occur\00State not recoverable\00Previous owner died\00Operation canceled\00Function not implemented\00No message of desired type\00Identifier removed\00Link has been severed\00Protocol error\00Bad message\00Not a socket\00Destination address required\00Message too large\00Protocol wrong type for socket\00Protocol not available\00Protocol not supported\00Not supported\00Address family not supported by protocol\00Address not available\00Network is down\00Network unreachable\00Connection reset by network\00Connection aborted\00No buffer space available\00Socket is connected\00Socket not connected\00Operation already in progress\00Operation in progress\00Stale file handle\00Quota exceeded\00Multihop attempted\00Capabilities insufficient\00\00\00\00\00\00\00\00u\02N\00\d6\01\e2\04\b9\04\18\01\8e\05\ed\02\16\04\f2\00\97\03\01\038\05\af\01\82\01O\03/\04\1e\00\d4\05\a2\00\12\03\1e\03\c2\01\de\03\08\00\ac\05\00\01d\02\f1\01e\054\02\8c\02\cf\02-\03L\04\e3\05\9f\02\f8\04\1c\05\08\05\b1\02K\05\15\02x\00R\02<\03\f1\03\e4\00\c3\03}\04\cc\00\aa\03y\05$\02n\01m\03\22\04\ab\04D\00\fb\01\ae\00\83\03`\00\e5\01\07\04\94\04^\04+\00X\019\01\92\00\c2\05\9b\01C\02F\01\f6\05\00\00\00\00\00\00\19\00\0a\00\19\19\19\00\00\00\00\05\00\00\00\00\00\00\09\00\00\00\00\0b\00\00\00\00\00\00\00\00\19\00\11\0a\19\19\19\03\0a\07\00\01\1b\09\0b\18\00\00\09\06\0b\00\00\0b\00\06\19\00\00\00\19\19\19\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0e\00\00\00\00\00\00\00\00\19\00\0a\0d\19\19\19\00\0d\00\00\02\00\09\0e\00\00\00\09\00\0e\00\00\0e\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\13\00\00\00\00\13\00\00\00\00\09\0c\00\00\00\00\00\0c\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\10\00\00\00\00\00\00\00\00\00\00\00\0f\00\00\00\04\0f\00\00\00\00\09\10\00\00\00\00\00\10\00\00\10\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\12\00\00\00\00\00\00\00\00\00\00\00\11\00\00\00\00\11\00\00\00\00\09\12\00\00\00\00\00\12\00\00\12\00\00\1a\00\00\00\1a\1a\1a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\1a\00\00\00\1a\1a\1a\00\00\00\00\00\00\09\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\14\00\00\00\00\00\00\00\00\00\00\00\17\00\00\00\00\17\00\00\00\00\09\14\00\00\00\00\00\14\00\00\14\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\16\00\00\00\00\00\00\00\00\00\00\00\15\00\00\00\00\15\00\00\00\00\09\16\00\00\00\00\00\16\00\00\16\00\000123456789ABCDEF") + (data $.data (i32.const 3488) "\05\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\00\00\00\04\00\00\00\98\10\00\00\00\04\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\0a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\a0\0d\00\00\00\00\00\00\05\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\04\00\00\00\c4\14\00\00\00\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\ff\ff\ff\ff\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\18\0e\00\00")) diff --git a/test.wasm b/test.wasm new file mode 100644 index 0000000000000000000000000000000000000000..71ce6ad9b60bbefcaf61d1962e003b2e9621a05e GIT binary patch literal 4756 zcmcIoTW=f36`q;Bl1oY}$4*qqc4oJJklO0j*pzGMK@-3U(g5vSp9-uga%po(iWIq$ zBB1puiP5?@H0d>MS~Lav*oXEXv@dNR`p{of6etS!JG0A+APLq>bm7dLIdjf;uESkc zAN4q6jNd6eG_ow?8HOhrfAWyiTxg033av~q(8x3Pkl~MK;!oUq`KUf>N29&^VDz}3 zMuTB|*p833+*UJcbo-;2i3>QY;Ak~RX+4b|#VIo`U~|AWisKG5FJK@|N5gg+vx~5l z2E%?Mir;Og%ro?2)TE4N&;gKExJ0~Y6EMyO=Ofvt+v|ygMz|_ez zO#NRFVM#G>p0=?#Ve0vFV;>xnN$$TlrCie#DWu`Qe=hZdDb*usPiYNhH2*<97tEVu z{*P$ke?*_&E2oy={9(@N0^#?F;RAykWXFd@UlF+}#*WyLSY4%$#W%?|gyfO+zwe4XvL1g;wkCYUb}=MI(;cMx$OUt=RYIa zpAByBo5&^P1MGY~Wt53MQ!8d%7-pHMujT$2Nf!U`&4AKD#hejTwl zAkie!IQD^6;T}#qV{wS-*T87%4dPA$m-b16&LvY?Nx>jI>0%X>qydJ}YN$AX~4K3-s4WMO}jd049nkN82pbczK+E8uzzax8=Acn}$L@seiV_};K zEm9zx`7+#SNxtXZ(*E~9rIUeB88!t{9=VJf{V7r3TK4|HQ7NCt;)E%`6N+1UN-X!- zy!Hf~?uP~(n+5RM#IZyUjG|tyhH#}Wl@+mrfIjE@VZN3oEGDofNo3?=EeBZV;S37t zH~@-k8`ju7O+5fo~`|5!gXl4F)X-(y=xsb;-@r(*wWgc7&(Rck{5{tLb#f%4y z95k#nwfo@suaXRPy*LjSkTH_tV5myse_tySC~~P$2wYX(ToU(g?V*1DtjNKR_BP zxB&Ht5;c4nfMYB#T?84866z&KQ|knF1p(y9Tv~?CJE5zLGzm+xgd-rMgrvLN2_3`( zj!+e4Vm)DSIz+al-5G;Jvq1X*Psou-ZYMOySgE+sHVDkc{Xz;Vq!}05UTYdO39sZq z%kv$8+{8!T6yd)g0OJ~Sm7x5@%vZPe5iA~vykiKMGtLg!t>idyg?Ar2N?#Z?A>mF& z9pNtw$F?6ZLy0$YY484-^?}0#syWaW^2%{sv(X_fPib za*;}JWC7Qyv}(8krPMT)xW2L}{G|4`TJ48rZsYC*Sgs7+qA4{A8L*>hpgBvZ6`-5~ zR5f)pOLL;zK0qhaoG5mPR8MkFk#kbEo#7Ps7+j;iopTyFr*R&qagQO#)VFd@v}4ka zff~0I1c@lRBWnC6bcMXi^a57DO;eaZNO1f36a#edRe>9)n7P}i8x!t<9E%3@QR+qD zMvFFfX89>2Eqsj6gI%AQtQTp$INg`IR1CO@)Wak+)ciX-dr@oD62>>;6cot^w@HJU zvzR&}U_mA6D$x!A3%Mg_5o4AO#_l6tD9&6p28)d0`&C{M#B3<3ol=B5OXdv51uV`L zgf_+7L=*52DM~bRF+-s9c)`Poz7WYdjzlKlAPoX|=zEu|+!Tiv59x;2C=ozcZ$VTl z-RTzmDbNnjJ5`}A|D00@OcD?pgcJcLcWM|EKfoY#7A&2ZL+&v0q|{!ayZmD4K0)`- zg^n$Ex^)Wr=~Jhm&z?FBec=pr3Kr${Y$S}l^5{x^f!7xax_d5kY#}P+ty9oXpE?D7 z_S9+USI$5OI{mE#5gDgq(K^T&#%o9*%vPDT&5+&F+F;fDtV%On{`lU3M473%zOp-XVAZCV?Q)ijIl5tc5IT*?b-!$57Ig=w$nkkOL8KXY6b5}BgQgcV&8 zYu(Ou%cCYZZkN<2b0YfPSt457St5W!E2rK@`ABUo#O29QNZAO<|NMXdJxcb~$$RfV zeV2Sn-;dD$G1J_n9a?oa0jiE?GvD&(Jnt#T9ev_@#^W|Fo@cI?T5S3wrqjvHz|6$| z$Miw}#SbsW@|bYR(IpxGHqE_yFXn$YL-vIzYWD{HVH)F^_uS`hJW}V+-F)LxywfLe zv3jWk^ek>%4u^g!H^2B|v6JU>t9ZD!=cA}UY(Hx6)w@xz-rjRS&<2mqbFWSbQyWTi zQz`*1&m7ZeJilO=sH|Ag1H2iiTFrxA?|5!O@Aslcz1xkNX@5AHH|foRUk0L9H|q8q zorOw-cL2?HU%ykhQi`Iqucg0axAb_`Y7Gw3(KR}A7!O>s50n~ob!6m`kIn-e6odX?T$GzQ1g9;L%>ycb-{ zUsbF(`n_I#uL-!6JI)o(;1|5bXmp}MzrB~n!_tCa&ib(5tfzHut<%5`>Agwwpb-y8 zyh8qpN29p8wtLKBMSbtlH@0rCZ?3;4S01P7V03R|<54?(e6UN}HoD!z{9_FVlem$} tt=3nzZf|bZZZ})It=-Mt-Ddr6d}r&m&01W)v$c75bN9=w?Rvej`hQ*?kq7_) literal 0 HcmV?d00001 From 0bb2290166ae5dc1114b43c370dbf5e08aa93d2b Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Tue, 8 Aug 2023 10:51:39 -0700 Subject: [PATCH 22/34] removed test.wasm --- test.wasm | Bin 4756 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test.wasm diff --git a/test.wasm b/test.wasm deleted file mode 100644 index 71ce6ad9b60bbefcaf61d1962e003b2e9621a05e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4756 zcmcIoTW=f36`q;Bl1oY}$4*qqc4oJJklO0j*pzGMK@-3U(g5vSp9-uga%po(iWIq$ zBB1puiP5?@H0d>MS~Lav*oXEXv@dNR`p{of6etS!JG0A+APLq>bm7dLIdjf;uESkc zAN4q6jNd6eG_ow?8HOhrfAWyiTxg033av~q(8x3Pkl~MK;!oUq`KUf>N29&^VDz}3 zMuTB|*p833+*UJcbo-;2i3>QY;Ak~RX+4b|#VIo`U~|AWisKG5FJK@|N5gg+vx~5l z2E%?Mir;Og%ro?2)TE4N&;gKExJ0~Y6EMyO=Ofvt+v|ygMz|_ez zO#NRFVM#G>p0=?#Ve0vFV;>xnN$$TlrCie#DWu`Qe=hZdDb*usPiYNhH2*<97tEVu z{*P$ke?*_&E2oy={9(@N0^#?F;RAykWXFd@UlF+}#*WyLSY4%$#W%?|gyfO+zwe4XvL1g;wkCYUb}=MI(;cMx$OUt=RYIa zpAByBo5&^P1MGY~Wt53MQ!8d%7-pHMujT$2Nf!U`&4AKD#hejTwl zAkie!IQD^6;T}#qV{wS-*T87%4dPA$m-b16&LvY?Nx>jI>0%X>qydJ}YN$AX~4K3-s4WMO}jd049nkN82pbczK+E8uzzax8=Acn}$L@seiV_};K zEm9zx`7+#SNxtXZ(*E~9rIUeB88!t{9=VJf{V7r3TK4|HQ7NCt;)E%`6N+1UN-X!- zy!Hf~?uP~(n+5RM#IZyUjG|tyhH#}Wl@+mrfIjE@VZN3oEGDofNo3?=EeBZV;S37t zH~@-k8`ju7O+5fo~`|5!gXl4F)X-(y=xsb;-@r(*wWgc7&(Rck{5{tLb#f%4y z95k#nwfo@suaXRPy*LjSkTH_tV5myse_tySC~~P$2wYX(ToU(g?V*1DtjNKR_BP zxB&Ht5;c4nfMYB#T?84866z&KQ|knF1p(y9Tv~?CJE5zLGzm+xgd-rMgrvLN2_3`( zj!+e4Vm)DSIz+al-5G;Jvq1X*Psou-ZYMOySgE+sHVDkc{Xz;Vq!}05UTYdO39sZq z%kv$8+{8!T6yd)g0OJ~Sm7x5@%vZPe5iA~vykiKMGtLg!t>idyg?Ar2N?#Z?A>mF& z9pNtw$F?6ZLy0$YY484-^?}0#syWaW^2%{sv(X_fPib za*;}JWC7Qyv}(8krPMT)xW2L}{G|4`TJ48rZsYC*Sgs7+qA4{A8L*>hpgBvZ6`-5~ zR5f)pOLL;zK0qhaoG5mPR8MkFk#kbEo#7Ps7+j;iopTyFr*R&qagQO#)VFd@v}4ka zff~0I1c@lRBWnC6bcMXi^a57DO;eaZNO1f36a#edRe>9)n7P}i8x!t<9E%3@QR+qD zMvFFfX89>2Eqsj6gI%AQtQTp$INg`IR1CO@)Wak+)ciX-dr@oD62>>;6cot^w@HJU zvzR&}U_mA6D$x!A3%Mg_5o4AO#_l6tD9&6p28)d0`&C{M#B3<3ol=B5OXdv51uV`L zgf_+7L=*52DM~bRF+-s9c)`Poz7WYdjzlKlAPoX|=zEu|+!Tiv59x;2C=ozcZ$VTl z-RTzmDbNnjJ5`}A|D00@OcD?pgcJcLcWM|EKfoY#7A&2ZL+&v0q|{!ayZmD4K0)`- zg^n$Ex^)Wr=~Jhm&z?FBec=pr3Kr${Y$S}l^5{x^f!7xax_d5kY#}P+ty9oXpE?D7 z_S9+USI$5OI{mE#5gDgq(K^T&#%o9*%vPDT&5+&F+F;fDtV%On{`lU3M473%zOp-XVAZCV?Q)ijIl5tc5IT*?b-!$57Ig=w$nkkOL8KXY6b5}BgQgcV&8 zYu(Ou%cCYZZkN<2b0YfPSt457St5W!E2rK@`ABUo#O29QNZAO<|NMXdJxcb~$$RfV zeV2Sn-;dD$G1J_n9a?oa0jiE?GvD&(Jnt#T9ev_@#^W|Fo@cI?T5S3wrqjvHz|6$| z$Miw}#SbsW@|bYR(IpxGHqE_yFXn$YL-vIzYWD{HVH)F^_uS`hJW}V+-F)LxywfLe zv3jWk^ek>%4u^g!H^2B|v6JU>t9ZD!=cA}UY(Hx6)w@xz-rjRS&<2mqbFWSbQyWTi zQz`*1&m7ZeJilO=sH|Ag1H2iiTFrxA?|5!O@Aslcz1xkNX@5AHH|foRUk0L9H|q8q zorOw-cL2?HU%ykhQi`Iqucg0axAb_`Y7Gw3(KR}A7!O>s50n~ob!6m`kIn-e6odX?T$GzQ1g9;L%>ycb-{ zUsbF(`n_I#uL-!6JI)o(;1|5bXmp}MzrB~n!_tCa&ib(5tfzHut<%5`>Agwwpb-y8 zyh8qpN29p8wtLKBMSbtlH@0rCZ?3;4S01P7V03R|<54?(e6UN}HoD!z{9_FVlem$} tt=3nzZf|bZZZ})It=-Mt-Ddr6d}r&m&01W)v$c75bN9=w?Rvej`hQ*?kq7_) From fe3db2a59e8b5f05d6c58c23a59799067a4dcb35 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Tue, 8 Aug 2023 10:56:03 -0700 Subject: [PATCH 23/34] removed malloc_twice.wat --- malloc_twice.wat | 10465 --------------------------------------------- 1 file changed, 10465 deletions(-) delete mode 100644 malloc_twice.wat diff --git a/malloc_twice.wat b/malloc_twice.wat deleted file mode 100644 index e2e2af5273ca..000000000000 --- a/malloc_twice.wat +++ /dev/null @@ -1,10465 +0,0 @@ -(module - (type (;0;) (func (param i32 i32 i32) (result i32))) - (type (;1;) (func (param i32 i64 i32) (result i64))) - (type (;2;) (func (param i32) (result i32))) - (type (;3;) (func (param i32 i32) (result i32))) - (type (;4;) (func (param i32 i64 i32 i32) (result i32))) - (type (;5;) (func (param i32 i32 i32 i32) (result i32))) - (type (;6;) (func (param i32))) - (type (;7;) (func)) - (type (;8;) (func (result i32))) - (type (;9;) (func (param f64 i32) (result f64))) - (type (;10;) (func (param i32 i32 i32 i32 i32) (result i32))) - (type (;11;) (func (param i32 i32 i32))) - (type (;12;) (func (param i32 i32 i32 i32 i32))) - (import "wasi_snapshot_preview1" "fd_close" (func $__imported_wasi_snapshot_preview1_fd_close (type 2))) - (import "wasi_snapshot_preview1" "fd_fdstat_get" (func $__imported_wasi_snapshot_preview1_fd_fdstat_get (type 3))) - (import "wasi_snapshot_preview1" "fd_seek" (func $__imported_wasi_snapshot_preview1_fd_seek (type 4))) - (import "wasi_snapshot_preview1" "fd_write" (func $__imported_wasi_snapshot_preview1_fd_write (type 5))) - (import "wasi_snapshot_preview1" "proc_exit" (func $__imported_wasi_snapshot_preview1_proc_exit (type 6))) - (func $__wasm_call_ctors (type 7)) - (func $_start (type 7) - (local i32) - block ;; label = @1 - block ;; label = @2 - i32.const 0 - i32.load offset=3728 - br_if 0 (;@2;) - i32.const 0 - i32.const 1 - i32.store offset=3728 - call $__wasm_call_ctors - call $__original_main - local.set 0 - call $__wasm_call_dtors - local.get 0 - br_if 1 (;@1;) - return - end - unreachable - unreachable - end - local.get 0 - call $__wasi_proc_exit - unreachable) - (func $__original_main (type 8) (result i32) - (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) - global.get $__stack_pointer - local.set 0 - i32.const 48 - local.set 1 - local.get 0 - local.get 1 - i32.sub - local.set 2 - local.get 2 - global.set $__stack_pointer - i32.const 40000 - local.set 3 - local.get 3 - call $malloc - local.set 4 - local.get 2 - local.get 4 - i32.store offset=44 - local.get 2 - i32.load offset=44 - local.set 5 - local.get 2 - local.get 5 - i32.store - i32.const 1115 - local.set 6 - local.get 6 - local.get 2 - call $printf - drop - i32.const 1078 - local.set 7 - i32.const 0 - local.set 8 - local.get 7 - local.get 8 - call $printf - drop - local.get 2 - i32.load offset=44 - local.set 9 - i32.const 1 - local.set 10 - local.get 9 - local.get 10 - i32.store8 - local.get 2 - i32.load offset=44 - local.set 11 - i32.const 2 - local.set 12 - local.get 11 - local.get 12 - i32.store8 offset=1 - local.get 2 - i32.load offset=44 - local.set 13 - local.get 13 - i32.load8_u - local.set 14 - i32.const 24 - local.set 15 - local.get 14 - local.get 15 - i32.shl - local.set 16 - local.get 16 - local.get 15 - i32.shr_s - local.set 17 - local.get 2 - i32.load offset=44 - local.set 18 - local.get 18 - i32.load8_u offset=1 - local.set 19 - i32.const 24 - local.set 20 - local.get 19 - local.get 20 - i32.shl - local.set 21 - local.get 21 - local.get 20 - i32.shr_s - local.set 22 - local.get 2 - local.get 22 - i32.store offset=20 - local.get 2 - local.get 17 - i32.store offset=16 - i32.const 1135 - local.set 23 - i32.const 16 - local.set 24 - local.get 2 - local.get 24 - i32.add - local.set 25 - local.get 23 - local.get 25 - call $printf - drop - i32.const 40000 - local.set 26 - local.get 26 - call $malloc - local.set 27 - local.get 2 - local.get 27 - i32.store offset=40 - local.get 2 - i32.load offset=40 - local.set 28 - local.get 2 - local.get 28 - i32.store offset=32 - i32.const 1098 - local.set 29 - i32.const 32 - local.set 30 - local.get 2 - local.get 30 - i32.add - local.set 31 - local.get 29 - local.get 31 - call $printf - drop - i32.const 0 - local.set 32 - i32.const 48 - local.set 33 - local.get 2 - local.get 33 - i32.add - local.set 34 - local.get 34 - global.set $__stack_pointer - local.get 32 - return) - (func $malloc (type 2) (param i32) (result i32) - local.get 0 - call $dlmalloc) - (func $dlmalloc (type 2) (param i32) (result i32) - (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) - global.get $__stack_pointer - i32.const 16 - i32.sub - local.tee 1 - global.set $__stack_pointer - block ;; label = @1 - i32.const 0 - i32.load offset=3756 - local.tee 2 - br_if 0 (;@1;) - block ;; label = @2 - block ;; label = @3 - i32.const 0 - i32.load offset=4204 - local.tee 3 - i32.eqz - br_if 0 (;@3;) - i32.const 0 - i32.load offset=4208 - local.set 4 - br 1 (;@2;) - end - i32.const 0 - i64.const -1 - i64.store offset=4216 align=4 - i32.const 0 - i64.const 281474976776192 - i64.store offset=4208 align=4 - i32.const 0 - local.get 1 - i32.const 8 - i32.add - i32.const -16 - i32.and - i32.const 1431655768 - i32.xor - local.tee 3 - i32.store offset=4204 - i32.const 0 - i32.const 0 - i32.store offset=4224 - i32.const 0 - i32.const 0 - i32.store offset=4176 - i32.const 65536 - local.set 4 - end - i32.const 0 - local.set 2 - i32.const 131072 - i32.const 70864 - local.get 4 - i32.add - i32.const -1 - i32.add - i32.const 0 - local.get 4 - i32.sub - i32.and - i32.const 131072 - select - i32.const 70864 - i32.sub - local.tee 5 - i32.const 89 - i32.lt_u - br_if 0 (;@1;) - i32.const 0 - local.set 4 - i32.const 0 - local.get 5 - i32.store offset=4184 - i32.const 0 - i32.const 70864 - i32.store offset=4180 - i32.const 0 - i32.const 70864 - i32.store offset=3748 - i32.const 0 - local.get 3 - i32.store offset=3768 - i32.const 0 - i32.const -1 - i32.store offset=3764 - loop ;; label = @2 - local.get 4 - i32.const 3792 - i32.add - local.get 4 - i32.const 3780 - i32.add - local.tee 3 - i32.store - local.get 3 - local.get 4 - i32.const 3772 - i32.add - local.tee 6 - i32.store - local.get 4 - i32.const 3784 - i32.add - local.get 6 - i32.store - local.get 4 - i32.const 3800 - i32.add - local.get 4 - i32.const 3788 - i32.add - local.tee 6 - i32.store - local.get 6 - local.get 3 - i32.store - local.get 4 - i32.const 3808 - i32.add - local.get 4 - i32.const 3796 - i32.add - local.tee 3 - i32.store - local.get 3 - local.get 6 - i32.store - local.get 4 - i32.const 3804 - i32.add - local.get 3 - i32.store - local.get 4 - i32.const 32 - i32.add - local.tee 4 - i32.const 256 - i32.ne - br_if 0 (;@2;) - end - i32.const 70864 - i32.const -8 - i32.const 70864 - i32.sub - i32.const 15 - i32.and - i32.const 0 - i32.const 70864 - i32.const 8 - i32.add - i32.const 15 - i32.and - select - local.tee 4 - i32.add - local.tee 2 - i32.const 4 - i32.add - local.get 5 - i32.const -56 - i32.add - local.tee 3 - local.get 4 - i32.sub - local.tee 4 - i32.const 1 - i32.or - i32.store - i32.const 0 - i32.const 0 - i32.load offset=4220 - i32.store offset=3760 - i32.const 0 - local.get 4 - i32.store offset=3744 - i32.const 0 - local.get 2 - i32.store offset=3756 - i32.const 70864 - local.get 3 - i32.add - i32.const 56 - i32.store offset=4 - end - block ;; label = @1 - block ;; label = @2 - block ;; label = @3 - block ;; label = @4 - block ;; label = @5 - block ;; label = @6 - block ;; label = @7 - block ;; label = @8 - block ;; label = @9 - block ;; label = @10 - block ;; label = @11 - block ;; label = @12 - local.get 0 - i32.const 236 - i32.gt_u - br_if 0 (;@12;) - block ;; label = @13 - i32.const 0 - i32.load offset=3732 - local.tee 7 - i32.const 16 - local.get 0 - i32.const 19 - i32.add - i32.const -16 - i32.and - local.get 0 - i32.const 11 - i32.lt_u - select - local.tee 5 - i32.const 3 - i32.shr_u - local.tee 3 - i32.shr_u - local.tee 4 - i32.const 3 - i32.and - i32.eqz - br_if 0 (;@13;) - block ;; label = @14 - block ;; label = @15 - local.get 4 - i32.const 1 - i32.and - local.get 3 - i32.or - i32.const 1 - i32.xor - local.tee 6 - i32.const 3 - i32.shl - local.tee 3 - i32.const 3772 - i32.add - local.tee 4 - local.get 3 - i32.const 3780 - i32.add - i32.load - local.tee 3 - i32.load offset=8 - local.tee 5 - i32.ne - br_if 0 (;@15;) - i32.const 0 - local.get 7 - i32.const -2 - local.get 6 - i32.rotl - i32.and - i32.store offset=3732 - br 1 (;@14;) - end - local.get 4 - local.get 5 - i32.store offset=8 - local.get 5 - local.get 4 - i32.store offset=12 - end - local.get 3 - i32.const 8 - i32.add - local.set 4 - local.get 3 - local.get 6 - i32.const 3 - i32.shl - local.tee 6 - i32.const 3 - i32.or - i32.store offset=4 - local.get 3 - local.get 6 - i32.add - local.tee 3 - local.get 3 - i32.load offset=4 - i32.const 1 - i32.or - i32.store offset=4 - br 12 (;@1;) - end - local.get 5 - i32.const 0 - i32.load offset=3740 - local.tee 8 - i32.le_u - br_if 1 (;@11;) - block ;; label = @13 - local.get 4 - i32.eqz - br_if 0 (;@13;) - block ;; label = @14 - block ;; label = @15 - local.get 4 - local.get 3 - i32.shl - i32.const 2 - local.get 3 - i32.shl - local.tee 4 - i32.const 0 - local.get 4 - i32.sub - i32.or - i32.and - local.tee 4 - i32.const 0 - local.get 4 - i32.sub - i32.and - i32.ctz - local.tee 3 - i32.const 3 - i32.shl - local.tee 4 - i32.const 3772 - i32.add - local.tee 6 - local.get 4 - i32.const 3780 - i32.add - i32.load - local.tee 4 - i32.load offset=8 - local.tee 0 - i32.ne - br_if 0 (;@15;) - i32.const 0 - local.get 7 - i32.const -2 - local.get 3 - i32.rotl - i32.and - local.tee 7 - i32.store offset=3732 - br 1 (;@14;) - end - local.get 6 - local.get 0 - i32.store offset=8 - local.get 0 - local.get 6 - i32.store offset=12 - end - local.get 4 - local.get 5 - i32.const 3 - i32.or - i32.store offset=4 - local.get 4 - local.get 3 - i32.const 3 - i32.shl - local.tee 3 - i32.add - local.get 3 - local.get 5 - i32.sub - local.tee 6 - i32.store - local.get 4 - local.get 5 - i32.add - local.tee 0 - local.get 6 - i32.const 1 - i32.or - i32.store offset=4 - block ;; label = @14 - local.get 8 - i32.eqz - br_if 0 (;@14;) - local.get 8 - i32.const -8 - i32.and - i32.const 3772 - i32.add - local.set 5 - i32.const 0 - i32.load offset=3752 - local.set 3 - block ;; label = @15 - block ;; label = @16 - local.get 7 - i32.const 1 - local.get 8 - i32.const 3 - i32.shr_u - i32.shl - local.tee 9 - i32.and - br_if 0 (;@16;) - i32.const 0 - local.get 7 - local.get 9 - i32.or - i32.store offset=3732 - local.get 5 - local.set 9 - br 1 (;@15;) - end - local.get 5 - i32.load offset=8 - local.set 9 - end - local.get 9 - local.get 3 - i32.store offset=12 - local.get 5 - local.get 3 - i32.store offset=8 - local.get 3 - local.get 5 - i32.store offset=12 - local.get 3 - local.get 9 - i32.store offset=8 - end - local.get 4 - i32.const 8 - i32.add - local.set 4 - i32.const 0 - local.get 0 - i32.store offset=3752 - i32.const 0 - local.get 6 - i32.store offset=3740 - br 12 (;@1;) - end - i32.const 0 - i32.load offset=3736 - local.tee 10 - i32.eqz - br_if 1 (;@11;) - local.get 10 - i32.const 0 - local.get 10 - i32.sub - i32.and - i32.ctz - i32.const 2 - i32.shl - i32.const 4036 - i32.add - i32.load - local.tee 0 - i32.load offset=4 - i32.const -8 - i32.and - local.get 5 - i32.sub - local.set 3 - local.get 0 - local.set 6 - block ;; label = @13 - loop ;; label = @14 - block ;; label = @15 - local.get 6 - i32.load offset=16 - local.tee 4 - br_if 0 (;@15;) - local.get 6 - i32.const 20 - i32.add - i32.load - local.tee 4 - i32.eqz - br_if 2 (;@13;) - end - local.get 4 - i32.load offset=4 - i32.const -8 - i32.and - local.get 5 - i32.sub - local.tee 6 - local.get 3 - local.get 6 - local.get 3 - i32.lt_u - local.tee 6 - select - local.set 3 - local.get 4 - local.get 0 - local.get 6 - select - local.set 0 - local.get 4 - local.set 6 - br 0 (;@14;) - end - end - local.get 0 - i32.load offset=24 - local.set 11 - block ;; label = @13 - local.get 0 - i32.load offset=12 - local.tee 9 - local.get 0 - i32.eq - br_if 0 (;@13;) - local.get 0 - i32.load offset=8 - local.tee 4 - i32.const 0 - i32.load offset=3748 - i32.lt_u - drop - local.get 9 - local.get 4 - i32.store offset=8 - local.get 4 - local.get 9 - i32.store offset=12 - br 11 (;@2;) - end - block ;; label = @13 - local.get 0 - i32.const 20 - i32.add - local.tee 6 - i32.load - local.tee 4 - br_if 0 (;@13;) - local.get 0 - i32.load offset=16 - local.tee 4 - i32.eqz - br_if 3 (;@10;) - local.get 0 - i32.const 16 - i32.add - local.set 6 - end - loop ;; label = @13 - local.get 6 - local.set 2 - local.get 4 - local.tee 9 - i32.const 20 - i32.add - local.tee 6 - i32.load - local.tee 4 - br_if 0 (;@13;) - local.get 9 - i32.const 16 - i32.add - local.set 6 - local.get 9 - i32.load offset=16 - local.tee 4 - br_if 0 (;@13;) - end - local.get 2 - i32.const 0 - i32.store - br 10 (;@2;) - end - i32.const -1 - local.set 5 - local.get 0 - i32.const -65 - i32.gt_u - br_if 0 (;@11;) - local.get 0 - i32.const 19 - i32.add - local.tee 4 - i32.const -16 - i32.and - local.set 5 - i32.const 0 - i32.load offset=3736 - local.tee 10 - i32.eqz - br_if 0 (;@11;) - i32.const 0 - local.set 8 - block ;; label = @12 - local.get 5 - i32.const 256 - i32.lt_u - br_if 0 (;@12;) - i32.const 31 - local.set 8 - local.get 5 - i32.const 16777215 - i32.gt_u - br_if 0 (;@12;) - local.get 5 - i32.const 38 - local.get 4 - i32.const 8 - i32.shr_u - i32.clz - local.tee 4 - i32.sub - i32.shr_u - i32.const 1 - i32.and - local.get 4 - i32.const 1 - i32.shl - i32.sub - i32.const 62 - i32.add - local.set 8 - end - i32.const 0 - local.get 5 - i32.sub - local.set 3 - block ;; label = @12 - block ;; label = @13 - block ;; label = @14 - block ;; label = @15 - local.get 8 - i32.const 2 - i32.shl - i32.const 4036 - i32.add - i32.load - local.tee 6 - br_if 0 (;@15;) - i32.const 0 - local.set 4 - i32.const 0 - local.set 9 - br 1 (;@14;) - end - i32.const 0 - local.set 4 - local.get 5 - i32.const 0 - i32.const 25 - local.get 8 - i32.const 1 - i32.shr_u - i32.sub - local.get 8 - i32.const 31 - i32.eq - select - i32.shl - local.set 0 - i32.const 0 - local.set 9 - loop ;; label = @15 - block ;; label = @16 - local.get 6 - i32.load offset=4 - i32.const -8 - i32.and - local.get 5 - i32.sub - local.tee 7 - local.get 3 - i32.ge_u - br_if 0 (;@16;) - local.get 7 - local.set 3 - local.get 6 - local.set 9 - local.get 7 - br_if 0 (;@16;) - i32.const 0 - local.set 3 - local.get 6 - local.set 9 - local.get 6 - local.set 4 - br 3 (;@13;) - end - local.get 4 - local.get 6 - i32.const 20 - i32.add - i32.load - local.tee 7 - local.get 7 - local.get 6 - local.get 0 - i32.const 29 - i32.shr_u - i32.const 4 - i32.and - i32.add - i32.const 16 - i32.add - i32.load - local.tee 6 - i32.eq - select - local.get 4 - local.get 7 - select - local.set 4 - local.get 0 - i32.const 1 - i32.shl - local.set 0 - local.get 6 - br_if 0 (;@15;) - end - end - block ;; label = @14 - local.get 4 - local.get 9 - i32.or - br_if 0 (;@14;) - i32.const 0 - local.set 9 - i32.const 2 - local.get 8 - i32.shl - local.tee 4 - i32.const 0 - local.get 4 - i32.sub - i32.or - local.get 10 - i32.and - local.tee 4 - i32.eqz - br_if 3 (;@11;) - local.get 4 - i32.const 0 - local.get 4 - i32.sub - i32.and - i32.ctz - i32.const 2 - i32.shl - i32.const 4036 - i32.add - i32.load - local.set 4 - end - local.get 4 - i32.eqz - br_if 1 (;@12;) - end - loop ;; label = @13 - local.get 4 - i32.load offset=4 - i32.const -8 - i32.and - local.get 5 - i32.sub - local.tee 7 - local.get 3 - i32.lt_u - local.set 0 - block ;; label = @14 - local.get 4 - i32.load offset=16 - local.tee 6 - br_if 0 (;@14;) - local.get 4 - i32.const 20 - i32.add - i32.load - local.set 6 - end - local.get 7 - local.get 3 - local.get 0 - select - local.set 3 - local.get 4 - local.get 9 - local.get 0 - select - local.set 9 - local.get 6 - local.set 4 - local.get 6 - br_if 0 (;@13;) - end - end - local.get 9 - i32.eqz - br_if 0 (;@11;) - local.get 3 - i32.const 0 - i32.load offset=3740 - local.get 5 - i32.sub - i32.ge_u - br_if 0 (;@11;) - local.get 9 - i32.load offset=24 - local.set 2 - block ;; label = @12 - local.get 9 - i32.load offset=12 - local.tee 0 - local.get 9 - i32.eq - br_if 0 (;@12;) - local.get 9 - i32.load offset=8 - local.tee 4 - i32.const 0 - i32.load offset=3748 - i32.lt_u - drop - local.get 0 - local.get 4 - i32.store offset=8 - local.get 4 - local.get 0 - i32.store offset=12 - br 9 (;@3;) - end - block ;; label = @12 - local.get 9 - i32.const 20 - i32.add - local.tee 6 - i32.load - local.tee 4 - br_if 0 (;@12;) - local.get 9 - i32.load offset=16 - local.tee 4 - i32.eqz - br_if 3 (;@9;) - local.get 9 - i32.const 16 - i32.add - local.set 6 - end - loop ;; label = @12 - local.get 6 - local.set 7 - local.get 4 - local.tee 0 - i32.const 20 - i32.add - local.tee 6 - i32.load - local.tee 4 - br_if 0 (;@12;) - local.get 0 - i32.const 16 - i32.add - local.set 6 - local.get 0 - i32.load offset=16 - local.tee 4 - br_if 0 (;@12;) - end - local.get 7 - i32.const 0 - i32.store - br 8 (;@3;) - end - block ;; label = @11 - i32.const 0 - i32.load offset=3740 - local.tee 4 - local.get 5 - i32.lt_u - br_if 0 (;@11;) - i32.const 0 - i32.load offset=3752 - local.set 3 - block ;; label = @12 - block ;; label = @13 - local.get 4 - local.get 5 - i32.sub - local.tee 6 - i32.const 16 - i32.lt_u - br_if 0 (;@13;) - local.get 3 - local.get 5 - i32.add - local.tee 0 - local.get 6 - i32.const 1 - i32.or - i32.store offset=4 - local.get 3 - local.get 4 - i32.add - local.get 6 - i32.store - local.get 3 - local.get 5 - i32.const 3 - i32.or - i32.store offset=4 - br 1 (;@12;) - end - local.get 3 - local.get 4 - i32.const 3 - i32.or - i32.store offset=4 - local.get 3 - local.get 4 - i32.add - local.tee 4 - local.get 4 - i32.load offset=4 - i32.const 1 - i32.or - i32.store offset=4 - i32.const 0 - local.set 0 - i32.const 0 - local.set 6 - end - i32.const 0 - local.get 6 - i32.store offset=3740 - i32.const 0 - local.get 0 - i32.store offset=3752 - local.get 3 - i32.const 8 - i32.add - local.set 4 - br 10 (;@1;) - end - block ;; label = @11 - i32.const 0 - i32.load offset=3744 - local.tee 6 - local.get 5 - i32.le_u - br_if 0 (;@11;) - local.get 2 - local.get 5 - i32.add - local.tee 4 - local.get 6 - local.get 5 - i32.sub - local.tee 3 - i32.const 1 - i32.or - i32.store offset=4 - i32.const 0 - local.get 4 - i32.store offset=3756 - i32.const 0 - local.get 3 - i32.store offset=3744 - local.get 2 - local.get 5 - i32.const 3 - i32.or - i32.store offset=4 - local.get 2 - i32.const 8 - i32.add - local.set 4 - br 10 (;@1;) - end - block ;; label = @11 - block ;; label = @12 - i32.const 0 - i32.load offset=4204 - i32.eqz - br_if 0 (;@12;) - i32.const 0 - i32.load offset=4212 - local.set 3 - br 1 (;@11;) - end - i32.const 0 - i64.const -1 - i64.store offset=4216 align=4 - i32.const 0 - i64.const 281474976776192 - i64.store offset=4208 align=4 - i32.const 0 - local.get 1 - i32.const 12 - i32.add - i32.const -16 - i32.and - i32.const 1431655768 - i32.xor - i32.store offset=4204 - i32.const 0 - i32.const 0 - i32.store offset=4224 - i32.const 0 - i32.const 0 - i32.store offset=4176 - i32.const 65536 - local.set 3 - end - i32.const 0 - local.set 4 - block ;; label = @11 - local.get 3 - local.get 5 - i32.const 71 - i32.add - local.tee 8 - i32.add - local.tee 0 - i32.const 0 - local.get 3 - i32.sub - local.tee 7 - i32.and - local.tee 9 - local.get 5 - i32.gt_u - br_if 0 (;@11;) - i32.const 0 - i32.const 48 - i32.store offset=4228 - br 10 (;@1;) - end - block ;; label = @11 - i32.const 0 - i32.load offset=4172 - local.tee 4 - i32.eqz - br_if 0 (;@11;) - block ;; label = @12 - i32.const 0 - i32.load offset=4164 - local.tee 3 - local.get 9 - i32.add - local.tee 10 - local.get 3 - i32.le_u - br_if 0 (;@12;) - local.get 10 - local.get 4 - i32.le_u - br_if 1 (;@11;) - end - i32.const 0 - local.set 4 - i32.const 0 - i32.const 48 - i32.store offset=4228 - br 10 (;@1;) - end - i32.const 0 - i32.load8_u offset=4176 - i32.const 4 - i32.and - br_if 4 (;@6;) - block ;; label = @11 - block ;; label = @12 - block ;; label = @13 - local.get 2 - i32.eqz - br_if 0 (;@13;) - i32.const 4180 - local.set 4 - loop ;; label = @14 - block ;; label = @15 - local.get 4 - i32.load - local.tee 3 - local.get 2 - i32.gt_u - br_if 0 (;@15;) - local.get 3 - local.get 4 - i32.load offset=4 - i32.add - local.get 2 - i32.gt_u - br_if 3 (;@12;) - end - local.get 4 - i32.load offset=8 - local.tee 4 - br_if 0 (;@14;) - end - end - i32.const 0 - call $sbrk - local.tee 0 - i32.const -1 - i32.eq - br_if 5 (;@7;) - local.get 9 - local.set 7 - block ;; label = @13 - i32.const 0 - i32.load offset=4208 - local.tee 4 - i32.const -1 - i32.add - local.tee 3 - local.get 0 - i32.and - i32.eqz - br_if 0 (;@13;) - local.get 9 - local.get 0 - i32.sub - local.get 3 - local.get 0 - i32.add - i32.const 0 - local.get 4 - i32.sub - i32.and - i32.add - local.set 7 - end - local.get 7 - local.get 5 - i32.le_u - br_if 5 (;@7;) - local.get 7 - i32.const 2147483646 - i32.gt_u - br_if 5 (;@7;) - block ;; label = @13 - i32.const 0 - i32.load offset=4172 - local.tee 4 - i32.eqz - br_if 0 (;@13;) - i32.const 0 - i32.load offset=4164 - local.tee 3 - local.get 7 - i32.add - local.tee 6 - local.get 3 - i32.le_u - br_if 6 (;@7;) - local.get 6 - local.get 4 - i32.gt_u - br_if 6 (;@7;) - end - local.get 7 - call $sbrk - local.tee 4 - local.get 0 - i32.ne - br_if 1 (;@11;) - br 7 (;@5;) - end - local.get 0 - local.get 6 - i32.sub - local.get 7 - i32.and - local.tee 7 - i32.const 2147483646 - i32.gt_u - br_if 4 (;@7;) - local.get 7 - call $sbrk - local.tee 0 - local.get 4 - i32.load - local.get 4 - i32.load offset=4 - i32.add - i32.eq - br_if 3 (;@8;) - local.get 0 - local.set 4 - end - block ;; label = @11 - local.get 4 - i32.const -1 - i32.eq - br_if 0 (;@11;) - local.get 5 - i32.const 72 - i32.add - local.get 7 - i32.le_u - br_if 0 (;@11;) - block ;; label = @12 - local.get 8 - local.get 7 - i32.sub - i32.const 0 - i32.load offset=4212 - local.tee 3 - i32.add - i32.const 0 - local.get 3 - i32.sub - i32.and - local.tee 3 - i32.const 2147483646 - i32.le_u - br_if 0 (;@12;) - local.get 4 - local.set 0 - br 7 (;@5;) - end - block ;; label = @12 - local.get 3 - call $sbrk - i32.const -1 - i32.eq - br_if 0 (;@12;) - local.get 3 - local.get 7 - i32.add - local.set 7 - local.get 4 - local.set 0 - br 7 (;@5;) - end - i32.const 0 - local.get 7 - i32.sub - call $sbrk - drop - br 4 (;@7;) - end - local.get 4 - local.set 0 - local.get 4 - i32.const -1 - i32.ne - br_if 5 (;@5;) - br 3 (;@7;) - end - i32.const 0 - local.set 9 - br 7 (;@2;) - end - i32.const 0 - local.set 0 - br 5 (;@3;) - end - local.get 0 - i32.const -1 - i32.ne - br_if 2 (;@5;) - end - i32.const 0 - i32.const 0 - i32.load offset=4176 - i32.const 4 - i32.or - i32.store offset=4176 - end - local.get 9 - i32.const 2147483646 - i32.gt_u - br_if 1 (;@4;) - local.get 9 - call $sbrk - local.set 0 - i32.const 0 - call $sbrk - local.set 4 - local.get 0 - i32.const -1 - i32.eq - br_if 1 (;@4;) - local.get 4 - i32.const -1 - i32.eq - br_if 1 (;@4;) - local.get 0 - local.get 4 - i32.ge_u - br_if 1 (;@4;) - local.get 4 - local.get 0 - i32.sub - local.tee 7 - local.get 5 - i32.const 56 - i32.add - i32.le_u - br_if 1 (;@4;) - end - i32.const 0 - i32.const 0 - i32.load offset=4164 - local.get 7 - i32.add - local.tee 4 - i32.store offset=4164 - block ;; label = @5 - local.get 4 - i32.const 0 - i32.load offset=4168 - i32.le_u - br_if 0 (;@5;) - i32.const 0 - local.get 4 - i32.store offset=4168 - end - block ;; label = @5 - block ;; label = @6 - block ;; label = @7 - block ;; label = @8 - i32.const 0 - i32.load offset=3756 - local.tee 3 - i32.eqz - br_if 0 (;@8;) - i32.const 4180 - local.set 4 - loop ;; label = @9 - local.get 0 - local.get 4 - i32.load - local.tee 6 - local.get 4 - i32.load offset=4 - local.tee 9 - i32.add - i32.eq - br_if 2 (;@7;) - local.get 4 - i32.load offset=8 - local.tee 4 - br_if 0 (;@9;) - br 3 (;@6;) - end - end - block ;; label = @8 - block ;; label = @9 - i32.const 0 - i32.load offset=3748 - local.tee 4 - i32.eqz - br_if 0 (;@9;) - local.get 0 - local.get 4 - i32.ge_u - br_if 1 (;@8;) - end - i32.const 0 - local.get 0 - i32.store offset=3748 - end - i32.const 0 - local.set 4 - i32.const 0 - local.get 7 - i32.store offset=4184 - i32.const 0 - local.get 0 - i32.store offset=4180 - i32.const 0 - i32.const -1 - i32.store offset=3764 - i32.const 0 - i32.const 0 - i32.load offset=4204 - i32.store offset=3768 - i32.const 0 - i32.const 0 - i32.store offset=4192 - loop ;; label = @8 - local.get 4 - i32.const 3792 - i32.add - local.get 4 - i32.const 3780 - i32.add - local.tee 3 - i32.store - local.get 3 - local.get 4 - i32.const 3772 - i32.add - local.tee 6 - i32.store - local.get 4 - i32.const 3784 - i32.add - local.get 6 - i32.store - local.get 4 - i32.const 3800 - i32.add - local.get 4 - i32.const 3788 - i32.add - local.tee 6 - i32.store - local.get 6 - local.get 3 - i32.store - local.get 4 - i32.const 3808 - i32.add - local.get 4 - i32.const 3796 - i32.add - local.tee 3 - i32.store - local.get 3 - local.get 6 - i32.store - local.get 4 - i32.const 3804 - i32.add - local.get 3 - i32.store - local.get 4 - i32.const 32 - i32.add - local.tee 4 - i32.const 256 - i32.ne - br_if 0 (;@8;) - end - local.get 0 - i32.const -8 - local.get 0 - i32.sub - i32.const 15 - i32.and - i32.const 0 - local.get 0 - i32.const 8 - i32.add - i32.const 15 - i32.and - select - local.tee 4 - i32.add - local.tee 3 - local.get 7 - i32.const -56 - i32.add - local.tee 6 - local.get 4 - i32.sub - local.tee 4 - i32.const 1 - i32.or - i32.store offset=4 - i32.const 0 - i32.const 0 - i32.load offset=4220 - i32.store offset=3760 - i32.const 0 - local.get 4 - i32.store offset=3744 - i32.const 0 - local.get 3 - i32.store offset=3756 - local.get 0 - local.get 6 - i32.add - i32.const 56 - i32.store offset=4 - br 2 (;@5;) - end - local.get 4 - i32.load8_u offset=12 - i32.const 8 - i32.and - br_if 0 (;@6;) - local.get 3 - local.get 6 - i32.lt_u - br_if 0 (;@6;) - local.get 3 - local.get 0 - i32.ge_u - br_if 0 (;@6;) - local.get 3 - i32.const -8 - local.get 3 - i32.sub - i32.const 15 - i32.and - i32.const 0 - local.get 3 - i32.const 8 - i32.add - i32.const 15 - i32.and - select - local.tee 6 - i32.add - local.tee 0 - i32.const 0 - i32.load offset=3744 - local.get 7 - i32.add - local.tee 2 - local.get 6 - i32.sub - local.tee 6 - i32.const 1 - i32.or - i32.store offset=4 - local.get 4 - local.get 9 - local.get 7 - i32.add - i32.store offset=4 - i32.const 0 - i32.const 0 - i32.load offset=4220 - i32.store offset=3760 - i32.const 0 - local.get 6 - i32.store offset=3744 - i32.const 0 - local.get 0 - i32.store offset=3756 - local.get 3 - local.get 2 - i32.add - i32.const 56 - i32.store offset=4 - br 1 (;@5;) - end - block ;; label = @6 - local.get 0 - i32.const 0 - i32.load offset=3748 - local.tee 9 - i32.ge_u - br_if 0 (;@6;) - i32.const 0 - local.get 0 - i32.store offset=3748 - local.get 0 - local.set 9 - end - local.get 0 - local.get 7 - i32.add - local.set 6 - i32.const 4180 - local.set 4 - block ;; label = @6 - block ;; label = @7 - block ;; label = @8 - block ;; label = @9 - block ;; label = @10 - block ;; label = @11 - block ;; label = @12 - loop ;; label = @13 - local.get 4 - i32.load - local.get 6 - i32.eq - br_if 1 (;@12;) - local.get 4 - i32.load offset=8 - local.tee 4 - br_if 0 (;@13;) - br 2 (;@11;) - end - end - local.get 4 - i32.load8_u offset=12 - i32.const 8 - i32.and - i32.eqz - br_if 1 (;@10;) - end - i32.const 4180 - local.set 4 - loop ;; label = @11 - block ;; label = @12 - local.get 4 - i32.load - local.tee 6 - local.get 3 - i32.gt_u - br_if 0 (;@12;) - local.get 6 - local.get 4 - i32.load offset=4 - i32.add - local.tee 6 - local.get 3 - i32.gt_u - br_if 3 (;@9;) - end - local.get 4 - i32.load offset=8 - local.set 4 - br 0 (;@11;) - end - end - local.get 4 - local.get 0 - i32.store - local.get 4 - local.get 4 - i32.load offset=4 - local.get 7 - i32.add - i32.store offset=4 - local.get 0 - i32.const -8 - local.get 0 - i32.sub - i32.const 15 - i32.and - i32.const 0 - local.get 0 - i32.const 8 - i32.add - i32.const 15 - i32.and - select - i32.add - local.tee 2 - local.get 5 - i32.const 3 - i32.or - i32.store offset=4 - local.get 6 - i32.const -8 - local.get 6 - i32.sub - i32.const 15 - i32.and - i32.const 0 - local.get 6 - i32.const 8 - i32.add - i32.const 15 - i32.and - select - i32.add - local.tee 7 - local.get 2 - local.get 5 - i32.add - local.tee 5 - i32.sub - local.set 4 - block ;; label = @10 - local.get 7 - local.get 3 - i32.ne - br_if 0 (;@10;) - i32.const 0 - local.get 5 - i32.store offset=3756 - i32.const 0 - i32.const 0 - i32.load offset=3744 - local.get 4 - i32.add - local.tee 4 - i32.store offset=3744 - local.get 5 - local.get 4 - i32.const 1 - i32.or - i32.store offset=4 - br 3 (;@7;) - end - block ;; label = @10 - local.get 7 - i32.const 0 - i32.load offset=3752 - i32.ne - br_if 0 (;@10;) - i32.const 0 - local.get 5 - i32.store offset=3752 - i32.const 0 - i32.const 0 - i32.load offset=3740 - local.get 4 - i32.add - local.tee 4 - i32.store offset=3740 - local.get 5 - local.get 4 - i32.const 1 - i32.or - i32.store offset=4 - local.get 5 - local.get 4 - i32.add - local.get 4 - i32.store - br 3 (;@7;) - end - block ;; label = @10 - local.get 7 - i32.load offset=4 - local.tee 3 - i32.const 3 - i32.and - i32.const 1 - i32.ne - br_if 0 (;@10;) - local.get 3 - i32.const -8 - i32.and - local.set 8 - block ;; label = @11 - block ;; label = @12 - local.get 3 - i32.const 255 - i32.gt_u - br_if 0 (;@12;) - local.get 7 - i32.load offset=8 - local.tee 6 - local.get 3 - i32.const 3 - i32.shr_u - local.tee 9 - i32.const 3 - i32.shl - i32.const 3772 - i32.add - local.tee 0 - i32.eq - drop - block ;; label = @13 - local.get 7 - i32.load offset=12 - local.tee 3 - local.get 6 - i32.ne - br_if 0 (;@13;) - i32.const 0 - i32.const 0 - i32.load offset=3732 - i32.const -2 - local.get 9 - i32.rotl - i32.and - i32.store offset=3732 - br 2 (;@11;) - end - local.get 3 - local.get 0 - i32.eq - drop - local.get 3 - local.get 6 - i32.store offset=8 - local.get 6 - local.get 3 - i32.store offset=12 - br 1 (;@11;) - end - local.get 7 - i32.load offset=24 - local.set 10 - block ;; label = @12 - block ;; label = @13 - local.get 7 - i32.load offset=12 - local.tee 0 - local.get 7 - i32.eq - br_if 0 (;@13;) - local.get 7 - i32.load offset=8 - local.tee 3 - local.get 9 - i32.lt_u - drop - local.get 0 - local.get 3 - i32.store offset=8 - local.get 3 - local.get 0 - i32.store offset=12 - br 1 (;@12;) - end - block ;; label = @13 - local.get 7 - i32.const 20 - i32.add - local.tee 3 - i32.load - local.tee 6 - br_if 0 (;@13;) - local.get 7 - i32.const 16 - i32.add - local.tee 3 - i32.load - local.tee 6 - br_if 0 (;@13;) - i32.const 0 - local.set 0 - br 1 (;@12;) - end - loop ;; label = @13 - local.get 3 - local.set 9 - local.get 6 - local.tee 0 - i32.const 20 - i32.add - local.tee 3 - i32.load - local.tee 6 - br_if 0 (;@13;) - local.get 0 - i32.const 16 - i32.add - local.set 3 - local.get 0 - i32.load offset=16 - local.tee 6 - br_if 0 (;@13;) - end - local.get 9 - i32.const 0 - i32.store - end - local.get 10 - i32.eqz - br_if 0 (;@11;) - block ;; label = @12 - block ;; label = @13 - local.get 7 - local.get 7 - i32.load offset=28 - local.tee 6 - i32.const 2 - i32.shl - i32.const 4036 - i32.add - local.tee 3 - i32.load - i32.ne - br_if 0 (;@13;) - local.get 3 - local.get 0 - i32.store - local.get 0 - br_if 1 (;@12;) - i32.const 0 - i32.const 0 - i32.load offset=3736 - i32.const -2 - local.get 6 - i32.rotl - i32.and - i32.store offset=3736 - br 2 (;@11;) - end - local.get 10 - i32.const 16 - i32.const 20 - local.get 10 - i32.load offset=16 - local.get 7 - i32.eq - select - i32.add - local.get 0 - i32.store - local.get 0 - i32.eqz - br_if 1 (;@11;) - end - local.get 0 - local.get 10 - i32.store offset=24 - block ;; label = @12 - local.get 7 - i32.load offset=16 - local.tee 3 - i32.eqz - br_if 0 (;@12;) - local.get 0 - local.get 3 - i32.store offset=16 - local.get 3 - local.get 0 - i32.store offset=24 - end - local.get 7 - i32.load offset=20 - local.tee 3 - i32.eqz - br_if 0 (;@11;) - local.get 0 - i32.const 20 - i32.add - local.get 3 - i32.store - local.get 3 - local.get 0 - i32.store offset=24 - end - local.get 8 - local.get 4 - i32.add - local.set 4 - local.get 7 - local.get 8 - i32.add - local.tee 7 - i32.load offset=4 - local.set 3 - end - local.get 7 - local.get 3 - i32.const -2 - i32.and - i32.store offset=4 - local.get 5 - local.get 4 - i32.add - local.get 4 - i32.store - local.get 5 - local.get 4 - i32.const 1 - i32.or - i32.store offset=4 - block ;; label = @10 - local.get 4 - i32.const 255 - i32.gt_u - br_if 0 (;@10;) - local.get 4 - i32.const -8 - i32.and - i32.const 3772 - i32.add - local.set 3 - block ;; label = @11 - block ;; label = @12 - i32.const 0 - i32.load offset=3732 - local.tee 6 - i32.const 1 - local.get 4 - i32.const 3 - i32.shr_u - i32.shl - local.tee 4 - i32.and - br_if 0 (;@12;) - i32.const 0 - local.get 6 - local.get 4 - i32.or - i32.store offset=3732 - local.get 3 - local.set 4 - br 1 (;@11;) - end - local.get 3 - i32.load offset=8 - local.set 4 - end - local.get 4 - local.get 5 - i32.store offset=12 - local.get 3 - local.get 5 - i32.store offset=8 - local.get 5 - local.get 3 - i32.store offset=12 - local.get 5 - local.get 4 - i32.store offset=8 - br 3 (;@7;) - end - i32.const 31 - local.set 3 - block ;; label = @10 - local.get 4 - i32.const 16777215 - i32.gt_u - br_if 0 (;@10;) - local.get 4 - i32.const 38 - local.get 4 - i32.const 8 - i32.shr_u - i32.clz - local.tee 3 - i32.sub - i32.shr_u - i32.const 1 - i32.and - local.get 3 - i32.const 1 - i32.shl - i32.sub - i32.const 62 - i32.add - local.set 3 - end - local.get 5 - local.get 3 - i32.store offset=28 - local.get 5 - i64.const 0 - i64.store offset=16 align=4 - local.get 3 - i32.const 2 - i32.shl - i32.const 4036 - i32.add - local.set 6 - block ;; label = @10 - i32.const 0 - i32.load offset=3736 - local.tee 0 - i32.const 1 - local.get 3 - i32.shl - local.tee 9 - i32.and - br_if 0 (;@10;) - local.get 6 - local.get 5 - i32.store - i32.const 0 - local.get 0 - local.get 9 - i32.or - i32.store offset=3736 - local.get 5 - local.get 6 - i32.store offset=24 - local.get 5 - local.get 5 - i32.store offset=8 - local.get 5 - local.get 5 - i32.store offset=12 - br 3 (;@7;) - end - local.get 4 - i32.const 0 - i32.const 25 - local.get 3 - i32.const 1 - i32.shr_u - i32.sub - local.get 3 - i32.const 31 - i32.eq - select - i32.shl - local.set 3 - local.get 6 - i32.load - local.set 0 - loop ;; label = @10 - local.get 0 - local.tee 6 - i32.load offset=4 - i32.const -8 - i32.and - local.get 4 - i32.eq - br_if 2 (;@8;) - local.get 3 - i32.const 29 - i32.shr_u - local.set 0 - local.get 3 - i32.const 1 - i32.shl - local.set 3 - local.get 6 - local.get 0 - i32.const 4 - i32.and - i32.add - i32.const 16 - i32.add - local.tee 9 - i32.load - local.tee 0 - br_if 0 (;@10;) - end - local.get 9 - local.get 5 - i32.store - local.get 5 - local.get 6 - i32.store offset=24 - local.get 5 - local.get 5 - i32.store offset=12 - local.get 5 - local.get 5 - i32.store offset=8 - br 2 (;@7;) - end - local.get 0 - i32.const -8 - local.get 0 - i32.sub - i32.const 15 - i32.and - i32.const 0 - local.get 0 - i32.const 8 - i32.add - i32.const 15 - i32.and - select - local.tee 4 - i32.add - local.tee 2 - local.get 7 - i32.const -56 - i32.add - local.tee 9 - local.get 4 - i32.sub - local.tee 4 - i32.const 1 - i32.or - i32.store offset=4 - local.get 0 - local.get 9 - i32.add - i32.const 56 - i32.store offset=4 - local.get 3 - local.get 6 - i32.const 55 - local.get 6 - i32.sub - i32.const 15 - i32.and - i32.const 0 - local.get 6 - i32.const -55 - i32.add - i32.const 15 - i32.and - select - i32.add - i32.const -63 - i32.add - local.tee 9 - local.get 9 - local.get 3 - i32.const 16 - i32.add - i32.lt_u - select - local.tee 9 - i32.const 35 - i32.store offset=4 - i32.const 0 - i32.const 0 - i32.load offset=4220 - i32.store offset=3760 - i32.const 0 - local.get 4 - i32.store offset=3744 - i32.const 0 - local.get 2 - i32.store offset=3756 - local.get 9 - i32.const 16 - i32.add - i32.const 0 - i64.load offset=4188 align=4 - i64.store align=4 - local.get 9 - i32.const 0 - i64.load offset=4180 align=4 - i64.store offset=8 align=4 - i32.const 0 - local.get 9 - i32.const 8 - i32.add - i32.store offset=4188 - i32.const 0 - local.get 7 - i32.store offset=4184 - i32.const 0 - local.get 0 - i32.store offset=4180 - i32.const 0 - i32.const 0 - i32.store offset=4192 - local.get 9 - i32.const 36 - i32.add - local.set 4 - loop ;; label = @9 - local.get 4 - i32.const 7 - i32.store - local.get 4 - i32.const 4 - i32.add - local.tee 4 - local.get 6 - i32.lt_u - br_if 0 (;@9;) - end - local.get 9 - local.get 3 - i32.eq - br_if 3 (;@5;) - local.get 9 - local.get 9 - i32.load offset=4 - i32.const -2 - i32.and - i32.store offset=4 - local.get 9 - local.get 9 - local.get 3 - i32.sub - local.tee 0 - i32.store - local.get 3 - local.get 0 - i32.const 1 - i32.or - i32.store offset=4 - block ;; label = @9 - local.get 0 - i32.const 255 - i32.gt_u - br_if 0 (;@9;) - local.get 0 - i32.const -8 - i32.and - i32.const 3772 - i32.add - local.set 4 - block ;; label = @10 - block ;; label = @11 - i32.const 0 - i32.load offset=3732 - local.tee 6 - i32.const 1 - local.get 0 - i32.const 3 - i32.shr_u - i32.shl - local.tee 0 - i32.and - br_if 0 (;@11;) - i32.const 0 - local.get 6 - local.get 0 - i32.or - i32.store offset=3732 - local.get 4 - local.set 6 - br 1 (;@10;) - end - local.get 4 - i32.load offset=8 - local.set 6 - end - local.get 6 - local.get 3 - i32.store offset=12 - local.get 4 - local.get 3 - i32.store offset=8 - local.get 3 - local.get 4 - i32.store offset=12 - local.get 3 - local.get 6 - i32.store offset=8 - br 4 (;@5;) - end - i32.const 31 - local.set 4 - block ;; label = @9 - local.get 0 - i32.const 16777215 - i32.gt_u - br_if 0 (;@9;) - local.get 0 - i32.const 38 - local.get 0 - i32.const 8 - i32.shr_u - i32.clz - local.tee 4 - i32.sub - i32.shr_u - i32.const 1 - i32.and - local.get 4 - i32.const 1 - i32.shl - i32.sub - i32.const 62 - i32.add - local.set 4 - end - local.get 3 - local.get 4 - i32.store offset=28 - local.get 3 - i64.const 0 - i64.store offset=16 align=4 - local.get 4 - i32.const 2 - i32.shl - i32.const 4036 - i32.add - local.set 6 - block ;; label = @9 - i32.const 0 - i32.load offset=3736 - local.tee 9 - i32.const 1 - local.get 4 - i32.shl - local.tee 7 - i32.and - br_if 0 (;@9;) - local.get 6 - local.get 3 - i32.store - i32.const 0 - local.get 9 - local.get 7 - i32.or - i32.store offset=3736 - local.get 3 - local.get 6 - i32.store offset=24 - local.get 3 - local.get 3 - i32.store offset=8 - local.get 3 - local.get 3 - i32.store offset=12 - br 4 (;@5;) - end - local.get 0 - i32.const 0 - i32.const 25 - local.get 4 - i32.const 1 - i32.shr_u - i32.sub - local.get 4 - i32.const 31 - i32.eq - select - i32.shl - local.set 4 - local.get 6 - i32.load - local.set 9 - loop ;; label = @9 - local.get 9 - local.tee 6 - i32.load offset=4 - i32.const -8 - i32.and - local.get 0 - i32.eq - br_if 3 (;@6;) - local.get 4 - i32.const 29 - i32.shr_u - local.set 9 - local.get 4 - i32.const 1 - i32.shl - local.set 4 - local.get 6 - local.get 9 - i32.const 4 - i32.and - i32.add - i32.const 16 - i32.add - local.tee 7 - i32.load - local.tee 9 - br_if 0 (;@9;) - end - local.get 7 - local.get 3 - i32.store - local.get 3 - local.get 6 - i32.store offset=24 - local.get 3 - local.get 3 - i32.store offset=12 - local.get 3 - local.get 3 - i32.store offset=8 - br 3 (;@5;) - end - local.get 6 - i32.load offset=8 - local.tee 4 - local.get 5 - i32.store offset=12 - local.get 6 - local.get 5 - i32.store offset=8 - local.get 5 - i32.const 0 - i32.store offset=24 - local.get 5 - local.get 6 - i32.store offset=12 - local.get 5 - local.get 4 - i32.store offset=8 - end - local.get 2 - i32.const 8 - i32.add - local.set 4 - br 5 (;@1;) - end - local.get 6 - i32.load offset=8 - local.tee 4 - local.get 3 - i32.store offset=12 - local.get 6 - local.get 3 - i32.store offset=8 - local.get 3 - i32.const 0 - i32.store offset=24 - local.get 3 - local.get 6 - i32.store offset=12 - local.get 3 - local.get 4 - i32.store offset=8 - end - i32.const 0 - i32.load offset=3744 - local.tee 4 - local.get 5 - i32.le_u - br_if 0 (;@4;) - i32.const 0 - i32.load offset=3756 - local.tee 3 - local.get 5 - i32.add - local.tee 6 - local.get 4 - local.get 5 - i32.sub - local.tee 4 - i32.const 1 - i32.or - i32.store offset=4 - i32.const 0 - local.get 4 - i32.store offset=3744 - i32.const 0 - local.get 6 - i32.store offset=3756 - local.get 3 - local.get 5 - i32.const 3 - i32.or - i32.store offset=4 - local.get 3 - i32.const 8 - i32.add - local.set 4 - br 3 (;@1;) - end - i32.const 0 - local.set 4 - i32.const 0 - i32.const 48 - i32.store offset=4228 - br 2 (;@1;) - end - block ;; label = @3 - local.get 2 - i32.eqz - br_if 0 (;@3;) - block ;; label = @4 - block ;; label = @5 - local.get 9 - local.get 9 - i32.load offset=28 - local.tee 6 - i32.const 2 - i32.shl - i32.const 4036 - i32.add - local.tee 4 - i32.load - i32.ne - br_if 0 (;@5;) - local.get 4 - local.get 0 - i32.store - local.get 0 - br_if 1 (;@4;) - i32.const 0 - local.get 10 - i32.const -2 - local.get 6 - i32.rotl - i32.and - local.tee 10 - i32.store offset=3736 - br 2 (;@3;) - end - local.get 2 - i32.const 16 - i32.const 20 - local.get 2 - i32.load offset=16 - local.get 9 - i32.eq - select - i32.add - local.get 0 - i32.store - local.get 0 - i32.eqz - br_if 1 (;@3;) - end - local.get 0 - local.get 2 - i32.store offset=24 - block ;; label = @4 - local.get 9 - i32.load offset=16 - local.tee 4 - i32.eqz - br_if 0 (;@4;) - local.get 0 - local.get 4 - i32.store offset=16 - local.get 4 - local.get 0 - i32.store offset=24 - end - local.get 9 - i32.const 20 - i32.add - i32.load - local.tee 4 - i32.eqz - br_if 0 (;@3;) - local.get 0 - i32.const 20 - i32.add - local.get 4 - i32.store - local.get 4 - local.get 0 - i32.store offset=24 - end - block ;; label = @3 - block ;; label = @4 - local.get 3 - i32.const 15 - i32.gt_u - br_if 0 (;@4;) - local.get 9 - local.get 3 - local.get 5 - i32.add - local.tee 4 - i32.const 3 - i32.or - i32.store offset=4 - local.get 9 - local.get 4 - i32.add - local.tee 4 - local.get 4 - i32.load offset=4 - i32.const 1 - i32.or - i32.store offset=4 - br 1 (;@3;) - end - local.get 9 - local.get 5 - i32.add - local.tee 0 - local.get 3 - i32.const 1 - i32.or - i32.store offset=4 - local.get 9 - local.get 5 - i32.const 3 - i32.or - i32.store offset=4 - local.get 0 - local.get 3 - i32.add - local.get 3 - i32.store - block ;; label = @4 - local.get 3 - i32.const 255 - i32.gt_u - br_if 0 (;@4;) - local.get 3 - i32.const -8 - i32.and - i32.const 3772 - i32.add - local.set 4 - block ;; label = @5 - block ;; label = @6 - i32.const 0 - i32.load offset=3732 - local.tee 6 - i32.const 1 - local.get 3 - i32.const 3 - i32.shr_u - i32.shl - local.tee 3 - i32.and - br_if 0 (;@6;) - i32.const 0 - local.get 6 - local.get 3 - i32.or - i32.store offset=3732 - local.get 4 - local.set 3 - br 1 (;@5;) - end - local.get 4 - i32.load offset=8 - local.set 3 - end - local.get 3 - local.get 0 - i32.store offset=12 - local.get 4 - local.get 0 - i32.store offset=8 - local.get 0 - local.get 4 - i32.store offset=12 - local.get 0 - local.get 3 - i32.store offset=8 - br 1 (;@3;) - end - i32.const 31 - local.set 4 - block ;; label = @4 - local.get 3 - i32.const 16777215 - i32.gt_u - br_if 0 (;@4;) - local.get 3 - i32.const 38 - local.get 3 - i32.const 8 - i32.shr_u - i32.clz - local.tee 4 - i32.sub - i32.shr_u - i32.const 1 - i32.and - local.get 4 - i32.const 1 - i32.shl - i32.sub - i32.const 62 - i32.add - local.set 4 - end - local.get 0 - local.get 4 - i32.store offset=28 - local.get 0 - i64.const 0 - i64.store offset=16 align=4 - local.get 4 - i32.const 2 - i32.shl - i32.const 4036 - i32.add - local.set 6 - block ;; label = @4 - local.get 10 - i32.const 1 - local.get 4 - i32.shl - local.tee 5 - i32.and - br_if 0 (;@4;) - local.get 6 - local.get 0 - i32.store - i32.const 0 - local.get 10 - local.get 5 - i32.or - i32.store offset=3736 - local.get 0 - local.get 6 - i32.store offset=24 - local.get 0 - local.get 0 - i32.store offset=8 - local.get 0 - local.get 0 - i32.store offset=12 - br 1 (;@3;) - end - local.get 3 - i32.const 0 - i32.const 25 - local.get 4 - i32.const 1 - i32.shr_u - i32.sub - local.get 4 - i32.const 31 - i32.eq - select - i32.shl - local.set 4 - local.get 6 - i32.load - local.set 5 - block ;; label = @4 - loop ;; label = @5 - local.get 5 - local.tee 6 - i32.load offset=4 - i32.const -8 - i32.and - local.get 3 - i32.eq - br_if 1 (;@4;) - local.get 4 - i32.const 29 - i32.shr_u - local.set 5 - local.get 4 - i32.const 1 - i32.shl - local.set 4 - local.get 6 - local.get 5 - i32.const 4 - i32.and - i32.add - i32.const 16 - i32.add - local.tee 7 - i32.load - local.tee 5 - br_if 0 (;@5;) - end - local.get 7 - local.get 0 - i32.store - local.get 0 - local.get 6 - i32.store offset=24 - local.get 0 - local.get 0 - i32.store offset=12 - local.get 0 - local.get 0 - i32.store offset=8 - br 1 (;@3;) - end - local.get 6 - i32.load offset=8 - local.tee 4 - local.get 0 - i32.store offset=12 - local.get 6 - local.get 0 - i32.store offset=8 - local.get 0 - i32.const 0 - i32.store offset=24 - local.get 0 - local.get 6 - i32.store offset=12 - local.get 0 - local.get 4 - i32.store offset=8 - end - local.get 9 - i32.const 8 - i32.add - local.set 4 - br 1 (;@1;) - end - block ;; label = @2 - local.get 11 - i32.eqz - br_if 0 (;@2;) - block ;; label = @3 - block ;; label = @4 - local.get 0 - local.get 0 - i32.load offset=28 - local.tee 6 - i32.const 2 - i32.shl - i32.const 4036 - i32.add - local.tee 4 - i32.load - i32.ne - br_if 0 (;@4;) - local.get 4 - local.get 9 - i32.store - local.get 9 - br_if 1 (;@3;) - i32.const 0 - local.get 10 - i32.const -2 - local.get 6 - i32.rotl - i32.and - i32.store offset=3736 - br 2 (;@2;) - end - local.get 11 - i32.const 16 - i32.const 20 - local.get 11 - i32.load offset=16 - local.get 0 - i32.eq - select - i32.add - local.get 9 - i32.store - local.get 9 - i32.eqz - br_if 1 (;@2;) - end - local.get 9 - local.get 11 - i32.store offset=24 - block ;; label = @3 - local.get 0 - i32.load offset=16 - local.tee 4 - i32.eqz - br_if 0 (;@3;) - local.get 9 - local.get 4 - i32.store offset=16 - local.get 4 - local.get 9 - i32.store offset=24 - end - local.get 0 - i32.const 20 - i32.add - i32.load - local.tee 4 - i32.eqz - br_if 0 (;@2;) - local.get 9 - i32.const 20 - i32.add - local.get 4 - i32.store - local.get 4 - local.get 9 - i32.store offset=24 - end - block ;; label = @2 - block ;; label = @3 - local.get 3 - i32.const 15 - i32.gt_u - br_if 0 (;@3;) - local.get 0 - local.get 3 - local.get 5 - i32.add - local.tee 4 - i32.const 3 - i32.or - i32.store offset=4 - local.get 0 - local.get 4 - i32.add - local.tee 4 - local.get 4 - i32.load offset=4 - i32.const 1 - i32.or - i32.store offset=4 - br 1 (;@2;) - end - local.get 0 - local.get 5 - i32.add - local.tee 6 - local.get 3 - i32.const 1 - i32.or - i32.store offset=4 - local.get 0 - local.get 5 - i32.const 3 - i32.or - i32.store offset=4 - local.get 6 - local.get 3 - i32.add - local.get 3 - i32.store - block ;; label = @3 - local.get 8 - i32.eqz - br_if 0 (;@3;) - local.get 8 - i32.const -8 - i32.and - i32.const 3772 - i32.add - local.set 5 - i32.const 0 - i32.load offset=3752 - local.set 4 - block ;; label = @4 - block ;; label = @5 - i32.const 1 - local.get 8 - i32.const 3 - i32.shr_u - i32.shl - local.tee 9 - local.get 7 - i32.and - br_if 0 (;@5;) - i32.const 0 - local.get 9 - local.get 7 - i32.or - i32.store offset=3732 - local.get 5 - local.set 9 - br 1 (;@4;) - end - local.get 5 - i32.load offset=8 - local.set 9 - end - local.get 9 - local.get 4 - i32.store offset=12 - local.get 5 - local.get 4 - i32.store offset=8 - local.get 4 - local.get 5 - i32.store offset=12 - local.get 4 - local.get 9 - i32.store offset=8 - end - i32.const 0 - local.get 6 - i32.store offset=3752 - i32.const 0 - local.get 3 - i32.store offset=3740 - end - local.get 0 - i32.const 8 - i32.add - local.set 4 - end - local.get 1 - i32.const 16 - i32.add - global.set $__stack_pointer - local.get 4) - (func $__wasi_fd_close (type 2) (param i32) (result i32) - local.get 0 - call $__imported_wasi_snapshot_preview1_fd_close - i32.const 65535 - i32.and) - (func $__wasi_fd_fdstat_get (type 3) (param i32 i32) (result i32) - local.get 0 - local.get 1 - call $__imported_wasi_snapshot_preview1_fd_fdstat_get - i32.const 65535 - i32.and) - (func $__wasi_fd_seek (type 4) (param i32 i64 i32 i32) (result i32) - local.get 0 - local.get 1 - local.get 2 - local.get 3 - call $__imported_wasi_snapshot_preview1_fd_seek - i32.const 65535 - i32.and) - (func $__wasi_fd_write (type 5) (param i32 i32 i32 i32) (result i32) - local.get 0 - local.get 1 - local.get 2 - local.get 3 - call $__imported_wasi_snapshot_preview1_fd_write - i32.const 65535 - i32.and) - (func $__wasi_proc_exit (type 6) (param i32) - local.get 0 - call $__imported_wasi_snapshot_preview1_proc_exit - unreachable) - (func $abort (type 7) - unreachable - unreachable) - (func $sbrk (type 2) (param i32) (result i32) - block ;; label = @1 - local.get 0 - br_if 0 (;@1;) - memory.size - i32.const 16 - i32.shl - return - end - block ;; label = @1 - local.get 0 - i32.const 65535 - i32.and - br_if 0 (;@1;) - local.get 0 - i32.const -1 - i32.le_s - br_if 0 (;@1;) - block ;; label = @2 - local.get 0 - i32.const 16 - i32.shr_u - memory.grow - local.tee 0 - i32.const -1 - i32.ne - br_if 0 (;@2;) - i32.const 0 - i32.const 48 - i32.store offset=4228 - i32.const -1 - return - end - local.get 0 - i32.const 16 - i32.shl - return - end - call $abort - unreachable) - (func $dummy (type 7)) - (func $__wasm_call_dtors (type 7) - call $dummy - call $__stdio_exit) - (func $printf (type 3) (param i32 i32) (result i32) - (local i32) - global.get $__stack_pointer - i32.const 16 - i32.sub - local.tee 2 - global.set $__stack_pointer - local.get 2 - local.get 1 - i32.store offset=12 - i32.const 3488 - local.get 0 - local.get 1 - call $vfprintf - local.set 1 - local.get 2 - i32.const 16 - i32.add - global.set $__stack_pointer - local.get 1) - (func $close (type 2) (param i32) (result i32) - block ;; label = @1 - local.get 0 - call $__wasi_fd_close - local.tee 0 - br_if 0 (;@1;) - i32.const 0 - return - end - i32.const 0 - local.get 0 - i32.store offset=4228 - i32.const -1) - (func $__stdio_close (type 2) (param i32) (result i32) - local.get 0 - i32.load offset=56 - call $close) - (func $writev (type 0) (param i32 i32 i32) (result i32) - (local i32 i32) - global.get $__stack_pointer - i32.const 16 - i32.sub - local.tee 3 - global.set $__stack_pointer - i32.const -1 - local.set 4 - block ;; label = @1 - block ;; label = @2 - local.get 2 - i32.const -1 - i32.gt_s - br_if 0 (;@2;) - i32.const 0 - i32.const 28 - i32.store offset=4228 - br 1 (;@1;) - end - block ;; label = @2 - local.get 0 - local.get 1 - local.get 2 - local.get 3 - i32.const 12 - i32.add - call $__wasi_fd_write - local.tee 2 - i32.eqz - br_if 0 (;@2;) - i32.const 0 - local.get 2 - i32.store offset=4228 - i32.const -1 - local.set 4 - br 1 (;@1;) - end - local.get 3 - i32.load offset=12 - local.set 4 - end - local.get 3 - i32.const 16 - i32.add - global.set $__stack_pointer - local.get 4) - (func $__stdio_write (type 0) (param i32 i32 i32) (result i32) - (local i32 i32 i32 i32 i32 i32 i32) - global.get $__stack_pointer - i32.const 16 - i32.sub - local.tee 3 - global.set $__stack_pointer - local.get 3 - local.get 2 - i32.store offset=12 - local.get 3 - local.get 1 - i32.store offset=8 - local.get 3 - local.get 0 - i32.load offset=24 - local.tee 1 - i32.store - local.get 3 - local.get 0 - i32.load offset=20 - local.get 1 - i32.sub - local.tee 1 - i32.store offset=4 - i32.const 2 - local.set 4 - block ;; label = @1 - block ;; label = @2 - local.get 1 - local.get 2 - i32.add - local.tee 5 - local.get 0 - i32.load offset=56 - local.get 3 - i32.const 2 - call $writev - local.tee 1 - i32.eq - br_if 0 (;@2;) - local.get 3 - local.set 6 - loop ;; label = @3 - block ;; label = @4 - local.get 1 - i32.const -1 - i32.gt_s - br_if 0 (;@4;) - i32.const 0 - local.set 1 - local.get 0 - i32.const 0 - i32.store offset=24 - local.get 0 - i64.const 0 - i64.store offset=16 - local.get 0 - local.get 0 - i32.load - i32.const 32 - i32.or - i32.store - local.get 4 - i32.const 2 - i32.eq - br_if 3 (;@1;) - local.get 2 - local.get 6 - i32.load offset=4 - i32.sub - local.set 1 - br 3 (;@1;) - end - local.get 6 - local.get 1 - local.get 6 - i32.load offset=4 - local.tee 7 - i32.gt_u - local.tee 8 - i32.const 3 - i32.shl - i32.add - local.tee 9 - local.get 9 - i32.load - local.get 1 - local.get 7 - i32.const 0 - local.get 8 - select - i32.sub - local.tee 7 - i32.add - i32.store - local.get 6 - i32.const 12 - i32.const 4 - local.get 8 - select - i32.add - local.tee 6 - local.get 6 - i32.load - local.get 7 - i32.sub - i32.store - local.get 9 - local.set 6 - local.get 5 - local.get 1 - i32.sub - local.tee 5 - local.get 0 - i32.load offset=56 - local.get 9 - local.get 4 - local.get 8 - i32.sub - local.tee 4 - call $writev - local.tee 1 - i32.ne - br_if 0 (;@3;) - end - end - local.get 0 - local.get 0 - i32.load offset=40 - local.tee 1 - i32.store offset=24 - local.get 0 - local.get 1 - i32.store offset=20 - local.get 0 - local.get 1 - local.get 0 - i32.load offset=44 - i32.add - i32.store offset=16 - local.get 2 - local.set 1 - end - local.get 3 - i32.const 16 - i32.add - global.set $__stack_pointer - local.get 1) - (func $__isatty (type 2) (param i32) (result i32) - (local i32 i32) - global.get $__stack_pointer - i32.const 32 - i32.sub - local.tee 1 - global.set $__stack_pointer - block ;; label = @1 - block ;; label = @2 - local.get 0 - local.get 1 - i32.const 8 - i32.add - call $__wasi_fd_fdstat_get - local.tee 0 - br_if 0 (;@2;) - i32.const 59 - local.set 0 - local.get 1 - i32.load8_u offset=8 - i32.const 2 - i32.ne - br_if 0 (;@2;) - local.get 1 - i32.load8_u offset=16 - i32.const 36 - i32.and - br_if 0 (;@2;) - i32.const 1 - local.set 2 - br 1 (;@1;) - end - i32.const 0 - local.set 2 - i32.const 0 - local.get 0 - i32.store offset=4228 - end - local.get 1 - i32.const 32 - i32.add - global.set $__stack_pointer - local.get 2) - (func $__stdout_write (type 0) (param i32 i32 i32) (result i32) - local.get 0 - i32.const 1 - i32.store offset=32 - block ;; label = @1 - local.get 0 - i32.load8_u - i32.const 64 - i32.and - br_if 0 (;@1;) - local.get 0 - i32.load offset=56 - call $__isatty - br_if 0 (;@1;) - local.get 0 - i32.const -1 - i32.store offset=64 - end - local.get 0 - local.get 1 - local.get 2 - call $__stdio_write) - (func $__lseek (type 1) (param i32 i64 i32) (result i64) - (local i32) - global.get $__stack_pointer - i32.const 16 - i32.sub - local.tee 3 - global.set $__stack_pointer - block ;; label = @1 - block ;; label = @2 - local.get 0 - local.get 1 - local.get 2 - i32.const 255 - i32.and - local.get 3 - i32.const 8 - i32.add - call $__wasi_fd_seek - local.tee 2 - i32.eqz - br_if 0 (;@2;) - i32.const 0 - i32.const 70 - local.get 2 - local.get 2 - i32.const 76 - i32.eq - select - i32.store offset=4228 - i64.const -1 - local.set 1 - br 1 (;@1;) - end - local.get 3 - i64.load offset=8 - local.set 1 - end - local.get 3 - i32.const 16 - i32.add - global.set $__stack_pointer - local.get 1) - (func $__stdio_seek (type 1) (param i32 i64 i32) (result i64) - local.get 0 - i32.load offset=56 - local.get 1 - local.get 2 - call $__lseek) - (func $__ofl_lock (type 8) (result i32) - i32.const 5272) - (func $__stdio_exit (type 7) - (local i32 i32 i32) - block ;; label = @1 - call $__ofl_lock - i32.load - local.tee 0 - i32.eqz - br_if 0 (;@1;) - loop ;; label = @2 - block ;; label = @3 - local.get 0 - i32.load offset=20 - local.get 0 - i32.load offset=24 - i32.eq - br_if 0 (;@3;) - local.get 0 - i32.const 0 - i32.const 0 - local.get 0 - i32.load offset=32 - call_indirect (type 0) - drop - end - block ;; label = @3 - local.get 0 - i32.load offset=4 - local.tee 1 - local.get 0 - i32.load offset=8 - local.tee 2 - i32.eq - br_if 0 (;@3;) - local.get 0 - local.get 1 - local.get 2 - i32.sub - i64.extend_i32_s - i32.const 1 - local.get 0 - i32.load offset=36 - call_indirect (type 1) - drop - end - local.get 0 - i32.load offset=52 - local.tee 0 - br_if 0 (;@2;) - end - end - block ;; label = @1 - i32.const 0 - i32.load offset=5276 - local.tee 0 - i32.eqz - br_if 0 (;@1;) - block ;; label = @2 - local.get 0 - i32.load offset=20 - local.get 0 - i32.load offset=24 - i32.eq - br_if 0 (;@2;) - local.get 0 - i32.const 0 - i32.const 0 - local.get 0 - i32.load offset=32 - call_indirect (type 0) - drop - end - local.get 0 - i32.load offset=4 - local.tee 1 - local.get 0 - i32.load offset=8 - local.tee 2 - i32.eq - br_if 0 (;@1;) - local.get 0 - local.get 1 - local.get 2 - i32.sub - i64.extend_i32_s - i32.const 1 - local.get 0 - i32.load offset=36 - call_indirect (type 1) - drop - end - block ;; label = @1 - i32.const 0 - i32.load offset=3600 - local.tee 0 - i32.eqz - br_if 0 (;@1;) - block ;; label = @2 - local.get 0 - i32.load offset=20 - local.get 0 - i32.load offset=24 - i32.eq - br_if 0 (;@2;) - local.get 0 - i32.const 0 - i32.const 0 - local.get 0 - i32.load offset=32 - call_indirect (type 0) - drop - end - local.get 0 - i32.load offset=4 - local.tee 1 - local.get 0 - i32.load offset=8 - local.tee 2 - i32.eq - br_if 0 (;@1;) - local.get 0 - local.get 1 - local.get 2 - i32.sub - i64.extend_i32_s - i32.const 1 - local.get 0 - i32.load offset=36 - call_indirect (type 1) - drop - end - block ;; label = @1 - i32.const 0 - i32.load offset=3720 - local.tee 0 - i32.eqz - br_if 0 (;@1;) - block ;; label = @2 - local.get 0 - i32.load offset=20 - local.get 0 - i32.load offset=24 - i32.eq - br_if 0 (;@2;) - local.get 0 - i32.const 0 - i32.const 0 - local.get 0 - i32.load offset=32 - call_indirect (type 0) - drop - end - local.get 0 - i32.load offset=4 - local.tee 1 - local.get 0 - i32.load offset=8 - local.tee 2 - i32.eq - br_if 0 (;@1;) - local.get 0 - local.get 1 - local.get 2 - i32.sub - i64.extend_i32_s - i32.const 1 - local.get 0 - i32.load offset=36 - call_indirect (type 1) - drop - end) - (func $__towrite (type 2) (param i32) (result i32) - (local i32) - local.get 0 - local.get 0 - i32.load offset=60 - local.tee 1 - i32.const -1 - i32.add - local.get 1 - i32.or - i32.store offset=60 - block ;; label = @1 - local.get 0 - i32.load - local.tee 1 - i32.const 8 - i32.and - i32.eqz - br_if 0 (;@1;) - local.get 0 - local.get 1 - i32.const 32 - i32.or - i32.store - i32.const -1 - return - end - local.get 0 - i64.const 0 - i64.store offset=4 align=4 - local.get 0 - local.get 0 - i32.load offset=40 - local.tee 1 - i32.store offset=24 - local.get 0 - local.get 1 - i32.store offset=20 - local.get 0 - local.get 1 - local.get 0 - i32.load offset=44 - i32.add - i32.store offset=16 - i32.const 0) - (func $__fwritex (type 0) (param i32 i32 i32) (result i32) - (local i32 i32 i32 i32 i32) - block ;; label = @1 - block ;; label = @2 - local.get 2 - i32.load offset=16 - local.tee 3 - br_if 0 (;@2;) - i32.const 0 - local.set 4 - local.get 2 - call $__towrite - br_if 1 (;@1;) - local.get 2 - i32.load offset=16 - local.set 3 - end - block ;; label = @2 - local.get 3 - local.get 2 - i32.load offset=20 - local.tee 5 - i32.sub - local.get 1 - i32.ge_u - br_if 0 (;@2;) - local.get 2 - local.get 0 - local.get 1 - local.get 2 - i32.load offset=32 - call_indirect (type 0) - return - end - i32.const 0 - local.set 6 - block ;; label = @2 - local.get 2 - i32.load offset=64 - i32.const 0 - i32.lt_s - br_if 0 (;@2;) - i32.const 0 - local.set 6 - local.get 0 - local.set 4 - i32.const 0 - local.set 3 - loop ;; label = @3 - local.get 1 - local.get 3 - i32.eq - br_if 1 (;@2;) - local.get 3 - i32.const 1 - i32.add - local.set 3 - local.get 4 - i32.const -1 - i32.add - local.tee 4 - local.get 1 - i32.add - local.tee 7 - i32.load8_u - i32.const 10 - i32.ne - br_if 0 (;@3;) - end - local.get 2 - local.get 0 - local.get 1 - local.get 3 - i32.sub - i32.const 1 - i32.add - local.tee 6 - local.get 2 - i32.load offset=32 - call_indirect (type 0) - local.tee 4 - local.get 6 - i32.lt_u - br_if 1 (;@1;) - local.get 3 - i32.const -1 - i32.add - local.set 1 - local.get 7 - i32.const 1 - i32.add - local.set 0 - local.get 2 - i32.load offset=20 - local.set 5 - end - local.get 5 - local.get 0 - local.get 1 - call $memcpy - drop - local.get 2 - local.get 2 - i32.load offset=20 - local.get 1 - i32.add - i32.store offset=20 - local.get 6 - local.get 1 - i32.add - local.set 4 - end - local.get 4) - (func $fwrite (type 5) (param i32 i32 i32 i32) (result i32) - (local i32 i32 i32 i32 i32 i32) - local.get 2 - local.get 1 - i32.mul - local.set 4 - block ;; label = @1 - block ;; label = @2 - local.get 3 - i32.load offset=16 - local.tee 5 - br_if 0 (;@2;) - i32.const 0 - local.set 6 - local.get 3 - call $__towrite - br_if 1 (;@1;) - local.get 3 - i32.load offset=16 - local.set 5 - end - block ;; label = @2 - local.get 5 - local.get 3 - i32.load offset=20 - local.tee 7 - i32.sub - local.get 4 - i32.ge_u - br_if 0 (;@2;) - local.get 3 - local.get 0 - local.get 4 - local.get 3 - i32.load offset=32 - call_indirect (type 0) - local.set 6 - br 1 (;@1;) - end - i32.const 0 - local.set 8 - block ;; label = @2 - block ;; label = @3 - local.get 3 - i32.load offset=64 - i32.const 0 - i32.ge_s - br_if 0 (;@3;) - local.get 4 - local.set 5 - br 1 (;@2;) - end - local.get 0 - local.get 4 - i32.add - local.set 6 - i32.const 0 - local.set 8 - i32.const 0 - local.set 5 - loop ;; label = @3 - block ;; label = @4 - local.get 4 - local.get 5 - i32.add - br_if 0 (;@4;) - local.get 4 - local.set 5 - br 2 (;@2;) - end - local.get 5 - i32.const -1 - i32.add - local.tee 5 - local.get 6 - i32.add - local.tee 9 - i32.load8_u - i32.const 10 - i32.ne - br_if 0 (;@3;) - end - local.get 3 - local.get 0 - local.get 4 - local.get 5 - i32.add - i32.const 1 - i32.add - local.tee 8 - local.get 3 - i32.load offset=32 - call_indirect (type 0) - local.tee 6 - local.get 8 - i32.lt_u - br_if 1 (;@1;) - local.get 5 - i32.const -1 - i32.xor - local.set 5 - local.get 9 - i32.const 1 - i32.add - local.set 0 - local.get 3 - i32.load offset=20 - local.set 7 - end - local.get 7 - local.get 0 - local.get 5 - call $memcpy - drop - local.get 3 - local.get 3 - i32.load offset=20 - local.get 5 - i32.add - i32.store offset=20 - local.get 8 - local.get 5 - i32.add - local.set 6 - end - block ;; label = @1 - local.get 6 - local.get 4 - i32.ne - br_if 0 (;@1;) - local.get 2 - i32.const 0 - local.get 1 - select - return - end - local.get 6 - local.get 1 - i32.div_u) - (func $dummy.1 (type 3) (param i32 i32) (result i32) - local.get 0) - (func $__lctrans (type 3) (param i32 i32) (result i32) - local.get 0 - local.get 1 - call $dummy.1) - (func $strerror (type 2) (param i32) (result i32) - (local i32) - block ;; label = @1 - i32.const 0 - i32.load offset=5304 - local.tee 1 - br_if 0 (;@1;) - i32.const 5280 - local.set 1 - i32.const 0 - i32.const 5280 - i32.store offset=5304 - end - i32.const 0 - local.get 0 - local.get 0 - i32.const 76 - i32.gt_u - select - i32.const 1 - i32.shl - i32.const 2848 - i32.add - i32.load16_u - i32.const 1291 - i32.add - local.get 1 - i32.load offset=20 - call $__lctrans) - (func $wcrtomb (type 0) (param i32 i32 i32) (result i32) - (local i32) - i32.const 1 - local.set 3 - block ;; label = @1 - local.get 0 - i32.eqz - br_if 0 (;@1;) - block ;; label = @2 - local.get 1 - i32.const 127 - i32.gt_u - br_if 0 (;@2;) - local.get 0 - local.get 1 - i32.store8 - i32.const 1 - return - end - block ;; label = @2 - block ;; label = @3 - i32.const 0 - i32.load offset=5280 - br_if 0 (;@3;) - block ;; label = @4 - local.get 1 - i32.const -128 - i32.and - i32.const 57216 - i32.eq - br_if 0 (;@4;) - i32.const 0 - i32.const 25 - i32.store offset=4228 - br 2 (;@2;) - end - local.get 0 - local.get 1 - i32.store8 - i32.const 1 - return - end - block ;; label = @3 - local.get 1 - i32.const 2047 - i32.gt_u - br_if 0 (;@3;) - local.get 0 - local.get 1 - i32.const 63 - i32.and - i32.const 128 - i32.or - i32.store8 offset=1 - local.get 0 - local.get 1 - i32.const 6 - i32.shr_u - i32.const 192 - i32.or - i32.store8 - i32.const 2 - return - end - block ;; label = @3 - block ;; label = @4 - local.get 1 - i32.const 55296 - i32.lt_u - br_if 0 (;@4;) - local.get 1 - i32.const -8192 - i32.and - i32.const 57344 - i32.ne - br_if 1 (;@3;) - end - local.get 0 - local.get 1 - i32.const 63 - i32.and - i32.const 128 - i32.or - i32.store8 offset=2 - local.get 0 - local.get 1 - i32.const 12 - i32.shr_u - i32.const 224 - i32.or - i32.store8 - local.get 0 - local.get 1 - i32.const 6 - i32.shr_u - i32.const 63 - i32.and - i32.const 128 - i32.or - i32.store8 offset=1 - i32.const 3 - return - end - block ;; label = @3 - local.get 1 - i32.const -65536 - i32.add - i32.const 1048575 - i32.gt_u - br_if 0 (;@3;) - local.get 0 - local.get 1 - i32.const 63 - i32.and - i32.const 128 - i32.or - i32.store8 offset=3 - local.get 0 - local.get 1 - i32.const 18 - i32.shr_u - i32.const 240 - i32.or - i32.store8 - local.get 0 - local.get 1 - i32.const 6 - i32.shr_u - i32.const 63 - i32.and - i32.const 128 - i32.or - i32.store8 offset=2 - local.get 0 - local.get 1 - i32.const 12 - i32.shr_u - i32.const 63 - i32.and - i32.const 128 - i32.or - i32.store8 offset=1 - i32.const 4 - return - end - i32.const 0 - i32.const 25 - i32.store offset=4228 - end - i32.const -1 - local.set 3 - end - local.get 3) - (func $wctomb (type 3) (param i32 i32) (result i32) - block ;; label = @1 - local.get 0 - br_if 0 (;@1;) - i32.const 0 - return - end - local.get 0 - local.get 1 - i32.const 0 - call $wcrtomb) - (func $frexp (type 9) (param f64 i32) (result f64) - (local i64 i32) - block ;; label = @1 - local.get 0 - i64.reinterpret_f64 - local.tee 2 - i64.const 52 - i64.shr_u - i32.wrap_i64 - i32.const 2047 - i32.and - local.tee 3 - i32.const 2047 - i32.eq - br_if 0 (;@1;) - block ;; label = @2 - local.get 3 - br_if 0 (;@2;) - block ;; label = @3 - local.get 0 - f64.const 0x0p+0 (;=0;) - f64.ne - br_if 0 (;@3;) - local.get 1 - i32.const 0 - i32.store - local.get 0 - return - end - local.get 0 - f64.const 0x1p+64 (;=1.84467e+19;) - f64.mul - local.get 1 - call $frexp - local.set 0 - local.get 1 - local.get 1 - i32.load - i32.const -64 - i32.add - i32.store - local.get 0 - return - end - local.get 1 - local.get 3 - i32.const -1022 - i32.add - i32.store - local.get 2 - i64.const -9218868437227405313 - i64.and - i64.const 4602678819172646912 - i64.or - f64.reinterpret_i64 - local.set 0 - end - local.get 0) - (func $fputs (type 3) (param i32 i32) (result i32) - (local i32) - local.get 0 - call $strlen - local.set 2 - i32.const -1 - i32.const 0 - local.get 2 - local.get 0 - i32.const 1 - local.get 2 - local.get 1 - call $fwrite - i32.ne - select) - (func $vfprintf (type 0) (param i32 i32 i32) (result i32) - (local i32 i32 i32) - global.get $__stack_pointer - i32.const 208 - i32.sub - local.tee 3 - global.set $__stack_pointer - local.get 3 - local.get 2 - i32.store offset=204 - local.get 3 - i32.const 160 - i32.add - i32.const 32 - i32.add - i64.const 0 - i64.store - local.get 3 - i32.const 184 - i32.add - i64.const 0 - i64.store - local.get 3 - i32.const 176 - i32.add - i64.const 0 - i64.store - local.get 3 - i64.const 0 - i64.store offset=168 - local.get 3 - i64.const 0 - i64.store offset=160 - local.get 3 - local.get 2 - i32.store offset=200 - block ;; label = @1 - block ;; label = @2 - i32.const 0 - local.get 1 - local.get 3 - i32.const 200 - i32.add - local.get 3 - i32.const 80 - i32.add - local.get 3 - i32.const 160 - i32.add - call $printf_core - i32.const 0 - i32.ge_s - br_if 0 (;@2;) - i32.const -1 - local.set 0 - br 1 (;@1;) - end - local.get 0 - i32.load - local.set 4 - block ;; label = @2 - local.get 0 - i32.load offset=60 - i32.const 0 - i32.gt_s - br_if 0 (;@2;) - local.get 0 - local.get 4 - i32.const -33 - i32.and - i32.store - end - block ;; label = @2 - block ;; label = @3 - block ;; label = @4 - block ;; label = @5 - local.get 0 - i32.load offset=44 - br_if 0 (;@5;) - local.get 0 - i32.const 80 - i32.store offset=44 - local.get 0 - i32.const 0 - i32.store offset=24 - local.get 0 - i64.const 0 - i64.store offset=16 - local.get 0 - i32.load offset=40 - local.set 5 - local.get 0 - local.get 3 - i32.store offset=40 - br 1 (;@4;) - end - i32.const 0 - local.set 5 - local.get 0 - i32.load offset=16 - br_if 1 (;@3;) - end - i32.const -1 - local.set 2 - local.get 0 - call $__towrite - br_if 1 (;@2;) - end - local.get 0 - local.get 1 - local.get 3 - i32.const 200 - i32.add - local.get 3 - i32.const 80 - i32.add - local.get 3 - i32.const 160 - i32.add - call $printf_core - local.set 2 - end - local.get 4 - i32.const 32 - i32.and - local.set 1 - block ;; label = @2 - local.get 5 - i32.eqz - br_if 0 (;@2;) - local.get 0 - i32.const 0 - i32.const 0 - local.get 0 - i32.load offset=32 - call_indirect (type 0) - drop - local.get 0 - i32.const 0 - i32.store offset=44 - local.get 0 - local.get 5 - i32.store offset=40 - local.get 0 - i32.const 0 - i32.store offset=24 - local.get 0 - i32.load offset=20 - local.set 5 - local.get 0 - i64.const 0 - i64.store offset=16 - local.get 2 - i32.const -1 - local.get 5 - select - local.set 2 - end - local.get 0 - local.get 0 - i32.load - local.tee 5 - local.get 1 - i32.or - i32.store - i32.const -1 - local.get 2 - local.get 5 - i32.const 32 - i32.and - select - local.set 0 - end - local.get 3 - i32.const 208 - i32.add - global.set $__stack_pointer - local.get 0) - (func $printf_core (type 10) (param i32 i32 i32 i32 i32) (result i32) - (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i64 i64 f64 i32 i32 i32 i32 i32 i32 i32 i32 f64) - global.get $__stack_pointer - i32.const 880 - i32.sub - local.tee 5 - global.set $__stack_pointer - local.get 5 - i32.const 68 - i32.add - i32.const 12 - i32.add - local.set 6 - i32.const 0 - local.get 5 - i32.const 112 - i32.add - i32.sub - local.set 7 - local.get 5 - i32.const -3988 - i32.add - local.set 8 - local.get 5 - i32.const 55 - i32.add - local.set 9 - local.get 5 - i32.const 80 - i32.add - i32.const -2 - i32.xor - local.set 10 - local.get 5 - i32.const 68 - i32.add - i32.const 11 - i32.add - local.set 11 - local.get 5 - i32.const 80 - i32.add - i32.const 8 - i32.or - local.set 12 - local.get 5 - i32.const 80 - i32.add - i32.const 9 - i32.or - local.set 13 - i32.const -10 - local.get 5 - i32.const 68 - i32.add - i32.sub - local.set 14 - local.get 5 - i32.const 68 - i32.add - i32.const 10 - i32.add - local.set 15 - local.get 5 - i32.const 56 - i32.add - local.set 16 - i32.const 0 - local.set 17 - i32.const 0 - local.set 18 - i32.const 0 - local.set 19 - block ;; label = @1 - block ;; label = @2 - block ;; label = @3 - loop ;; label = @4 - local.get 1 - local.set 20 - local.get 19 - local.get 18 - i32.const 2147483647 - i32.xor - i32.gt_s - br_if 1 (;@3;) - local.get 19 - local.get 18 - i32.add - local.set 18 - block ;; label = @5 - block ;; label = @6 - block ;; label = @7 - block ;; label = @8 - block ;; label = @9 - block ;; label = @10 - block ;; label = @11 - block ;; label = @12 - block ;; label = @13 - local.get 20 - i32.load8_u - local.tee 19 - i32.eqz - br_if 0 (;@13;) - local.get 20 - local.set 1 - loop ;; label = @14 - block ;; label = @15 - block ;; label = @16 - block ;; label = @17 - local.get 19 - i32.const 255 - i32.and - local.tee 19 - i32.eqz - br_if 0 (;@17;) - local.get 19 - i32.const 37 - i32.ne - br_if 2 (;@15;) - local.get 1 - local.set 21 - local.get 1 - local.set 19 - loop ;; label = @18 - block ;; label = @19 - local.get 19 - i32.load8_u offset=1 - i32.const 37 - i32.eq - br_if 0 (;@19;) - local.get 19 - local.set 1 - br 3 (;@16;) - end - local.get 21 - i32.const 1 - i32.add - local.set 21 - local.get 19 - i32.load8_u offset=2 - local.set 22 - local.get 19 - i32.const 2 - i32.add - local.tee 1 - local.set 19 - local.get 22 - i32.const 37 - i32.eq - br_if 0 (;@18;) - br 2 (;@16;) - end - end - local.get 1 - local.set 21 - end - local.get 21 - local.get 20 - i32.sub - local.tee 19 - local.get 18 - i32.const 2147483647 - i32.xor - local.tee 21 - i32.gt_s - br_if 12 (;@3;) - block ;; label = @16 - local.get 0 - i32.eqz - br_if 0 (;@16;) - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@16;) - local.get 20 - local.get 19 - local.get 0 - call $__fwritex - drop - end - local.get 19 - br_if 11 (;@4;) - local.get 1 - i32.const 1 - i32.add - local.set 19 - i32.const -1 - local.set 23 - block ;; label = @16 - local.get 1 - i32.load8_s offset=1 - local.tee 24 - i32.const -48 - i32.add - local.tee 22 - i32.const 9 - i32.gt_u - br_if 0 (;@16;) - local.get 1 - i32.load8_u offset=2 - i32.const 36 - i32.ne - br_if 0 (;@16;) - local.get 1 - i32.const 3 - i32.add - local.set 19 - local.get 1 - i32.load8_s offset=3 - local.set 24 - i32.const 1 - local.set 17 - local.get 22 - local.set 23 - end - i32.const 0 - local.set 25 - block ;; label = @16 - local.get 24 - i32.const -32 - i32.add - local.tee 1 - i32.const 31 - i32.gt_u - br_if 0 (;@16;) - i32.const 1 - local.get 1 - i32.shl - local.tee 1 - i32.const 75913 - i32.and - i32.eqz - br_if 0 (;@16;) - local.get 19 - i32.const 1 - i32.add - local.set 22 - i32.const 0 - local.set 25 - loop ;; label = @17 - local.get 1 - local.get 25 - i32.or - local.set 25 - local.get 22 - local.tee 19 - i32.load8_s - local.tee 24 - i32.const -32 - i32.add - local.tee 1 - i32.const 32 - i32.ge_u - br_if 1 (;@16;) - local.get 19 - i32.const 1 - i32.add - local.set 22 - i32.const 1 - local.get 1 - i32.shl - local.tee 1 - i32.const 75913 - i32.and - br_if 0 (;@17;) - end - end - block ;; label = @16 - local.get 24 - i32.const 42 - i32.ne - br_if 0 (;@16;) - block ;; label = @17 - block ;; label = @18 - local.get 19 - i32.load8_s offset=1 - i32.const -48 - i32.add - local.tee 1 - i32.const 9 - i32.gt_u - br_if 0 (;@18;) - local.get 19 - i32.load8_u offset=2 - i32.const 36 - i32.ne - br_if 0 (;@18;) - local.get 4 - local.get 1 - i32.const 2 - i32.shl - i32.add - i32.const 10 - i32.store - local.get 19 - i32.const 3 - i32.add - local.set 22 - local.get 19 - i32.load8_s offset=1 - i32.const 3 - i32.shl - local.get 3 - i32.add - i32.const -384 - i32.add - i32.load - local.set 26 - i32.const 1 - local.set 17 - br 1 (;@17;) - end - local.get 17 - br_if 6 (;@11;) - local.get 19 - i32.const 1 - i32.add - local.set 22 - block ;; label = @18 - local.get 0 - br_if 0 (;@18;) - i32.const 0 - local.set 17 - i32.const 0 - local.set 26 - br 6 (;@12;) - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 1 - i32.load - local.set 26 - i32.const 0 - local.set 17 - end - local.get 26 - i32.const -1 - i32.gt_s - br_if 4 (;@12;) - i32.const 0 - local.get 26 - i32.sub - local.set 26 - local.get 25 - i32.const 8192 - i32.or - local.set 25 - br 4 (;@12;) - end - i32.const 0 - local.set 26 - block ;; label = @16 - local.get 24 - i32.const -48 - i32.add - local.tee 1 - i32.const 9 - i32.le_u - br_if 0 (;@16;) - local.get 19 - local.set 22 - br 4 (;@12;) - end - i32.const 0 - local.set 26 - loop ;; label = @16 - block ;; label = @17 - local.get 26 - i32.const 214748364 - i32.gt_u - br_if 0 (;@17;) - i32.const -1 - local.get 26 - i32.const 10 - i32.mul - local.tee 22 - local.get 1 - i32.add - local.get 1 - local.get 22 - i32.const 2147483647 - i32.xor - i32.gt_u - select - local.set 26 - local.get 19 - i32.load8_s offset=1 - local.set 1 - local.get 19 - i32.const 1 - i32.add - local.tee 22 - local.set 19 - local.get 1 - i32.const -48 - i32.add - local.tee 1 - i32.const 10 - i32.lt_u - br_if 1 (;@16;) - local.get 26 - i32.const 0 - i32.lt_s - br_if 14 (;@3;) - br 5 (;@12;) - end - local.get 19 - i32.load8_s offset=1 - local.set 1 - i32.const -1 - local.set 26 - local.get 19 - i32.const 1 - i32.add - local.set 19 - local.get 1 - i32.const -48 - i32.add - local.tee 1 - i32.const 10 - i32.lt_u - br_if 0 (;@16;) - br 13 (;@3;) - end - end - local.get 1 - i32.load8_u offset=1 - local.set 19 - local.get 1 - i32.const 1 - i32.add - local.set 1 - br 0 (;@14;) - end - end - local.get 0 - br_if 11 (;@1;) - block ;; label = @13 - local.get 17 - br_if 0 (;@13;) - i32.const 0 - local.set 18 - br 12 (;@1;) - end - block ;; label = @13 - block ;; label = @14 - local.get 4 - i32.load offset=4 - local.tee 1 - br_if 0 (;@14;) - i32.const 1 - local.set 1 - br 1 (;@13;) - end - local.get 3 - i32.const 8 - i32.add - local.get 1 - local.get 2 - call $pop_arg - block ;; label = @14 - local.get 4 - i32.load offset=8 - local.tee 1 - br_if 0 (;@14;) - i32.const 2 - local.set 1 - br 1 (;@13;) - end - local.get 3 - i32.const 16 - i32.add - local.get 1 - local.get 2 - call $pop_arg - block ;; label = @14 - local.get 4 - i32.load offset=12 - local.tee 1 - br_if 0 (;@14;) - i32.const 3 - local.set 1 - br 1 (;@13;) - end - local.get 3 - i32.const 24 - i32.add - local.get 1 - local.get 2 - call $pop_arg - block ;; label = @14 - local.get 4 - i32.load offset=16 - local.tee 1 - br_if 0 (;@14;) - i32.const 4 - local.set 1 - br 1 (;@13;) - end - local.get 3 - i32.const 32 - i32.add - local.get 1 - local.get 2 - call $pop_arg - block ;; label = @14 - local.get 4 - i32.load offset=20 - local.tee 1 - br_if 0 (;@14;) - i32.const 5 - local.set 1 - br 1 (;@13;) - end - local.get 3 - i32.const 40 - i32.add - local.get 1 - local.get 2 - call $pop_arg - block ;; label = @14 - local.get 4 - i32.load offset=24 - local.tee 1 - br_if 0 (;@14;) - i32.const 6 - local.set 1 - br 1 (;@13;) - end - local.get 3 - i32.const 48 - i32.add - local.get 1 - local.get 2 - call $pop_arg - block ;; label = @14 - local.get 4 - i32.load offset=28 - local.tee 1 - br_if 0 (;@14;) - i32.const 7 - local.set 1 - br 1 (;@13;) - end - local.get 3 - i32.const 56 - i32.add - local.get 1 - local.get 2 - call $pop_arg - block ;; label = @14 - local.get 4 - i32.load offset=32 - local.tee 1 - br_if 0 (;@14;) - i32.const 8 - local.set 1 - br 1 (;@13;) - end - local.get 3 - i32.const 64 - i32.add - local.get 1 - local.get 2 - call $pop_arg - block ;; label = @14 - local.get 4 - i32.load offset=36 - local.tee 1 - br_if 0 (;@14;) - i32.const 9 - local.set 1 - br 1 (;@13;) - end - local.get 3 - i32.const 72 - i32.add - local.get 1 - local.get 2 - call $pop_arg - i32.const 1 - local.set 18 - br 12 (;@1;) - end - local.get 1 - i32.const 2 - i32.shl - local.set 1 - loop ;; label = @13 - local.get 4 - local.get 1 - i32.add - i32.load - br_if 2 (;@11;) - local.get 1 - i32.const 4 - i32.add - local.tee 1 - i32.const 40 - i32.ne - br_if 0 (;@13;) - end - i32.const 1 - local.set 18 - br 11 (;@1;) - end - i32.const 0 - local.set 19 - i32.const -1 - local.set 24 - block ;; label = @12 - block ;; label = @13 - local.get 22 - i32.load8_u - i32.const 46 - i32.eq - br_if 0 (;@13;) - local.get 22 - local.set 1 - i32.const 0 - local.set 27 - br 1 (;@12;) - end - block ;; label = @13 - local.get 22 - i32.load8_s offset=1 - local.tee 24 - i32.const 42 - i32.ne - br_if 0 (;@13;) - block ;; label = @14 - block ;; label = @15 - local.get 22 - i32.load8_s offset=2 - i32.const -48 - i32.add - local.tee 1 - i32.const 9 - i32.gt_u - br_if 0 (;@15;) - local.get 22 - i32.load8_u offset=3 - i32.const 36 - i32.ne - br_if 0 (;@15;) - local.get 4 - local.get 1 - i32.const 2 - i32.shl - i32.add - i32.const 10 - i32.store - local.get 22 - i32.const 4 - i32.add - local.set 1 - local.get 22 - i32.load8_s offset=2 - i32.const 3 - i32.shl - local.get 3 - i32.add - i32.const -384 - i32.add - i32.load - local.set 24 - br 1 (;@14;) - end - local.get 17 - br_if 3 (;@11;) - local.get 22 - i32.const 2 - i32.add - local.set 1 - block ;; label = @15 - local.get 0 - br_if 0 (;@15;) - i32.const 0 - local.set 24 - br 1 (;@14;) - end - local.get 2 - local.get 2 - i32.load - local.tee 22 - i32.const 4 - i32.add - i32.store - local.get 22 - i32.load - local.set 24 - end - local.get 24 - i32.const -1 - i32.xor - i32.const 31 - i32.shr_u - local.set 27 - br 1 (;@12;) - end - local.get 22 - i32.const 1 - i32.add - local.set 1 - block ;; label = @13 - local.get 24 - i32.const -48 - i32.add - local.tee 28 - i32.const 9 - i32.le_u - br_if 0 (;@13;) - i32.const 1 - local.set 27 - i32.const 0 - local.set 24 - br 1 (;@12;) - end - i32.const 0 - local.set 29 - local.get 1 - local.set 22 - loop ;; label = @13 - i32.const -1 - local.set 24 - block ;; label = @14 - local.get 29 - i32.const 214748364 - i32.gt_u - br_if 0 (;@14;) - i32.const -1 - local.get 29 - i32.const 10 - i32.mul - local.tee 1 - local.get 28 - i32.add - local.get 28 - local.get 1 - i32.const 2147483647 - i32.xor - i32.gt_u - select - local.set 24 - end - i32.const 1 - local.set 27 - local.get 22 - i32.load8_s offset=1 - local.set 28 - local.get 24 - local.set 29 - local.get 22 - i32.const 1 - i32.add - local.tee 1 - local.set 22 - local.get 28 - i32.const -48 - i32.add - local.tee 28 - i32.const 10 - i32.lt_u - br_if 0 (;@13;) - end - end - loop ;; label = @12 - local.get 19 - local.set 22 - local.get 1 - i32.load8_s - local.tee 19 - i32.const -123 - i32.add - i32.const -58 - i32.lt_u - br_if 1 (;@11;) - local.get 1 - i32.const 1 - i32.add - local.set 1 - local.get 19 - local.get 22 - i32.const 58 - i32.mul - i32.add - i32.const 2943 - i32.add - i32.load8_u - local.tee 19 - i32.const -1 - i32.add - i32.const 8 - i32.lt_u - br_if 0 (;@12;) - end - block ;; label = @12 - block ;; label = @13 - block ;; label = @14 - local.get 19 - i32.const 27 - i32.eq - br_if 0 (;@14;) - local.get 19 - i32.eqz - br_if 3 (;@11;) - block ;; label = @15 - local.get 23 - i32.const 0 - i32.lt_s - br_if 0 (;@15;) - local.get 4 - local.get 23 - i32.const 2 - i32.shl - i32.add - local.get 19 - i32.store - local.get 5 - local.get 3 - local.get 23 - i32.const 3 - i32.shl - i32.add - i64.load - i64.store offset=56 - br 2 (;@13;) - end - block ;; label = @15 - local.get 0 - br_if 0 (;@15;) - i32.const 0 - local.set 18 - br 14 (;@1;) - end - local.get 5 - i32.const 56 - i32.add - local.get 19 - local.get 2 - call $pop_arg - br 2 (;@12;) - end - local.get 23 - i32.const -1 - i32.gt_s - br_if 2 (;@11;) - end - i32.const 0 - local.set 19 - local.get 0 - i32.eqz - br_if 8 (;@4;) - end - local.get 25 - i32.const -65537 - i32.and - local.tee 29 - local.get 25 - local.get 25 - i32.const 8192 - i32.and - select - local.set 30 - block ;; label = @12 - block ;; label = @13 - block ;; label = @14 - block ;; label = @15 - block ;; label = @16 - block ;; label = @17 - block ;; label = @18 - block ;; label = @19 - block ;; label = @20 - block ;; label = @21 - block ;; label = @22 - block ;; label = @23 - block ;; label = @24 - block ;; label = @25 - block ;; label = @26 - block ;; label = @27 - block ;; label = @28 - local.get 1 - i32.const -1 - i32.add - i32.load8_s - local.tee 19 - i32.const -33 - i32.and - local.get 19 - local.get 19 - i32.const 15 - i32.and - i32.const 3 - i32.eq - select - local.get 19 - local.get 22 - select - local.tee 31 - i32.const -65 - i32.add - br_table 16 (;@12;) 18 (;@10;) 13 (;@15;) 18 (;@10;) 16 (;@12;) 16 (;@12;) 16 (;@12;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 12 (;@16;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 3 (;@25;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 16 (;@12;) 18 (;@10;) 8 (;@20;) 5 (;@23;) 16 (;@12;) 16 (;@12;) 16 (;@12;) 18 (;@10;) 5 (;@23;) 18 (;@10;) 18 (;@10;) 18 (;@10;) 9 (;@19;) 1 (;@27;) 4 (;@24;) 2 (;@26;) 18 (;@10;) 18 (;@10;) 10 (;@18;) 18 (;@10;) 0 (;@28;) 18 (;@10;) 18 (;@10;) 3 (;@25;) 18 (;@10;) - end - i32.const 0 - local.set 28 - i32.const 1024 - local.set 23 - local.get 5 - i64.load offset=56 - local.set 32 - br 5 (;@22;) - end - i32.const 0 - local.set 19 - block ;; label = @27 - block ;; label = @28 - block ;; label = @29 - block ;; label = @30 - block ;; label = @31 - block ;; label = @32 - block ;; label = @33 - local.get 22 - i32.const 255 - i32.and - br_table 0 (;@33;) 1 (;@32;) 2 (;@31;) 3 (;@30;) 4 (;@29;) 29 (;@4;) 5 (;@28;) 6 (;@27;) 29 (;@4;) - end - local.get 5 - i32.load offset=56 - local.get 18 - i32.store - br 28 (;@4;) - end - local.get 5 - i32.load offset=56 - local.get 18 - i32.store - br 27 (;@4;) - end - local.get 5 - i32.load offset=56 - local.get 18 - i64.extend_i32_s - i64.store - br 26 (;@4;) - end - local.get 5 - i32.load offset=56 - local.get 18 - i32.store16 - br 25 (;@4;) - end - local.get 5 - i32.load offset=56 - local.get 18 - i32.store8 - br 24 (;@4;) - end - local.get 5 - i32.load offset=56 - local.get 18 - i32.store - br 23 (;@4;) - end - local.get 5 - i32.load offset=56 - local.get 18 - i64.extend_i32_s - i64.store - br 22 (;@4;) - end - local.get 24 - i32.const 8 - local.get 24 - i32.const 8 - i32.gt_u - select - local.set 24 - local.get 30 - i32.const 8 - i32.or - local.set 30 - i32.const 120 - local.set 31 - end - i32.const 0 - local.set 28 - i32.const 1024 - local.set 23 - block ;; label = @25 - local.get 5 - i64.load offset=56 - local.tee 32 - i64.eqz - i32.eqz - br_if 0 (;@25;) - local.get 16 - local.set 20 - br 4 (;@21;) - end - local.get 31 - i32.const 32 - i32.and - local.set 22 - local.get 16 - local.set 20 - loop ;; label = @25 - local.get 20 - i32.const -1 - i32.add - local.tee 20 - local.get 32 - i32.wrap_i64 - i32.const 15 - i32.and - i32.const 3472 - i32.add - i32.load8_u - local.get 22 - i32.or - i32.store8 - local.get 32 - i64.const 15 - i64.gt_u - local.set 19 - local.get 32 - i64.const 4 - i64.shr_u - local.set 32 - local.get 19 - br_if 0 (;@25;) - end - local.get 30 - i32.const 8 - i32.and - i32.eqz - br_if 3 (;@21;) - local.get 31 - i32.const 4 - i32.shr_s - i32.const 1024 - i32.add - local.set 23 - i32.const 2 - local.set 28 - br 3 (;@21;) - end - local.get 16 - local.set 20 - block ;; label = @24 - local.get 5 - i64.load offset=56 - local.tee 32 - i64.eqz - br_if 0 (;@24;) - local.get 16 - local.set 20 - loop ;; label = @25 - local.get 20 - i32.const -1 - i32.add - local.tee 20 - local.get 32 - i32.wrap_i64 - i32.const 7 - i32.and - i32.const 48 - i32.or - i32.store8 - local.get 32 - i64.const 7 - i64.gt_u - local.set 19 - local.get 32 - i64.const 3 - i64.shr_u - local.set 32 - local.get 19 - br_if 0 (;@25;) - end - end - i32.const 0 - local.set 28 - i32.const 1024 - local.set 23 - local.get 30 - i32.const 8 - i32.and - i32.eqz - br_if 2 (;@21;) - local.get 24 - local.get 16 - local.get 20 - i32.sub - local.tee 19 - i32.const 1 - i32.add - local.get 24 - local.get 19 - i32.gt_s - select - local.set 24 - br 2 (;@21;) - end - block ;; label = @23 - local.get 5 - i64.load offset=56 - local.tee 32 - i64.const -1 - i64.gt_s - br_if 0 (;@23;) - local.get 5 - i64.const 0 - local.get 32 - i64.sub - local.tee 32 - i64.store offset=56 - i32.const 1 - local.set 28 - i32.const 1024 - local.set 23 - br 1 (;@22;) - end - block ;; label = @23 - local.get 30 - i32.const 2048 - i32.and - i32.eqz - br_if 0 (;@23;) - i32.const 1 - local.set 28 - i32.const 1025 - local.set 23 - br 1 (;@22;) - end - i32.const 1026 - i32.const 1024 - local.get 30 - i32.const 1 - i32.and - local.tee 28 - select - local.set 23 - end - block ;; label = @22 - block ;; label = @23 - local.get 32 - i64.const 4294967296 - i64.ge_u - br_if 0 (;@23;) - local.get 32 - local.set 33 - local.get 16 - local.set 20 - br 1 (;@22;) - end - local.get 16 - local.set 20 - loop ;; label = @23 - local.get 20 - i32.const -1 - i32.add - local.tee 20 - local.get 32 - local.get 32 - i64.const 10 - i64.div_u - local.tee 33 - i64.const 10 - i64.mul - i64.sub - i32.wrap_i64 - i32.const 48 - i32.or - i32.store8 - local.get 32 - i64.const 42949672959 - i64.gt_u - local.set 19 - local.get 33 - local.set 32 - local.get 19 - br_if 0 (;@23;) - end - end - local.get 33 - i32.wrap_i64 - local.tee 19 - i32.eqz - br_if 0 (;@21;) - loop ;; label = @22 - local.get 20 - i32.const -1 - i32.add - local.tee 20 - local.get 19 - local.get 19 - i32.const 10 - i32.div_u - local.tee 22 - i32.const 10 - i32.mul - i32.sub - i32.const 48 - i32.or - i32.store8 - local.get 19 - i32.const 9 - i32.gt_u - local.set 25 - local.get 22 - local.set 19 - local.get 25 - br_if 0 (;@22;) - end - end - block ;; label = @21 - local.get 27 - i32.eqz - br_if 0 (;@21;) - local.get 24 - i32.const 0 - i32.lt_s - br_if 18 (;@3;) - end - local.get 30 - i32.const -65537 - i32.and - local.get 30 - local.get 27 - select - local.set 29 - block ;; label = @21 - local.get 5 - i64.load offset=56 - local.tee 32 - i64.const 0 - i64.ne - br_if 0 (;@21;) - i32.const 0 - local.set 25 - local.get 24 - br_if 0 (;@21;) - local.get 16 - local.set 20 - local.get 16 - local.set 19 - br 12 (;@9;) - end - local.get 24 - local.get 16 - local.get 20 - i32.sub - local.get 32 - i64.eqz - i32.add - local.tee 19 - local.get 24 - local.get 19 - i32.gt_s - select - local.set 25 - local.get 16 - local.set 19 - br 11 (;@9;) - end - local.get 5 - local.get 5 - i64.load offset=56 - i64.store8 offset=55 - i32.const 0 - local.set 28 - i32.const 1024 - local.set 23 - i32.const 1 - local.set 25 - local.get 9 - local.set 20 - local.get 16 - local.set 19 - br 10 (;@9;) - end - i32.const 4228 - i32.load - call $strerror - local.set 20 - br 1 (;@17;) - end - local.get 5 - i32.load offset=56 - local.tee 19 - i32.const 1071 - local.get 19 - select - local.set 20 - end - local.get 20 - local.get 20 - local.get 24 - i32.const 2147483647 - local.get 24 - i32.const 2147483647 - i32.lt_u - select - call $strnlen - local.tee 25 - i32.add - local.set 19 - i32.const 0 - local.set 28 - i32.const 1024 - local.set 23 - local.get 24 - i32.const -1 - i32.gt_s - br_if 7 (;@9;) - local.get 19 - i32.load8_u - i32.eqz - br_if 7 (;@9;) - br 13 (;@3;) - end - local.get 5 - i32.load offset=56 - local.set 20 - local.get 24 - br_if 1 (;@14;) - i32.const 0 - local.set 19 - br 2 (;@13;) - end - local.get 5 - i32.const 0 - i32.store offset=12 - local.get 5 - local.get 5 - i64.load offset=56 - i64.store32 offset=8 - local.get 5 - local.get 5 - i32.const 8 - i32.add - i32.store offset=56 - local.get 5 - i32.const 8 - i32.add - local.set 20 - i32.const -1 - local.set 24 - end - i32.const 0 - local.set 19 - local.get 20 - local.set 21 - block ;; label = @14 - loop ;; label = @15 - local.get 21 - i32.load - local.tee 22 - i32.eqz - br_if 1 (;@14;) - block ;; label = @16 - local.get 5 - i32.const 4 - i32.add - local.get 22 - call $wctomb - local.tee 22 - i32.const 0 - i32.lt_s - local.tee 25 - br_if 0 (;@16;) - local.get 22 - local.get 24 - local.get 19 - i32.sub - i32.gt_u - br_if 0 (;@16;) - local.get 21 - i32.const 4 - i32.add - local.set 21 - local.get 24 - local.get 22 - local.get 19 - i32.add - local.tee 19 - i32.gt_u - br_if 1 (;@15;) - br 2 (;@14;) - end - end - local.get 25 - br_if 12 (;@2;) - end - local.get 19 - i32.const 0 - i32.lt_s - br_if 10 (;@3;) - end - block ;; label = @13 - local.get 30 - i32.const 73728 - i32.and - local.tee 25 - br_if 0 (;@13;) - local.get 26 - local.get 19 - i32.le_s - br_if 0 (;@13;) - local.get 5 - i32.const 112 - i32.add - i32.const 32 - local.get 26 - local.get 19 - i32.sub - local.tee 21 - i32.const 256 - local.get 21 - i32.const 256 - i32.lt_u - local.tee 22 - select - call $memset - drop - block ;; label = @14 - local.get 22 - br_if 0 (;@14;) - loop ;; label = @15 - block ;; label = @16 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@16;) - local.get 5 - i32.const 112 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 21 - i32.const -256 - i32.add - local.tee 21 - i32.const 255 - i32.gt_u - br_if 0 (;@15;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@13;) - local.get 5 - i32.const 112 - i32.add - local.get 21 - local.get 0 - call $__fwritex - drop - end - block ;; label = @13 - local.get 19 - i32.eqz - br_if 0 (;@13;) - i32.const 0 - local.set 21 - loop ;; label = @14 - local.get 20 - i32.load - local.tee 22 - i32.eqz - br_if 1 (;@13;) - local.get 5 - i32.const 4 - i32.add - local.get 22 - call $wctomb - local.tee 22 - local.get 21 - i32.add - local.tee 21 - local.get 19 - i32.gt_u - br_if 1 (;@13;) - block ;; label = @15 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@15;) - local.get 5 - i32.const 4 - i32.add - local.get 22 - local.get 0 - call $__fwritex - drop - end - local.get 20 - i32.const 4 - i32.add - local.set 20 - local.get 21 - local.get 19 - i32.lt_u - br_if 0 (;@14;) - end - end - block ;; label = @13 - local.get 25 - i32.const 8192 - i32.ne - br_if 0 (;@13;) - local.get 26 - local.get 19 - i32.le_s - br_if 0 (;@13;) - local.get 5 - i32.const 112 - i32.add - i32.const 32 - local.get 26 - local.get 19 - i32.sub - local.tee 21 - i32.const 256 - local.get 21 - i32.const 256 - i32.lt_u - local.tee 22 - select - call $memset - drop - block ;; label = @14 - local.get 22 - br_if 0 (;@14;) - loop ;; label = @15 - block ;; label = @16 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@16;) - local.get 5 - i32.const 112 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 21 - i32.const -256 - i32.add - local.tee 21 - i32.const 255 - i32.gt_u - br_if 0 (;@15;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@13;) - local.get 5 - i32.const 112 - i32.add - local.get 21 - local.get 0 - call $__fwritex - drop - end - local.get 26 - local.get 19 - local.get 26 - local.get 19 - i32.gt_s - select - local.set 19 - br 8 (;@4;) - end - block ;; label = @12 - local.get 27 - i32.eqz - br_if 0 (;@12;) - local.get 24 - i32.const 0 - i32.lt_s - br_if 9 (;@3;) - end - local.get 5 - f64.load offset=56 - local.set 34 - local.get 5 - i32.const 0 - i32.store offset=108 - block ;; label = @12 - block ;; label = @13 - local.get 34 - i64.reinterpret_f64 - i64.const -1 - i64.gt_s - br_if 0 (;@13;) - local.get 34 - f64.neg - local.set 34 - i32.const 1 - local.set 35 - i32.const 0 - local.set 36 - i32.const 1034 - local.set 37 - br 1 (;@12;) - end - block ;; label = @13 - local.get 30 - i32.const 2048 - i32.and - i32.eqz - br_if 0 (;@13;) - i32.const 1 - local.set 35 - i32.const 0 - local.set 36 - i32.const 1037 - local.set 37 - br 1 (;@12;) - end - i32.const 1040 - i32.const 1035 - local.get 30 - i32.const 1 - i32.and - local.tee 35 - select - local.set 37 - local.get 35 - i32.eqz - local.set 36 - end - block ;; label = @12 - local.get 34 - f64.abs - f64.const inf (;=inf;) - f64.lt - br_if 0 (;@12;) - local.get 35 - i32.const 3 - i32.add - local.set 21 - block ;; label = @13 - local.get 30 - i32.const 8192 - i32.and - br_if 0 (;@13;) - local.get 26 - local.get 21 - i32.le_s - br_if 0 (;@13;) - local.get 5 - i32.const 624 - i32.add - i32.const 32 - local.get 26 - local.get 21 - i32.sub - local.tee 19 - i32.const 256 - local.get 19 - i32.const 256 - i32.lt_u - local.tee 22 - select - call $memset - drop - block ;; label = @14 - local.get 22 - br_if 0 (;@14;) - loop ;; label = @15 - block ;; label = @16 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@16;) - local.get 5 - i32.const 624 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const -256 - i32.add - local.tee 19 - i32.const 255 - i32.gt_u - br_if 0 (;@15;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@13;) - local.get 5 - i32.const 624 - i32.add - local.get 19 - local.get 0 - call $__fwritex - drop - end - block ;; label = @13 - local.get 0 - i32.load - local.tee 19 - i32.const 32 - i32.and - br_if 0 (;@13;) - local.get 37 - local.get 35 - local.get 0 - call $__fwritex - drop - local.get 0 - i32.load - local.set 19 - end - block ;; label = @13 - local.get 19 - i32.const 32 - i32.and - br_if 0 (;@13;) - i32.const 1053 - i32.const 1061 - local.get 31 - i32.const 32 - i32.and - local.tee 19 - select - i32.const 1057 - i32.const 1065 - local.get 19 - select - local.get 34 - local.get 34 - f64.ne - select - i32.const 3 - local.get 0 - call $__fwritex - drop - end - block ;; label = @13 - local.get 30 - i32.const 73728 - i32.and - i32.const 8192 - i32.ne - br_if 0 (;@13;) - local.get 26 - local.get 21 - i32.le_s - br_if 0 (;@13;) - local.get 5 - i32.const 624 - i32.add - i32.const 32 - local.get 26 - local.get 21 - i32.sub - local.tee 19 - i32.const 256 - local.get 19 - i32.const 256 - i32.lt_u - local.tee 22 - select - call $memset - drop - block ;; label = @14 - local.get 22 - br_if 0 (;@14;) - loop ;; label = @15 - block ;; label = @16 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@16;) - local.get 5 - i32.const 624 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const -256 - i32.add - local.tee 19 - i32.const 255 - i32.gt_u - br_if 0 (;@15;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@13;) - local.get 5 - i32.const 624 - i32.add - local.get 19 - local.get 0 - call $__fwritex - drop - end - local.get 21 - local.get 26 - local.get 21 - local.get 26 - i32.gt_s - select - local.set 19 - br 8 (;@4;) - end - block ;; label = @12 - block ;; label = @13 - block ;; label = @14 - local.get 34 - local.get 5 - i32.const 108 - i32.add - call $frexp - local.tee 34 - local.get 34 - f64.add - local.tee 34 - f64.const 0x0p+0 (;=0;) - f64.eq - br_if 0 (;@14;) - local.get 5 - local.get 5 - i32.load offset=108 - local.tee 19 - i32.const -1 - i32.add - i32.store offset=108 - local.get 31 - i32.const 32 - i32.or - local.tee 38 - i32.const 97 - i32.ne - br_if 1 (;@13;) - br 8 (;@6;) - end - local.get 31 - i32.const 32 - i32.or - local.tee 38 - i32.const 97 - i32.eq - br_if 7 (;@6;) - i32.const 6 - local.get 24 - local.get 24 - i32.const 0 - i32.lt_s - select - local.set 27 - local.get 5 - i32.load offset=108 - local.set 20 - br 1 (;@12;) - end - local.get 5 - local.get 19 - i32.const -29 - i32.add - local.tee 20 - i32.store offset=108 - i32.const 6 - local.get 24 - local.get 24 - i32.const 0 - i32.lt_s - select - local.set 27 - local.get 34 - f64.const 0x1p+28 (;=2.68435e+08;) - f64.mul - local.set 34 - end - local.get 5 - i32.const 112 - i32.add - i32.const 0 - i32.const 72 - local.get 20 - i32.const 0 - i32.lt_s - local.tee 39 - select - i32.const 2 - i32.shl - local.tee 40 - i32.add - local.tee 23 - local.set 21 - loop ;; label = @12 - block ;; label = @13 - block ;; label = @14 - local.get 34 - f64.const 0x1p+32 (;=4.29497e+09;) - f64.lt - local.get 34 - f64.const 0x0p+0 (;=0;) - f64.ge - i32.and - i32.eqz - br_if 0 (;@14;) - local.get 34 - i32.trunc_f64_u - local.set 19 - br 1 (;@13;) - end - i32.const 0 - local.set 19 - end - local.get 21 - local.get 19 - i32.store - local.get 21 - i32.const 4 - i32.add - local.set 21 - local.get 34 - local.get 19 - f64.convert_i32_u - f64.sub - f64.const 0x1.dcd65p+29 (;=1e+09;) - f64.mul - local.tee 34 - f64.const 0x0p+0 (;=0;) - f64.ne - br_if 0 (;@12;) - end - block ;; label = @12 - block ;; label = @13 - local.get 20 - i32.const 1 - i32.ge_s - br_if 0 (;@13;) - local.get 21 - local.set 19 - local.get 23 - local.set 22 - br 1 (;@12;) - end - local.get 23 - local.set 22 - loop ;; label = @13 - local.get 20 - i32.const 29 - local.get 20 - i32.const 29 - i32.lt_s - select - local.set 20 - block ;; label = @14 - local.get 21 - i32.const -4 - i32.add - local.tee 19 - local.get 22 - i32.lt_u - br_if 0 (;@14;) - local.get 20 - i64.extend_i32_u - local.set 33 - i64.const 0 - local.set 32 - loop ;; label = @15 - local.get 19 - local.get 19 - i64.load32_u - local.get 33 - i64.shl - local.get 32 - i64.const 4294967295 - i64.and - i64.add - local.tee 32 - local.get 32 - i64.const 1000000000 - i64.div_u - local.tee 32 - i64.const 1000000000 - i64.mul - i64.sub - i64.store32 - local.get 19 - i32.const -4 - i32.add - local.tee 19 - local.get 22 - i32.ge_u - br_if 0 (;@15;) - end - local.get 32 - i32.wrap_i64 - local.tee 19 - i32.eqz - br_if 0 (;@14;) - local.get 22 - i32.const -4 - i32.add - local.tee 22 - local.get 19 - i32.store - end - block ;; label = @14 - loop ;; label = @15 - local.get 21 - local.tee 19 - local.get 22 - i32.le_u - br_if 1 (;@14;) - local.get 19 - i32.const -4 - i32.add - local.tee 21 - i32.load - i32.eqz - br_if 0 (;@15;) - end - end - local.get 5 - local.get 5 - i32.load offset=108 - local.get 20 - i32.sub - local.tee 20 - i32.store offset=108 - local.get 19 - local.set 21 - local.get 20 - i32.const 0 - i32.gt_s - br_if 0 (;@13;) - end - end - block ;; label = @12 - local.get 20 - i32.const -1 - i32.gt_s - br_if 0 (;@12;) - local.get 27 - i32.const 25 - i32.add - i32.const 9 - i32.div_u - i32.const 1 - i32.add - local.set 41 - loop ;; label = @13 - i32.const 0 - local.get 20 - i32.sub - local.tee 21 - i32.const 9 - local.get 21 - i32.const 9 - i32.lt_s - select - local.set 24 - block ;; label = @14 - block ;; label = @15 - local.get 22 - local.get 19 - i32.lt_u - br_if 0 (;@15;) - local.get 22 - i32.load - local.set 21 - br 1 (;@14;) - end - i32.const 1000000000 - local.get 24 - i32.shr_u - local.set 29 - i32.const -1 - local.get 24 - i32.shl - i32.const -1 - i32.xor - local.set 28 - i32.const 0 - local.set 20 - local.get 22 - local.set 21 - loop ;; label = @15 - local.get 21 - local.get 21 - i32.load - local.tee 25 - local.get 24 - i32.shr_u - local.get 20 - i32.add - i32.store - local.get 25 - local.get 28 - i32.and - local.get 29 - i32.mul - local.set 20 - local.get 21 - i32.const 4 - i32.add - local.tee 21 - local.get 19 - i32.lt_u - br_if 0 (;@15;) - end - local.get 22 - i32.load - local.set 21 - local.get 20 - i32.eqz - br_if 0 (;@14;) - local.get 19 - local.get 20 - i32.store - local.get 19 - i32.const 4 - i32.add - local.set 19 - end - local.get 5 - local.get 5 - i32.load offset=108 - local.get 24 - i32.add - local.tee 20 - i32.store offset=108 - local.get 23 - local.get 22 - local.get 21 - i32.eqz - i32.const 2 - i32.shl - i32.add - local.tee 22 - local.get 38 - i32.const 102 - i32.eq - select - local.tee 21 - local.get 41 - i32.const 2 - i32.shl - i32.add - local.get 19 - local.get 19 - local.get 21 - i32.sub - i32.const 2 - i32.shr_s - local.get 41 - i32.gt_s - select - local.set 19 - local.get 20 - i32.const 0 - i32.lt_s - br_if 0 (;@13;) - end - end - i32.const 0 - local.set 25 - block ;; label = @12 - local.get 22 - local.get 19 - i32.ge_u - br_if 0 (;@12;) - local.get 23 - local.get 22 - i32.sub - i32.const 2 - i32.shr_s - i32.const 9 - i32.mul - local.set 25 - local.get 22 - i32.load - local.tee 20 - i32.const 10 - i32.lt_u - br_if 0 (;@12;) - i32.const 10 - local.set 21 - loop ;; label = @13 - local.get 25 - i32.const 1 - i32.add - local.set 25 - local.get 20 - local.get 21 - i32.const 10 - i32.mul - local.tee 21 - i32.ge_u - br_if 0 (;@13;) - end - end - block ;; label = @12 - local.get 27 - i32.const 0 - local.get 25 - local.get 38 - i32.const 102 - i32.eq - select - i32.sub - local.get 27 - i32.const 0 - i32.ne - local.get 38 - i32.const 103 - i32.eq - local.tee 28 - i32.and - i32.sub - local.tee 21 - local.get 19 - local.get 23 - i32.sub - i32.const 2 - i32.shr_s - i32.const 9 - i32.mul - i32.const -9 - i32.add - i32.ge_s - br_if 0 (;@12;) - local.get 21 - i32.const 9216 - i32.add - local.tee 20 - i32.const 9 - i32.div_s - local.tee 24 - i32.const 2 - i32.shl - local.tee 42 - local.get 5 - i32.const 112 - i32.add - i32.const 1 - i32.const 73 - local.get 39 - select - i32.const 2 - i32.shl - local.tee 39 - i32.add - i32.add - i32.const -4096 - i32.add - local.set 29 - i32.const 10 - local.set 21 - block ;; label = @13 - local.get 20 - local.get 24 - i32.const 9 - i32.mul - i32.sub - local.tee 24 - i32.const 7 - i32.gt_s - br_if 0 (;@13;) - i32.const 8 - local.get 24 - i32.sub - local.tee 41 - i32.const 7 - i32.and - local.set 20 - i32.const 10 - local.set 21 - block ;; label = @14 - local.get 24 - i32.const -1 - i32.add - i32.const 7 - i32.lt_u - br_if 0 (;@14;) - local.get 41 - i32.const -8 - i32.and - local.set 24 - i32.const 10 - local.set 21 - loop ;; label = @15 - local.get 21 - i32.const 100000000 - i32.mul - local.set 21 - local.get 24 - i32.const -8 - i32.add - local.tee 24 - br_if 0 (;@15;) - end - end - local.get 20 - i32.eqz - br_if 0 (;@13;) - loop ;; label = @14 - local.get 21 - i32.const 10 - i32.mul - local.set 21 - local.get 20 - i32.const -1 - i32.add - local.tee 20 - br_if 0 (;@14;) - end - end - local.get 29 - i32.const 4 - i32.add - local.set 41 - block ;; label = @13 - block ;; label = @14 - local.get 29 - i32.load - local.tee 20 - local.get 20 - local.get 21 - i32.div_u - local.tee 38 - local.get 21 - i32.mul - i32.sub - local.tee 24 - br_if 0 (;@14;) - local.get 41 - local.get 19 - i32.eq - br_if 1 (;@13;) - end - block ;; label = @14 - block ;; label = @15 - local.get 38 - i32.const 1 - i32.and - br_if 0 (;@15;) - f64.const 0x1p+53 (;=9.0072e+15;) - local.set 34 - local.get 21 - i32.const 1000000000 - i32.ne - br_if 1 (;@14;) - local.get 29 - local.get 22 - i32.le_u - br_if 1 (;@14;) - local.get 29 - i32.const -4 - i32.add - i32.load8_u - i32.const 1 - i32.and - i32.eqz - br_if 1 (;@14;) - end - f64.const 0x1.0000000000001p+53 (;=9.0072e+15;) - local.set 34 - end - f64.const 0x1p-1 (;=0.5;) - f64.const 0x1p+0 (;=1;) - f64.const 0x1.8p+0 (;=1.5;) - local.get 41 - local.get 19 - i32.eq - select - f64.const 0x1.8p+0 (;=1.5;) - local.get 24 - local.get 21 - i32.const 1 - i32.shr_u - local.tee 41 - i32.eq - select - local.get 24 - local.get 41 - i32.lt_u - select - local.set 43 - block ;; label = @14 - local.get 36 - br_if 0 (;@14;) - local.get 37 - i32.load8_u - i32.const 45 - i32.ne - br_if 0 (;@14;) - local.get 43 - f64.neg - local.set 43 - local.get 34 - f64.neg - local.set 34 - end - local.get 29 - local.get 20 - local.get 24 - i32.sub - local.tee 20 - i32.store - local.get 34 - local.get 43 - f64.add - local.get 34 - f64.eq - br_if 0 (;@13;) - local.get 29 - local.get 20 - local.get 21 - i32.add - local.tee 21 - i32.store - block ;; label = @14 - local.get 21 - i32.const 1000000000 - i32.lt_u - br_if 0 (;@14;) - local.get 8 - local.get 39 - local.get 42 - i32.add - i32.add - local.set 21 - loop ;; label = @15 - local.get 21 - i32.const 4 - i32.add - i32.const 0 - i32.store - block ;; label = @16 - local.get 21 - local.get 22 - i32.ge_u - br_if 0 (;@16;) - local.get 22 - i32.const -4 - i32.add - local.tee 22 - i32.const 0 - i32.store - end - local.get 21 - local.get 21 - i32.load - i32.const 1 - i32.add - local.tee 20 - i32.store - local.get 21 - i32.const -4 - i32.add - local.set 21 - local.get 20 - i32.const 999999999 - i32.gt_u - br_if 0 (;@15;) - end - local.get 21 - i32.const 4 - i32.add - local.set 29 - end - local.get 23 - local.get 22 - i32.sub - i32.const 2 - i32.shr_s - i32.const 9 - i32.mul - local.set 25 - local.get 22 - i32.load - local.tee 20 - i32.const 10 - i32.lt_u - br_if 0 (;@13;) - i32.const 10 - local.set 21 - loop ;; label = @14 - local.get 25 - i32.const 1 - i32.add - local.set 25 - local.get 20 - local.get 21 - i32.const 10 - i32.mul - local.tee 21 - i32.ge_u - br_if 0 (;@14;) - end - end - local.get 29 - i32.const 4 - i32.add - local.tee 21 - local.get 19 - local.get 19 - local.get 21 - i32.gt_u - select - local.set 19 - end - local.get 7 - local.get 19 - i32.add - local.get 40 - i32.sub - local.set 21 - block ;; label = @12 - loop ;; label = @13 - local.get 21 - local.set 20 - local.get 19 - local.tee 29 - local.get 22 - i32.le_u - local.tee 24 - br_if 1 (;@12;) - local.get 20 - i32.const -4 - i32.add - local.set 21 - local.get 29 - i32.const -4 - i32.add - local.tee 19 - i32.load - i32.eqz - br_if 0 (;@13;) - end - end - block ;; label = @12 - block ;; label = @13 - local.get 28 - br_if 0 (;@13;) - local.get 30 - i32.const 8 - i32.and - local.set 41 - br 1 (;@12;) - end - local.get 25 - i32.const -1 - i32.xor - i32.const -1 - local.get 27 - i32.const 1 - local.get 27 - select - local.tee 19 - local.get 25 - i32.gt_s - local.get 25 - i32.const -5 - i32.gt_s - i32.and - local.tee 21 - select - local.get 19 - i32.add - local.set 27 - i32.const -1 - i32.const -2 - local.get 21 - select - local.get 31 - i32.add - local.set 31 - local.get 30 - i32.const 8 - i32.and - local.tee 41 - br_if 0 (;@12;) - i32.const -9 - local.set 19 - block ;; label = @13 - local.get 24 - br_if 0 (;@13;) - local.get 29 - i32.const -4 - i32.add - i32.load - local.tee 24 - i32.eqz - br_if 0 (;@13;) - i32.const 0 - local.set 19 - local.get 24 - i32.const 10 - i32.rem_u - br_if 0 (;@13;) - i32.const 10 - local.set 21 - i32.const 0 - local.set 19 - loop ;; label = @14 - local.get 19 - i32.const -1 - i32.add - local.set 19 - local.get 24 - local.get 21 - i32.const 10 - i32.mul - local.tee 21 - i32.rem_u - i32.eqz - br_if 0 (;@14;) - end - end - local.get 20 - i32.const 2 - i32.shr_s - i32.const 9 - i32.mul - i32.const -9 - i32.add - local.set 21 - block ;; label = @13 - local.get 31 - i32.const -33 - i32.and - i32.const 70 - i32.ne - br_if 0 (;@13;) - i32.const 0 - local.set 41 - local.get 27 - local.get 21 - local.get 19 - i32.add - local.tee 19 - i32.const 0 - local.get 19 - i32.const 0 - i32.gt_s - select - local.tee 19 - local.get 27 - local.get 19 - i32.lt_s - select - local.set 27 - br 1 (;@12;) - end - i32.const 0 - local.set 41 - local.get 27 - local.get 21 - local.get 25 - i32.add - local.get 19 - i32.add - local.tee 19 - i32.const 0 - local.get 19 - i32.const 0 - i32.gt_s - select - local.tee 19 - local.get 27 - local.get 19 - i32.lt_s - select - local.set 27 - end - local.get 27 - i32.const 2147483645 - i32.const 2147483646 - local.get 27 - local.get 41 - i32.or - local.tee 36 - select - i32.gt_s - br_if 8 (;@3;) - local.get 27 - local.get 36 - i32.const 0 - i32.ne - i32.add - i32.const 1 - i32.add - local.set 38 - block ;; label = @12 - block ;; label = @13 - local.get 31 - i32.const -33 - i32.and - i32.const 70 - i32.ne - local.tee 39 - br_if 0 (;@13;) - local.get 25 - local.get 38 - i32.const 2147483647 - i32.xor - i32.gt_s - br_if 10 (;@3;) - local.get 25 - i32.const 0 - local.get 25 - i32.const 0 - i32.gt_s - select - local.set 19 - br 1 (;@12;) - end - block ;; label = @13 - block ;; label = @14 - local.get 25 - br_if 0 (;@14;) - local.get 6 - local.set 20 - local.get 6 - local.set 21 - br 1 (;@13;) - end - local.get 25 - local.get 25 - i32.const 31 - i32.shr_s - local.tee 19 - i32.xor - local.get 19 - i32.sub - local.set 19 - local.get 6 - local.set 20 - local.get 6 - local.set 21 - loop ;; label = @14 - local.get 21 - i32.const -1 - i32.add - local.tee 21 - local.get 19 - local.get 19 - i32.const 10 - i32.div_u - local.tee 24 - i32.const 10 - i32.mul - i32.sub - i32.const 48 - i32.or - i32.store8 - local.get 20 - i32.const -1 - i32.add - local.set 20 - local.get 19 - i32.const 9 - i32.gt_u - local.set 28 - local.get 24 - local.set 19 - local.get 28 - br_if 0 (;@14;) - end - end - block ;; label = @13 - local.get 6 - local.get 20 - i32.sub - i32.const 1 - i32.gt_s - br_if 0 (;@13;) - local.get 21 - local.get 15 - local.get 20 - i32.sub - i32.add - local.tee 21 - i32.const 48 - local.get 14 - local.get 20 - i32.add - call $memset - drop - end - local.get 21 - i32.const -2 - i32.add - local.tee 40 - local.get 31 - i32.store8 - local.get 21 - i32.const -1 - i32.add - i32.const 45 - i32.const 43 - local.get 25 - i32.const 0 - i32.lt_s - select - i32.store8 - local.get 6 - local.get 40 - i32.sub - local.tee 19 - local.get 38 - i32.const 2147483647 - i32.xor - i32.gt_s - br_if 9 (;@3;) - end - local.get 19 - local.get 38 - i32.add - local.tee 19 - local.get 35 - i32.const 2147483647 - i32.xor - i32.gt_s - br_if 8 (;@3;) - local.get 19 - local.get 35 - i32.add - local.set 28 - block ;; label = @12 - local.get 30 - i32.const 73728 - i32.and - local.tee 30 - br_if 0 (;@12;) - local.get 26 - local.get 28 - i32.le_s - br_if 0 (;@12;) - local.get 5 - i32.const 624 - i32.add - i32.const 32 - local.get 26 - local.get 28 - i32.sub - local.tee 19 - i32.const 256 - local.get 19 - i32.const 256 - i32.lt_u - local.tee 21 - select - call $memset - drop - block ;; label = @13 - local.get 21 - br_if 0 (;@13;) - loop ;; label = @14 - block ;; label = @15 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@15;) - local.get 5 - i32.const 624 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const -256 - i32.add - local.tee 19 - i32.const 255 - i32.gt_u - br_if 0 (;@14;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@12;) - local.get 5 - i32.const 624 - i32.add - local.get 19 - local.get 0 - call $__fwritex - drop - end - block ;; label = @12 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@12;) - local.get 37 - local.get 35 - local.get 0 - call $__fwritex - drop - end - block ;; label = @12 - local.get 30 - i32.const 65536 - i32.ne - br_if 0 (;@12;) - local.get 26 - local.get 28 - i32.le_s - br_if 0 (;@12;) - local.get 5 - i32.const 624 - i32.add - i32.const 48 - local.get 26 - local.get 28 - i32.sub - local.tee 19 - i32.const 256 - local.get 19 - i32.const 256 - i32.lt_u - local.tee 21 - select - call $memset - drop - block ;; label = @13 - local.get 21 - br_if 0 (;@13;) - loop ;; label = @14 - block ;; label = @15 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@15;) - local.get 5 - i32.const 624 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const -256 - i32.add - local.tee 19 - i32.const 255 - i32.gt_u - br_if 0 (;@14;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@12;) - local.get 5 - i32.const 624 - i32.add - local.get 19 - local.get 0 - call $__fwritex - drop - end - local.get 39 - br_if 3 (;@8;) - local.get 23 - local.get 22 - local.get 22 - local.get 23 - i32.gt_u - select - local.tee 25 - local.set 24 - loop ;; label = @12 - block ;; label = @13 - block ;; label = @14 - block ;; label = @15 - block ;; label = @16 - local.get 24 - i32.load - local.tee 19 - i32.eqz - br_if 0 (;@16;) - i32.const 8 - local.set 21 - loop ;; label = @17 - local.get 5 - i32.const 80 - i32.add - local.get 21 - i32.add - local.get 19 - local.get 19 - i32.const 10 - i32.div_u - local.tee 22 - i32.const 10 - i32.mul - i32.sub - i32.const 48 - i32.or - i32.store8 - local.get 21 - i32.const -1 - i32.add - local.set 21 - local.get 19 - i32.const 9 - i32.gt_u - local.set 20 - local.get 22 - local.set 19 - local.get 20 - br_if 0 (;@17;) - end - local.get 21 - i32.const 1 - i32.add - local.tee 22 - local.get 5 - i32.const 80 - i32.add - i32.add - local.set 19 - block ;; label = @17 - local.get 24 - local.get 25 - i32.eq - br_if 0 (;@17;) - local.get 21 - i32.const 2 - i32.add - i32.const 2 - i32.lt_s - br_if 4 (;@13;) - br 3 (;@14;) - end - local.get 21 - i32.const 8 - i32.ne - br_if 3 (;@13;) - br 1 (;@15;) - end - i32.const 9 - local.set 22 - local.get 24 - local.get 25 - i32.ne - br_if 1 (;@14;) - end - local.get 5 - i32.const 48 - i32.store8 offset=88 - local.get 12 - local.set 19 - br 1 (;@13;) - end - local.get 5 - i32.const 80 - i32.add - local.get 22 - local.get 5 - i32.const 80 - i32.add - i32.add - local.tee 21 - i32.const -1 - i32.add - local.tee 19 - local.get 5 - i32.const 80 - i32.add - local.get 19 - i32.lt_u - select - local.tee 19 - i32.const 48 - local.get 21 - local.get 19 - i32.sub - call $memset - drop - end - block ;; label = @13 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@13;) - local.get 19 - local.get 13 - local.get 19 - i32.sub - local.get 0 - call $__fwritex - drop - end - local.get 24 - i32.const 4 - i32.add - local.tee 24 - local.get 23 - i32.le_u - br_if 0 (;@12;) - end - block ;; label = @12 - local.get 36 - i32.eqz - br_if 0 (;@12;) - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@12;) - i32.const 1069 - i32.const 1 - local.get 0 - call $__fwritex - drop - end - block ;; label = @12 - block ;; label = @13 - local.get 24 - local.get 29 - i32.lt_u - br_if 0 (;@13;) - local.get 27 - local.set 19 - br 1 (;@12;) - end - block ;; label = @13 - local.get 27 - i32.const 1 - i32.ge_s - br_if 0 (;@13;) - local.get 27 - local.set 19 - br 1 (;@12;) - end - loop ;; label = @13 - block ;; label = @14 - block ;; label = @15 - block ;; label = @16 - local.get 24 - i32.load - local.tee 19 - br_if 0 (;@16;) - local.get 13 - local.set 21 - local.get 13 - local.set 22 - br 1 (;@15;) - end - local.get 13 - local.set 22 - local.get 13 - local.set 21 - loop ;; label = @16 - local.get 21 - i32.const -1 - i32.add - local.tee 21 - local.get 19 - local.get 19 - i32.const 10 - i32.div_u - local.tee 20 - i32.const 10 - i32.mul - i32.sub - i32.const 48 - i32.or - i32.store8 - local.get 22 - i32.const -1 - i32.add - local.set 22 - local.get 19 - i32.const 9 - i32.gt_u - local.set 25 - local.get 20 - local.set 19 - local.get 25 - br_if 0 (;@16;) - end - local.get 21 - local.get 5 - i32.const 80 - i32.add - i32.le_u - br_if 1 (;@14;) - end - local.get 21 - local.get 5 - i32.const 80 - i32.add - i32.add - local.get 22 - i32.sub - local.tee 21 - i32.const 48 - local.get 22 - local.get 5 - i32.const 80 - i32.add - i32.sub - call $memset - drop - end - block ;; label = @14 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@14;) - local.get 21 - local.get 27 - i32.const 9 - local.get 27 - i32.const 9 - i32.lt_s - select - local.get 0 - call $__fwritex - drop - end - local.get 27 - i32.const -9 - i32.add - local.set 19 - local.get 24 - i32.const 4 - i32.add - local.tee 24 - local.get 29 - i32.ge_u - br_if 1 (;@12;) - local.get 27 - i32.const 9 - i32.gt_s - local.set 21 - local.get 19 - local.set 27 - local.get 21 - br_if 0 (;@13;) - end - end - local.get 0 - i32.const 48 - local.get 19 - i32.const 9 - i32.add - i32.const 9 - i32.const 0 - call $pad - br 4 (;@7;) - end - i32.const 4228 - i32.const 28 - i32.store - br 8 (;@2;) - end - i32.const 0 - local.set 28 - i32.const 1024 - local.set 23 - local.get 16 - local.set 19 - local.get 30 - local.set 29 - local.get 24 - local.set 25 - end - local.get 25 - local.get 19 - local.get 20 - i32.sub - local.tee 24 - local.get 25 - local.get 24 - i32.gt_s - select - local.tee 27 - local.get 28 - i32.const 2147483647 - i32.xor - i32.gt_s - br_if 5 (;@3;) - local.get 26 - local.get 28 - local.get 27 - i32.add - local.tee 22 - local.get 26 - local.get 22 - i32.gt_s - select - local.tee 19 - local.get 21 - i32.gt_s - br_if 5 (;@3;) - block ;; label = @9 - local.get 29 - i32.const 73728 - i32.and - local.tee 29 - br_if 0 (;@9;) - local.get 22 - local.get 26 - i32.ge_s - br_if 0 (;@9;) - local.get 5 - i32.const 112 - i32.add - i32.const 32 - local.get 19 - local.get 22 - i32.sub - local.tee 21 - i32.const 256 - local.get 21 - i32.const 256 - i32.lt_u - local.tee 30 - select - call $memset - drop - block ;; label = @10 - local.get 30 - br_if 0 (;@10;) - loop ;; label = @11 - block ;; label = @12 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@12;) - local.get 5 - i32.const 112 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 21 - i32.const -256 - i32.add - local.tee 21 - i32.const 255 - i32.gt_u - br_if 0 (;@11;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@9;) - local.get 5 - i32.const 112 - i32.add - local.get 21 - local.get 0 - call $__fwritex - drop - end - block ;; label = @9 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@9;) - local.get 23 - local.get 28 - local.get 0 - call $__fwritex - drop - end - block ;; label = @9 - local.get 29 - i32.const 65536 - i32.ne - br_if 0 (;@9;) - local.get 22 - local.get 26 - i32.ge_s - br_if 0 (;@9;) - local.get 5 - i32.const 112 - i32.add - i32.const 48 - local.get 19 - local.get 22 - i32.sub - local.tee 21 - i32.const 256 - local.get 21 - i32.const 256 - i32.lt_u - local.tee 28 - select - call $memset - drop - block ;; label = @10 - local.get 28 - br_if 0 (;@10;) - loop ;; label = @11 - block ;; label = @12 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@12;) - local.get 5 - i32.const 112 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 21 - i32.const -256 - i32.add - local.tee 21 - i32.const 255 - i32.gt_u - br_if 0 (;@11;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@9;) - local.get 5 - i32.const 112 - i32.add - local.get 21 - local.get 0 - call $__fwritex - drop - end - block ;; label = @9 - local.get 24 - local.get 25 - i32.ge_s - br_if 0 (;@9;) - local.get 5 - i32.const 112 - i32.add - i32.const 48 - local.get 27 - local.get 24 - i32.sub - local.tee 21 - i32.const 256 - local.get 21 - i32.const 256 - i32.lt_u - local.tee 25 - select - call $memset - drop - block ;; label = @10 - local.get 25 - br_if 0 (;@10;) - loop ;; label = @11 - block ;; label = @12 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@12;) - local.get 5 - i32.const 112 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 21 - i32.const -256 - i32.add - local.tee 21 - i32.const 255 - i32.gt_u - br_if 0 (;@11;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@9;) - local.get 5 - i32.const 112 - i32.add - local.get 21 - local.get 0 - call $__fwritex - drop - end - block ;; label = @9 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@9;) - local.get 20 - local.get 24 - local.get 0 - call $__fwritex - drop - end - local.get 29 - i32.const 8192 - i32.ne - br_if 4 (;@4;) - local.get 22 - local.get 26 - i32.ge_s - br_if 4 (;@4;) - local.get 5 - i32.const 112 - i32.add - i32.const 32 - local.get 19 - local.get 22 - i32.sub - local.tee 21 - i32.const 256 - local.get 21 - i32.const 256 - i32.lt_u - local.tee 22 - select - call $memset - drop - block ;; label = @9 - local.get 22 - br_if 0 (;@9;) - loop ;; label = @10 - block ;; label = @11 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@11;) - local.get 5 - i32.const 112 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 21 - i32.const -256 - i32.add - local.tee 21 - i32.const 255 - i32.gt_u - br_if 0 (;@10;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 4 (;@4;) - local.get 5 - i32.const 112 - i32.add - local.get 21 - local.get 0 - call $__fwritex - drop - br 4 (;@4;) - end - block ;; label = @8 - local.get 27 - i32.const 0 - i32.lt_s - br_if 0 (;@8;) - local.get 29 - local.get 22 - i32.const 4 - i32.add - local.get 29 - local.get 22 - i32.gt_u - select - local.set 29 - local.get 22 - local.set 24 - loop ;; label = @9 - block ;; label = @10 - block ;; label = @11 - local.get 24 - i32.load - local.tee 19 - i32.eqz - br_if 0 (;@11;) - i32.const 0 - local.set 21 - loop ;; label = @12 - local.get 5 - i32.const 80 - i32.add - local.get 21 - i32.add - i32.const 8 - i32.add - local.get 19 - local.get 19 - i32.const 10 - i32.div_u - local.tee 20 - i32.const 10 - i32.mul - i32.sub - i32.const 48 - i32.or - i32.store8 - local.get 21 - i32.const -1 - i32.add - local.set 21 - local.get 19 - i32.const 9 - i32.gt_u - local.set 25 - local.get 20 - local.set 19 - local.get 25 - br_if 0 (;@12;) - end - local.get 21 - i32.eqz - br_if 0 (;@11;) - local.get 5 - i32.const 80 - i32.add - local.get 21 - i32.add - i32.const 9 - i32.add - local.set 19 - br 1 (;@10;) - end - local.get 5 - i32.const 48 - i32.store8 offset=88 - local.get 12 - local.set 19 - end - block ;; label = @10 - block ;; label = @11 - local.get 24 - local.get 22 - i32.eq - br_if 0 (;@11;) - local.get 19 - local.get 5 - i32.const 80 - i32.add - i32.le_u - br_if 1 (;@10;) - local.get 5 - i32.const 80 - i32.add - i32.const 48 - local.get 19 - local.get 5 - i32.const 80 - i32.add - i32.sub - call $memset - drop - local.get 5 - i32.const 80 - i32.add - local.set 19 - br 1 (;@10;) - end - block ;; label = @11 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@11;) - local.get 19 - i32.const 1 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const 1 - i32.add - local.set 19 - block ;; label = @11 - local.get 41 - br_if 0 (;@11;) - local.get 27 - i32.const 1 - i32.lt_s - br_if 1 (;@10;) - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@10;) - i32.const 1069 - i32.const 1 - local.get 0 - call $__fwritex - drop - end - local.get 13 - local.get 19 - i32.sub - local.set 21 - block ;; label = @10 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@10;) - local.get 19 - local.get 27 - local.get 21 - local.get 27 - local.get 21 - i32.lt_s - select - local.get 0 - call $__fwritex - drop - end - local.get 27 - local.get 21 - i32.sub - local.set 27 - local.get 24 - i32.const 4 - i32.add - local.tee 24 - local.get 29 - i32.ge_u - br_if 1 (;@8;) - local.get 27 - i32.const -1 - i32.gt_s - br_if 0 (;@9;) - end - end - local.get 0 - i32.const 48 - local.get 27 - i32.const 18 - i32.add - i32.const 18 - i32.const 0 - call $pad - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@7;) - local.get 40 - local.get 6 - local.get 40 - i32.sub - local.get 0 - call $__fwritex - drop - end - local.get 30 - i32.const 8192 - i32.ne - br_if 1 (;@5;) - local.get 26 - local.get 28 - i32.le_s - br_if 1 (;@5;) - local.get 5 - i32.const 624 - i32.add - i32.const 32 - local.get 26 - local.get 28 - i32.sub - local.tee 19 - i32.const 256 - local.get 19 - i32.const 256 - i32.lt_u - local.tee 21 - select - call $memset - drop - block ;; label = @7 - local.get 21 - br_if 0 (;@7;) - loop ;; label = @8 - block ;; label = @9 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@9;) - local.get 5 - i32.const 624 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const -256 - i32.add - local.tee 19 - i32.const 255 - i32.gt_u - br_if 0 (;@8;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 1 (;@5;) - local.get 5 - i32.const 624 - i32.add - local.get 19 - local.get 0 - call $__fwritex - drop - br 1 (;@5;) - end - local.get 37 - local.get 31 - i32.const 26 - i32.shl - i32.const 31 - i32.shr_s - i32.const 9 - i32.and - i32.add - local.set 23 - block ;; label = @6 - local.get 24 - i32.const 11 - i32.gt_u - br_if 0 (;@6;) - block ;; label = @7 - block ;; label = @8 - i32.const 12 - local.get 24 - i32.sub - local.tee 19 - i32.const 7 - i32.and - local.tee 21 - br_if 0 (;@8;) - f64.const 0x1p+4 (;=16;) - local.set 43 - br 1 (;@7;) - end - local.get 24 - i32.const -12 - i32.add - local.set 19 - f64.const 0x1p+4 (;=16;) - local.set 43 - loop ;; label = @8 - local.get 19 - i32.const 1 - i32.add - local.set 19 - local.get 43 - f64.const 0x1p+4 (;=16;) - f64.mul - local.set 43 - local.get 21 - i32.const -1 - i32.add - local.tee 21 - br_if 0 (;@8;) - end - i32.const 0 - local.get 19 - i32.sub - local.set 19 - end - block ;; label = @7 - local.get 24 - i32.const -5 - i32.add - i32.const 7 - i32.lt_u - br_if 0 (;@7;) - loop ;; label = @8 - local.get 43 - f64.const 0x1p+4 (;=16;) - f64.mul - f64.const 0x1p+4 (;=16;) - f64.mul - f64.const 0x1p+4 (;=16;) - f64.mul - f64.const 0x1p+4 (;=16;) - f64.mul - f64.const 0x1p+4 (;=16;) - f64.mul - f64.const 0x1p+4 (;=16;) - f64.mul - f64.const 0x1p+4 (;=16;) - f64.mul - f64.const 0x1p+4 (;=16;) - f64.mul - local.set 43 - local.get 19 - i32.const -8 - i32.add - local.tee 19 - br_if 0 (;@8;) - end - end - block ;; label = @7 - local.get 23 - i32.load8_u - i32.const 45 - i32.ne - br_if 0 (;@7;) - local.get 43 - local.get 34 - f64.neg - local.get 43 - f64.sub - f64.add - f64.neg - local.set 34 - br 1 (;@6;) - end - local.get 34 - local.get 43 - f64.add - local.get 43 - f64.sub - local.set 34 - end - block ;; label = @6 - block ;; label = @7 - local.get 5 - i32.load offset=108 - local.tee 25 - i32.eqz - br_if 0 (;@7;) - local.get 25 - local.get 25 - i32.const 31 - i32.shr_s - local.tee 19 - i32.xor - local.get 19 - i32.sub - local.set 19 - i32.const 0 - local.set 21 - loop ;; label = @8 - local.get 5 - i32.const 68 - i32.add - local.get 21 - i32.add - i32.const 11 - i32.add - local.get 19 - local.get 19 - i32.const 10 - i32.div_u - local.tee 22 - i32.const 10 - i32.mul - i32.sub - i32.const 48 - i32.or - i32.store8 - local.get 21 - i32.const -1 - i32.add - local.set 21 - local.get 19 - i32.const 9 - i32.gt_u - local.set 20 - local.get 22 - local.set 19 - local.get 20 - br_if 0 (;@8;) - end - local.get 21 - i32.eqz - br_if 0 (;@7;) - local.get 5 - i32.const 68 - i32.add - local.get 21 - i32.add - i32.const 12 - i32.add - local.set 19 - br 1 (;@6;) - end - local.get 5 - i32.const 48 - i32.store8 offset=79 - local.get 11 - local.set 19 - end - local.get 35 - i32.const 2 - i32.or - local.set 27 - local.get 31 - i32.const 32 - i32.and - local.set 22 - local.get 19 - i32.const -2 - i32.add - local.tee 29 - local.get 31 - i32.const 15 - i32.add - i32.store8 - local.get 19 - i32.const -1 - i32.add - i32.const 45 - i32.const 43 - local.get 25 - i32.const 0 - i32.lt_s - select - i32.store8 - local.get 30 - i32.const 8 - i32.and - local.set 20 - local.get 5 - i32.const 80 - i32.add - local.set 21 - loop ;; label = @6 - local.get 21 - local.set 19 - block ;; label = @7 - block ;; label = @8 - local.get 34 - f64.abs - f64.const 0x1p+31 (;=2.14748e+09;) - f64.lt - i32.eqz - br_if 0 (;@8;) - local.get 34 - i32.trunc_f64_s - local.set 21 - br 1 (;@7;) - end - i32.const -2147483648 - local.set 21 - end - local.get 19 - local.get 21 - i32.const 3472 - i32.add - i32.load8_u - local.get 22 - i32.or - i32.store8 - local.get 34 - local.get 21 - f64.convert_i32_s - f64.sub - f64.const 0x1p+4 (;=16;) - f64.mul - local.set 34 - block ;; label = @7 - local.get 19 - i32.const 1 - i32.add - local.tee 21 - local.get 5 - i32.const 80 - i32.add - i32.sub - i32.const 1 - i32.ne - br_if 0 (;@7;) - block ;; label = @8 - local.get 20 - br_if 0 (;@8;) - local.get 24 - i32.const 0 - i32.gt_s - br_if 0 (;@8;) - local.get 34 - f64.const 0x0p+0 (;=0;) - f64.eq - br_if 1 (;@7;) - end - local.get 19 - i32.const 46 - i32.store8 offset=1 - local.get 19 - i32.const 2 - i32.add - local.set 21 - end - local.get 34 - f64.const 0x0p+0 (;=0;) - f64.ne - br_if 0 (;@6;) - end - i32.const 2147483645 - local.get 6 - local.get 29 - i32.sub - local.tee 25 - local.get 27 - i32.add - local.tee 19 - i32.sub - local.get 24 - i32.lt_s - br_if 2 (;@3;) - local.get 24 - i32.const 2 - i32.add - local.get 21 - local.get 5 - i32.const 80 - i32.add - i32.sub - local.tee 22 - local.get 10 - local.get 21 - i32.add - local.get 24 - i32.lt_s - select - local.get 22 - local.get 24 - select - local.tee 20 - local.get 19 - i32.add - local.set 28 - block ;; label = @6 - local.get 30 - i32.const 73728 - i32.and - local.tee 21 - br_if 0 (;@6;) - local.get 26 - local.get 28 - i32.le_s - br_if 0 (;@6;) - local.get 5 - i32.const 624 - i32.add - i32.const 32 - local.get 26 - local.get 28 - i32.sub - local.tee 19 - i32.const 256 - local.get 19 - i32.const 256 - i32.lt_u - local.tee 24 - select - call $memset - drop - block ;; label = @7 - local.get 24 - br_if 0 (;@7;) - loop ;; label = @8 - block ;; label = @9 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@9;) - local.get 5 - i32.const 624 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const -256 - i32.add - local.tee 19 - i32.const 255 - i32.gt_u - br_if 0 (;@8;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@6;) - local.get 5 - i32.const 624 - i32.add - local.get 19 - local.get 0 - call $__fwritex - drop - end - block ;; label = @6 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@6;) - local.get 23 - local.get 27 - local.get 0 - call $__fwritex - drop - end - block ;; label = @6 - local.get 21 - i32.const 65536 - i32.ne - br_if 0 (;@6;) - local.get 26 - local.get 28 - i32.le_s - br_if 0 (;@6;) - local.get 5 - i32.const 624 - i32.add - i32.const 48 - local.get 26 - local.get 28 - i32.sub - local.tee 19 - i32.const 256 - local.get 19 - i32.const 256 - i32.lt_u - local.tee 24 - select - call $memset - drop - block ;; label = @7 - local.get 24 - br_if 0 (;@7;) - loop ;; label = @8 - block ;; label = @9 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@9;) - local.get 5 - i32.const 624 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const -256 - i32.add - local.tee 19 - i32.const 255 - i32.gt_u - br_if 0 (;@8;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@6;) - local.get 5 - i32.const 624 - i32.add - local.get 19 - local.get 0 - call $__fwritex - drop - end - block ;; label = @6 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@6;) - local.get 5 - i32.const 80 - i32.add - local.get 22 - local.get 0 - call $__fwritex - drop - end - block ;; label = @6 - local.get 20 - local.get 22 - i32.sub - local.tee 19 - i32.const 1 - i32.lt_s - br_if 0 (;@6;) - local.get 5 - i32.const 624 - i32.add - i32.const 48 - local.get 19 - i32.const 256 - local.get 19 - i32.const 256 - i32.lt_u - local.tee 22 - select - call $memset - drop - block ;; label = @7 - local.get 22 - br_if 0 (;@7;) - loop ;; label = @8 - block ;; label = @9 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@9;) - local.get 5 - i32.const 624 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const -256 - i32.add - local.tee 19 - i32.const 255 - i32.gt_u - br_if 0 (;@8;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@6;) - local.get 5 - i32.const 624 - i32.add - local.get 19 - local.get 0 - call $__fwritex - drop - end - block ;; label = @6 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@6;) - local.get 29 - local.get 25 - local.get 0 - call $__fwritex - drop - end - local.get 21 - i32.const 8192 - i32.ne - br_if 0 (;@5;) - local.get 26 - local.get 28 - i32.le_s - br_if 0 (;@5;) - local.get 5 - i32.const 624 - i32.add - i32.const 32 - local.get 26 - local.get 28 - i32.sub - local.tee 19 - i32.const 256 - local.get 19 - i32.const 256 - i32.lt_u - local.tee 21 - select - call $memset - drop - block ;; label = @6 - local.get 21 - br_if 0 (;@6;) - loop ;; label = @7 - block ;; label = @8 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@8;) - local.get 5 - i32.const 624 - i32.add - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 19 - i32.const -256 - i32.add - local.tee 19 - i32.const 255 - i32.gt_u - br_if 0 (;@7;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@5;) - local.get 5 - i32.const 624 - i32.add - local.get 19 - local.get 0 - call $__fwritex - drop - end - local.get 28 - local.get 26 - local.get 28 - local.get 26 - i32.gt_s - select - local.tee 19 - i32.const 0 - i32.ge_s - br_if 0 (;@4;) - end - end - i32.const 4228 - i32.const 61 - i32.store - end - i32.const -1 - local.set 18 - end - local.get 5 - i32.const 880 - i32.add - global.set $__stack_pointer - local.get 18) - (func $pop_arg (type 11) (param i32 i32 i32) - block ;; label = @1 - block ;; label = @2 - block ;; label = @3 - block ;; label = @4 - block ;; label = @5 - block ;; label = @6 - block ;; label = @7 - block ;; label = @8 - block ;; label = @9 - block ;; label = @10 - block ;; label = @11 - block ;; label = @12 - block ;; label = @13 - block ;; label = @14 - block ;; label = @15 - block ;; label = @16 - block ;; label = @17 - block ;; label = @18 - block ;; label = @19 - local.get 1 - i32.const -9 - i32.add - br_table 17 (;@2;) 0 (;@19;) 1 (;@18;) 4 (;@15;) 2 (;@17;) 3 (;@16;) 5 (;@14;) 6 (;@13;) 7 (;@12;) 8 (;@11;) 9 (;@10;) 10 (;@9;) 11 (;@8;) 12 (;@7;) 13 (;@6;) 14 (;@5;) 15 (;@4;) 16 (;@3;) 18 (;@1;) - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load32_s - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load32_u - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load32_s - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load32_u - i64.store - return - end - local.get 2 - local.get 2 - i32.load - i32.const 7 - i32.add - i32.const -8 - i32.and - local.tee 1 - i32.const 8 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load16_s - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load16_u - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load8_s - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load8_u - i64.store - return - end - local.get 2 - local.get 2 - i32.load - i32.const 7 - i32.add - i32.const -8 - i32.and - local.tee 1 - i32.const 8 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load32_u - i64.store - return - end - local.get 2 - local.get 2 - i32.load - i32.const 7 - i32.add - i32.const -8 - i32.and - local.tee 1 - i32.const 8 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load - i64.store - return - end - local.get 2 - local.get 2 - i32.load - i32.const 7 - i32.add - i32.const -8 - i32.and - local.tee 1 - i32.const 8 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load32_s - i64.store - return - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i64.load32_u - i64.store - return - end - local.get 2 - local.get 2 - i32.load - i32.const 7 - i32.add - i32.const -8 - i32.and - local.tee 1 - i32.const 8 - i32.add - i32.store - local.get 0 - local.get 1 - f64.load - f64.store - return - end - call $long_double_not_supported - unreachable - end - local.get 2 - local.get 2 - i32.load - local.tee 1 - i32.const 4 - i32.add - i32.store - local.get 0 - local.get 1 - i32.load - i32.store - end) - (func $pad (type 12) (param i32 i32 i32 i32 i32) - (local i32) - global.get $__stack_pointer - i32.const 256 - i32.sub - local.tee 5 - global.set $__stack_pointer - block ;; label = @1 - local.get 2 - local.get 3 - i32.le_s - br_if 0 (;@1;) - local.get 4 - i32.const 73728 - i32.and - br_if 0 (;@1;) - local.get 5 - local.get 1 - local.get 2 - local.get 3 - i32.sub - local.tee 3 - i32.const 256 - local.get 3 - i32.const 256 - i32.lt_u - local.tee 4 - select - call $memset - local.set 2 - block ;; label = @2 - local.get 4 - br_if 0 (;@2;) - loop ;; label = @3 - block ;; label = @4 - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@4;) - local.get 2 - i32.const 256 - local.get 0 - call $__fwritex - drop - end - local.get 3 - i32.const -256 - i32.add - local.tee 3 - i32.const 255 - i32.gt_u - br_if 0 (;@3;) - end - end - local.get 0 - i32.load8_u - i32.const 32 - i32.and - br_if 0 (;@1;) - local.get 2 - local.get 3 - local.get 0 - call $__fwritex - drop - end - local.get 5 - i32.const 256 - i32.add - global.set $__stack_pointer) - (func $long_double_not_supported (type 7) - i32.const 1160 - i32.const 3608 - call $fputs - drop - call $abort - unreachable) - (func $memcpy (type 0) (param i32 i32 i32) (result i32) - (local i32 i32 i32 i32) - block ;; label = @1 - block ;; label = @2 - block ;; label = @3 - local.get 2 - i32.const 32 - i32.gt_u - br_if 0 (;@3;) - local.get 1 - i32.const 3 - i32.and - i32.eqz - br_if 1 (;@2;) - local.get 2 - i32.eqz - br_if 1 (;@2;) - local.get 0 - local.get 1 - i32.load8_u - i32.store8 - local.get 2 - i32.const -1 - i32.add - local.set 3 - local.get 0 - i32.const 1 - i32.add - local.set 4 - local.get 1 - i32.const 1 - i32.add - local.tee 5 - i32.const 3 - i32.and - i32.eqz - br_if 2 (;@1;) - local.get 3 - i32.eqz - br_if 2 (;@1;) - local.get 0 - local.get 1 - i32.load8_u offset=1 - i32.store8 offset=1 - local.get 2 - i32.const -2 - i32.add - local.set 3 - local.get 0 - i32.const 2 - i32.add - local.set 4 - local.get 1 - i32.const 2 - i32.add - local.tee 5 - i32.const 3 - i32.and - i32.eqz - br_if 2 (;@1;) - local.get 3 - i32.eqz - br_if 2 (;@1;) - local.get 0 - local.get 1 - i32.load8_u offset=2 - i32.store8 offset=2 - local.get 2 - i32.const -3 - i32.add - local.set 3 - local.get 0 - i32.const 3 - i32.add - local.set 4 - local.get 1 - i32.const 3 - i32.add - local.tee 5 - i32.const 3 - i32.and - i32.eqz - br_if 2 (;@1;) - local.get 3 - i32.eqz - br_if 2 (;@1;) - local.get 0 - local.get 1 - i32.load8_u offset=3 - i32.store8 offset=3 - local.get 2 - i32.const -4 - i32.add - local.set 3 - local.get 0 - i32.const 4 - i32.add - local.set 4 - local.get 1 - i32.const 4 - i32.add - local.set 5 - br 2 (;@1;) - end - local.get 0 - local.get 1 - local.get 2 - memory.copy - local.get 0 - return - end - local.get 2 - local.set 3 - local.get 0 - local.set 4 - local.get 1 - local.set 5 - end - block ;; label = @1 - block ;; label = @2 - local.get 4 - i32.const 3 - i32.and - local.tee 2 - br_if 0 (;@2;) - block ;; label = @3 - block ;; label = @4 - local.get 3 - i32.const 16 - i32.ge_u - br_if 0 (;@4;) - local.get 3 - local.set 2 - br 1 (;@3;) - end - block ;; label = @4 - local.get 3 - i32.const -16 - i32.add - local.tee 2 - i32.const 16 - i32.and - br_if 0 (;@4;) - local.get 4 - local.get 5 - i64.load align=4 - i64.store align=4 - local.get 4 - local.get 5 - i64.load offset=8 align=4 - i64.store offset=8 align=4 - local.get 4 - i32.const 16 - i32.add - local.set 4 - local.get 5 - i32.const 16 - i32.add - local.set 5 - local.get 2 - local.set 3 - end - local.get 2 - i32.const 16 - i32.lt_u - br_if 0 (;@3;) - local.get 3 - local.set 2 - loop ;; label = @4 - local.get 4 - local.get 5 - i64.load align=4 - i64.store align=4 - local.get 4 - local.get 5 - i64.load offset=8 align=4 - i64.store offset=8 align=4 - local.get 4 - local.get 5 - i64.load offset=16 align=4 - i64.store offset=16 align=4 - local.get 4 - local.get 5 - i64.load offset=24 align=4 - i64.store offset=24 align=4 - local.get 4 - i32.const 32 - i32.add - local.set 4 - local.get 5 - i32.const 32 - i32.add - local.set 5 - local.get 2 - i32.const -32 - i32.add - local.tee 2 - i32.const 15 - i32.gt_u - br_if 0 (;@4;) - end - end - block ;; label = @3 - local.get 2 - i32.const 8 - i32.lt_u - br_if 0 (;@3;) - local.get 4 - local.get 5 - i64.load align=4 - i64.store align=4 - local.get 5 - i32.const 8 - i32.add - local.set 5 - local.get 4 - i32.const 8 - i32.add - local.set 4 - end - block ;; label = @3 - local.get 2 - i32.const 4 - i32.and - i32.eqz - br_if 0 (;@3;) - local.get 4 - local.get 5 - i32.load - i32.store - local.get 5 - i32.const 4 - i32.add - local.set 5 - local.get 4 - i32.const 4 - i32.add - local.set 4 - end - block ;; label = @3 - local.get 2 - i32.const 2 - i32.and - i32.eqz - br_if 0 (;@3;) - local.get 4 - local.get 5 - i32.load16_u align=1 - i32.store16 align=1 - local.get 4 - i32.const 2 - i32.add - local.set 4 - local.get 5 - i32.const 2 - i32.add - local.set 5 - end - local.get 2 - i32.const 1 - i32.and - i32.eqz - br_if 1 (;@1;) - local.get 4 - local.get 5 - i32.load8_u - i32.store8 - local.get 0 - return - end - block ;; label = @2 - block ;; label = @3 - block ;; label = @4 - block ;; label = @5 - block ;; label = @6 - local.get 3 - i32.const 32 - i32.lt_u - br_if 0 (;@6;) - block ;; label = @7 - block ;; label = @8 - local.get 2 - i32.const -1 - i32.add - br_table 3 (;@5;) 0 (;@8;) 1 (;@7;) 7 (;@1;) - end - local.get 4 - local.get 5 - i32.load - i32.store16 align=1 - local.get 4 - local.get 5 - i32.const 2 - i32.add - i32.load align=2 - i32.store offset=2 - local.get 4 - local.get 5 - i32.const 6 - i32.add - i64.load align=2 - i64.store offset=6 align=4 - local.get 4 - i32.const 18 - i32.add - local.set 2 - local.get 5 - i32.const 18 - i32.add - local.set 1 - i32.const 14 - local.set 6 - local.get 5 - i32.const 14 - i32.add - i32.load align=2 - local.set 5 - i32.const 14 - local.set 3 - br 3 (;@4;) - end - local.get 4 - local.get 5 - i32.load - i32.store8 - local.get 4 - local.get 5 - i32.const 1 - i32.add - i32.load align=1 - i32.store offset=1 - local.get 4 - local.get 5 - i32.const 5 - i32.add - i64.load align=1 - i64.store offset=5 align=4 - local.get 4 - i32.const 17 - i32.add - local.set 2 - local.get 5 - i32.const 17 - i32.add - local.set 1 - i32.const 13 - local.set 6 - local.get 5 - i32.const 13 - i32.add - i32.load align=1 - local.set 5 - i32.const 15 - local.set 3 - br 2 (;@4;) - end - block ;; label = @6 - block ;; label = @7 - local.get 3 - i32.const 16 - i32.ge_u - br_if 0 (;@7;) - local.get 4 - local.set 2 - local.get 5 - local.set 1 - br 1 (;@6;) - end - local.get 4 - local.get 5 - i32.load8_u - i32.store8 - local.get 4 - local.get 5 - i32.load offset=1 align=1 - i32.store offset=1 align=1 - local.get 4 - local.get 5 - i64.load offset=5 align=1 - i64.store offset=5 align=1 - local.get 4 - local.get 5 - i32.load16_u offset=13 align=1 - i32.store16 offset=13 align=1 - local.get 4 - local.get 5 - i32.load8_u offset=15 - i32.store8 offset=15 - local.get 4 - i32.const 16 - i32.add - local.set 2 - local.get 5 - i32.const 16 - i32.add - local.set 1 - end - local.get 3 - i32.const 8 - i32.and - br_if 2 (;@3;) - br 3 (;@2;) - end - local.get 4 - local.get 5 - i32.load - local.tee 2 - i32.store8 - local.get 4 - local.get 2 - i32.const 16 - i32.shr_u - i32.store8 offset=2 - local.get 4 - local.get 2 - i32.const 8 - i32.shr_u - i32.store8 offset=1 - local.get 4 - local.get 5 - i32.const 3 - i32.add - i32.load align=1 - i32.store offset=3 - local.get 4 - local.get 5 - i32.const 7 - i32.add - i64.load align=1 - i64.store offset=7 align=4 - local.get 4 - i32.const 19 - i32.add - local.set 2 - local.get 5 - i32.const 19 - i32.add - local.set 1 - i32.const 15 - local.set 6 - local.get 5 - i32.const 15 - i32.add - i32.load align=1 - local.set 5 - i32.const 13 - local.set 3 - end - local.get 4 - local.get 6 - i32.add - local.get 5 - i32.store - end - local.get 2 - local.get 1 - i64.load align=1 - i64.store align=1 - local.get 2 - i32.const 8 - i32.add - local.set 2 - local.get 1 - i32.const 8 - i32.add - local.set 1 - end - block ;; label = @2 - local.get 3 - i32.const 4 - i32.and - i32.eqz - br_if 0 (;@2;) - local.get 2 - local.get 1 - i32.load align=1 - i32.store align=1 - local.get 2 - i32.const 4 - i32.add - local.set 2 - local.get 1 - i32.const 4 - i32.add - local.set 1 - end - block ;; label = @2 - local.get 3 - i32.const 2 - i32.and - i32.eqz - br_if 0 (;@2;) - local.get 2 - local.get 1 - i32.load16_u align=1 - i32.store16 align=1 - local.get 2 - i32.const 2 - i32.add - local.set 2 - local.get 1 - i32.const 2 - i32.add - local.set 1 - end - local.get 3 - i32.const 1 - i32.and - i32.eqz - br_if 0 (;@1;) - local.get 2 - local.get 1 - i32.load8_u - i32.store8 - end - local.get 0) - (func $memset (type 0) (param i32 i32 i32) (result i32) - (local i32 i32 i32 i64) - block ;; label = @1 - local.get 2 - i32.const 33 - i32.lt_u - br_if 0 (;@1;) - local.get 0 - local.get 1 - local.get 2 - memory.fill - local.get 0 - return - end - block ;; label = @1 - local.get 2 - i32.eqz - br_if 0 (;@1;) - local.get 0 - local.get 1 - i32.store8 - local.get 2 - local.get 0 - i32.add - local.tee 3 - i32.const -1 - i32.add - local.get 1 - i32.store8 - local.get 2 - i32.const 3 - i32.lt_u - br_if 0 (;@1;) - local.get 0 - local.get 1 - i32.store8 offset=2 - local.get 0 - local.get 1 - i32.store8 offset=1 - local.get 3 - i32.const -3 - i32.add - local.get 1 - i32.store8 - local.get 3 - i32.const -2 - i32.add - local.get 1 - i32.store8 - local.get 2 - i32.const 7 - i32.lt_u - br_if 0 (;@1;) - local.get 0 - local.get 1 - i32.store8 offset=3 - local.get 3 - i32.const -4 - i32.add - local.get 1 - i32.store8 - local.get 2 - i32.const 9 - i32.lt_u - br_if 0 (;@1;) - local.get 0 - i32.const 0 - local.get 0 - i32.sub - i32.const 3 - i32.and - local.tee 4 - i32.add - local.tee 5 - local.get 1 - i32.const 255 - i32.and - i32.const 16843009 - i32.mul - local.tee 3 - i32.store - local.get 5 - local.get 2 - local.get 4 - i32.sub - i32.const -4 - i32.and - local.tee 1 - i32.add - local.tee 2 - i32.const -4 - i32.add - local.get 3 - i32.store - local.get 1 - i32.const 9 - i32.lt_u - br_if 0 (;@1;) - local.get 5 - local.get 3 - i32.store offset=8 - local.get 5 - local.get 3 - i32.store offset=4 - local.get 2 - i32.const -8 - i32.add - local.get 3 - i32.store - local.get 2 - i32.const -12 - i32.add - local.get 3 - i32.store - local.get 1 - i32.const 25 - i32.lt_u - br_if 0 (;@1;) - local.get 5 - local.get 3 - i32.store offset=24 - local.get 5 - local.get 3 - i32.store offset=20 - local.get 5 - local.get 3 - i32.store offset=16 - local.get 5 - local.get 3 - i32.store offset=12 - local.get 2 - i32.const -16 - i32.add - local.get 3 - i32.store - local.get 2 - i32.const -20 - i32.add - local.get 3 - i32.store - local.get 2 - i32.const -24 - i32.add - local.get 3 - i32.store - local.get 2 - i32.const -28 - i32.add - local.get 3 - i32.store - local.get 1 - local.get 5 - i32.const 4 - i32.and - i32.const 24 - i32.or - local.tee 2 - i32.sub - local.tee 1 - i32.const 32 - i32.lt_u - br_if 0 (;@1;) - local.get 3 - i64.extend_i32_u - i64.const 4294967297 - i64.mul - local.set 6 - local.get 5 - local.get 2 - i32.add - local.set 2 - loop ;; label = @2 - local.get 2 - local.get 6 - i64.store offset=24 - local.get 2 - local.get 6 - i64.store offset=16 - local.get 2 - local.get 6 - i64.store offset=8 - local.get 2 - local.get 6 - i64.store - local.get 2 - i32.const 32 - i32.add - local.set 2 - local.get 1 - i32.const -32 - i32.add - local.tee 1 - i32.const 31 - i32.gt_u - br_if 0 (;@2;) - end - end - local.get 0) - (func $strlen (type 2) (param i32) (result i32) - (local i32 i32) - local.get 0 - local.set 1 - block ;; label = @1 - block ;; label = @2 - local.get 0 - i32.const 3 - i32.and - i32.eqz - br_if 0 (;@2;) - local.get 0 - local.set 1 - local.get 0 - i32.load8_u - i32.eqz - br_if 1 (;@1;) - local.get 0 - i32.const 1 - i32.add - local.tee 1 - i32.const 3 - i32.and - i32.eqz - br_if 0 (;@2;) - local.get 1 - i32.load8_u - i32.eqz - br_if 1 (;@1;) - local.get 0 - i32.const 2 - i32.add - local.tee 1 - i32.const 3 - i32.and - i32.eqz - br_if 0 (;@2;) - local.get 1 - i32.load8_u - i32.eqz - br_if 1 (;@1;) - local.get 0 - i32.const 3 - i32.add - local.tee 1 - i32.const 3 - i32.and - i32.eqz - br_if 0 (;@2;) - local.get 1 - i32.load8_u - i32.eqz - br_if 1 (;@1;) - local.get 0 - i32.const 4 - i32.add - local.set 1 - end - local.get 1 - i32.const -5 - i32.add - local.set 1 - loop ;; label = @2 - local.get 1 - i32.const 5 - i32.add - local.set 2 - local.get 1 - i32.const 4 - i32.add - local.set 1 - local.get 2 - i32.load - local.tee 2 - i32.const -1 - i32.xor - local.get 2 - i32.const -16843009 - i32.add - i32.and - i32.const -2139062144 - i32.and - i32.eqz - br_if 0 (;@2;) - end - loop ;; label = @2 - local.get 1 - i32.const 1 - i32.add - local.tee 1 - i32.load8_u - br_if 0 (;@2;) - end - end - local.get 1 - local.get 0 - i32.sub) - (func $memchr (type 0) (param i32 i32 i32) (result i32) - (local i32 i32 i32) - local.get 2 - i32.const 0 - i32.ne - local.set 3 - block ;; label = @1 - block ;; label = @2 - block ;; label = @3 - block ;; label = @4 - local.get 0 - i32.const 3 - i32.and - i32.eqz - br_if 0 (;@4;) - local.get 2 - i32.eqz - br_if 0 (;@4;) - block ;; label = @5 - local.get 0 - i32.load8_u - local.get 1 - i32.const 255 - i32.and - i32.ne - br_if 0 (;@5;) - local.get 0 - local.set 4 - local.get 2 - local.set 5 - br 3 (;@2;) - end - local.get 2 - i32.const -1 - i32.add - local.tee 5 - i32.const 0 - i32.ne - local.set 3 - local.get 0 - i32.const 1 - i32.add - local.tee 4 - i32.const 3 - i32.and - i32.eqz - br_if 1 (;@3;) - local.get 5 - i32.eqz - br_if 1 (;@3;) - local.get 4 - i32.load8_u - local.get 1 - i32.const 255 - i32.and - i32.eq - br_if 2 (;@2;) - local.get 2 - i32.const -2 - i32.add - local.tee 5 - i32.const 0 - i32.ne - local.set 3 - local.get 0 - i32.const 2 - i32.add - local.tee 4 - i32.const 3 - i32.and - i32.eqz - br_if 1 (;@3;) - local.get 5 - i32.eqz - br_if 1 (;@3;) - local.get 4 - i32.load8_u - local.get 1 - i32.const 255 - i32.and - i32.eq - br_if 2 (;@2;) - local.get 2 - i32.const -3 - i32.add - local.tee 5 - i32.const 0 - i32.ne - local.set 3 - local.get 0 - i32.const 3 - i32.add - local.tee 4 - i32.const 3 - i32.and - i32.eqz - br_if 1 (;@3;) - local.get 5 - i32.eqz - br_if 1 (;@3;) - local.get 4 - i32.load8_u - local.get 1 - i32.const 255 - i32.and - i32.eq - br_if 2 (;@2;) - local.get 0 - i32.const 4 - i32.add - local.set 4 - local.get 2 - i32.const -4 - i32.add - local.tee 5 - i32.const 0 - i32.ne - local.set 3 - br 1 (;@3;) - end - local.get 2 - local.set 5 - local.get 0 - local.set 4 - end - local.get 3 - i32.eqz - br_if 1 (;@1;) - block ;; label = @3 - local.get 4 - i32.load8_u - local.get 1 - i32.const 255 - i32.and - i32.eq - br_if 0 (;@3;) - local.get 5 - i32.const 4 - i32.lt_u - br_if 0 (;@3;) - local.get 1 - i32.const 255 - i32.and - i32.const 16843009 - i32.mul - local.set 0 - loop ;; label = @4 - local.get 4 - i32.load - local.get 0 - i32.xor - local.tee 2 - i32.const -1 - i32.xor - local.get 2 - i32.const -16843009 - i32.add - i32.and - i32.const -2139062144 - i32.and - br_if 2 (;@2;) - local.get 4 - i32.const 4 - i32.add - local.set 4 - local.get 5 - i32.const -4 - i32.add - local.tee 5 - i32.const 3 - i32.gt_u - br_if 0 (;@4;) - end - end - local.get 5 - i32.eqz - br_if 1 (;@1;) - end - local.get 1 - i32.const 255 - i32.and - local.set 2 - loop ;; label = @2 - block ;; label = @3 - local.get 4 - i32.load8_u - local.get 2 - i32.ne - br_if 0 (;@3;) - local.get 4 - return - end - local.get 4 - i32.const 1 - i32.add - local.set 4 - local.get 5 - i32.const -1 - i32.add - local.tee 5 - br_if 0 (;@2;) - end - end - i32.const 0) - (func $strnlen (type 3) (param i32 i32) (result i32) - (local i32) - local.get 0 - i32.const 0 - local.get 1 - call $memchr - local.tee 2 - local.get 0 - i32.sub - local.get 1 - local.get 2 - select) - (table (;0;) 5 5 funcref) - (memory (;0;) 2) - (global $__stack_pointer (mut i32) (i32.const 70864)) - (export "memory" (memory 0)) - (export "_start" (func $_start)) - (elem (;0;) (i32.const 1) func $__stdio_write $__stdio_close $__stdout_write $__stdio_seek) - (data $.rodata (i32.const 1024) "-+ 0X0x\00-0X+0X 0X-0x+0x 0x\00nan\00inf\00NAN\00INF\00.\00(null)\00writing to pointer\0a\00malloc again %p\0a\00malloc returned %p\0a\00pointer contains %d, %d\0a\00Support for formatting long double values is currently disabled.\0aTo enable it, add -lc-printscan-long-double to the link command.\0a\00Success\00Illegal byte sequence\00Domain error\00Result not representable\00Not a tty\00Permission denied\00Operation not permitted\00No such file or directory\00No such process\00File exists\00Value too large for data type\00No space left on device\00Out of memory\00Resource busy\00Interrupted system call\00Resource temporarily unavailable\00Invalid seek\00Cross-device link\00Read-only file system\00Directory not empty\00Connection reset by peer\00Operation timed out\00Connection refused\00Host is unreachable\00Address in use\00Broken pipe\00I/O error\00No such device or address\00No such device\00Not a directory\00Is a directory\00Text file busy\00Exec format error\00Invalid argument\00Argument list too long\00Symbolic link loop\00Filename too long\00Too many open files in system\00No file descriptors available\00Bad file descriptor\00No child process\00Bad address\00File too large\00Too many links\00No locks available\00Resource deadlock would occur\00State not recoverable\00Previous owner died\00Operation canceled\00Function not implemented\00No message of desired type\00Identifier removed\00Link has been severed\00Protocol error\00Bad message\00Not a socket\00Destination address required\00Message too large\00Protocol wrong type for socket\00Protocol not available\00Protocol not supported\00Not supported\00Address family not supported by protocol\00Address not available\00Network is down\00Network unreachable\00Connection reset by network\00Connection aborted\00No buffer space available\00Socket is connected\00Socket not connected\00Operation already in progress\00Operation in progress\00Stale file handle\00Quota exceeded\00Multihop attempted\00Capabilities insufficient\00\00\00\00\00\00\00\00u\02N\00\d6\01\e2\04\b9\04\18\01\8e\05\ed\02\16\04\f2\00\97\03\01\038\05\af\01\82\01O\03/\04\1e\00\d4\05\a2\00\12\03\1e\03\c2\01\de\03\08\00\ac\05\00\01d\02\f1\01e\054\02\8c\02\cf\02-\03L\04\e3\05\9f\02\f8\04\1c\05\08\05\b1\02K\05\15\02x\00R\02<\03\f1\03\e4\00\c3\03}\04\cc\00\aa\03y\05$\02n\01m\03\22\04\ab\04D\00\fb\01\ae\00\83\03`\00\e5\01\07\04\94\04^\04+\00X\019\01\92\00\c2\05\9b\01C\02F\01\f6\05\00\00\00\00\00\00\19\00\0a\00\19\19\19\00\00\00\00\05\00\00\00\00\00\00\09\00\00\00\00\0b\00\00\00\00\00\00\00\00\19\00\11\0a\19\19\19\03\0a\07\00\01\1b\09\0b\18\00\00\09\06\0b\00\00\0b\00\06\19\00\00\00\19\19\19\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0e\00\00\00\00\00\00\00\00\19\00\0a\0d\19\19\19\00\0d\00\00\02\00\09\0e\00\00\00\09\00\0e\00\00\0e\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\13\00\00\00\00\13\00\00\00\00\09\0c\00\00\00\00\00\0c\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\10\00\00\00\00\00\00\00\00\00\00\00\0f\00\00\00\04\0f\00\00\00\00\09\10\00\00\00\00\00\10\00\00\10\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\12\00\00\00\00\00\00\00\00\00\00\00\11\00\00\00\00\11\00\00\00\00\09\12\00\00\00\00\00\12\00\00\12\00\00\1a\00\00\00\1a\1a\1a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\1a\00\00\00\1a\1a\1a\00\00\00\00\00\00\09\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\14\00\00\00\00\00\00\00\00\00\00\00\17\00\00\00\00\17\00\00\00\00\09\14\00\00\00\00\00\14\00\00\14\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\16\00\00\00\00\00\00\00\00\00\00\00\15\00\00\00\00\15\00\00\00\00\09\16\00\00\00\00\00\16\00\00\16\00\000123456789ABCDEF") - (data $.data (i32.const 3488) "\05\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\00\00\00\04\00\00\00\98\10\00\00\00\04\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\0a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\a0\0d\00\00\00\00\00\00\05\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\04\00\00\00\c4\14\00\00\00\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\ff\ff\ff\ff\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\18\0e\00\00")) From c108c5f322060199746c69bc3dc15740642031f9 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Tue, 8 Aug 2023 15:08:26 -0700 Subject: [PATCH 24/34] doc comments in spec.rs --- cranelift/wasm/src/environ/spec.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index 3aafb679a7c4..c6682a1acb6a 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -588,19 +588,24 @@ pub trait FuncEnvironment: TargetEnvironment { false } - /// + /// Inserts call to check_malloc and check_free before the return of malloc + /// and free if wasmtime is compiled and run with valgrind. fn handle_before_return(&mut self, retvals: &[ir::Value], builder: &mut FunctionBuilder) {} - /// + /// Inserts call to check_load before a load instruction if wasmtime is + /// compiled and run with valgrind. fn before_load(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) {} - /// + /// Inserts call to check_store before a store instruction if wasmtime is + /// compiled and run with valgrind. fn before_store(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) {} - /// + /// Inserts call to update_stack_pointer when stack pointer is updated if + /// wasmtime is compiled and run with valgrind. fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) {} - /// + /// Inserts calls to update_mem_size after memory.grow if wasmtime is + /// compiled and run with valgrind. fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, num_bytes: ir::Value) {} } From 36bbfd99aef76d8a399ed87822285feb40821b29 Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Thu, 10 Aug 2023 11:28:55 -0700 Subject: [PATCH 25/34] pr feedback addressed --- .github/workflows/main.yml | 1 + Cargo.lock | 10 +- Cargo.toml | 6 +- cranelift/wasm/src/code_translator.rs | 3 +- cranelift/wasm/src/environ/spec.rs | 20 +-- cranelift/wasm/src/sections_translator.rs | 1 - crates/cranelift/Cargo.toml | 2 +- crates/cranelift/src/builder.rs | 10 +- crates/cranelift/src/compiler.rs | 8 +- crates/cranelift/src/func_environ.rs | 115 +++++++------ crates/environ/src/compilation.rs | 4 +- crates/runtime/Cargo.toml | 4 +- crates/runtime/src/instance.rs | 29 ++-- crates/runtime/src/instance/allocator.rs | 4 +- crates/runtime/src/libcalls.rs | 74 ++++---- crates/types/src/lib.rs | 2 +- crates/valgrind/Cargo.toml | 8 - crates/wasmtime/Cargo.toml | 2 +- crates/wasmtime/src/config.rs | 18 +- crates/wasmtime/src/instance.rs | 2 +- crates/wasmtime/src/module.rs | 2 +- crates/wasmtime/src/store.rs | 2 +- crates/wasmtime/src/trampoline.rs | 2 +- crates/wasmtime/src/trampoline/memory.rs | 2 +- crates/wmemcheck/Cargo.toml | 11 ++ .../{valgrind => wmemcheck}/fuzz/.gitignore | 0 .../{valgrind => wmemcheck}/fuzz/Cargo.lock | 6 +- .../{valgrind => wmemcheck}/fuzz/Cargo.toml | 4 +- .../fuzz/fuzz_targets/buggy_accesses.rs | 14 +- .../fuzz/fuzz_targets/valid_accesses.rs | 14 +- crates/{valgrind => wmemcheck}/src/lib.rs | 159 +++++++++--------- docs/wmemcheck.md | 8 + src/commands/run.rs | 9 +- 33 files changed, 301 insertions(+), 255 deletions(-) delete mode 100644 crates/valgrind/Cargo.toml create mode 100644 crates/wmemcheck/Cargo.toml rename crates/{valgrind => wmemcheck}/fuzz/.gitignore (100%) rename crates/{valgrind => wmemcheck}/fuzz/Cargo.lock (98%) rename crates/{valgrind => wmemcheck}/fuzz/Cargo.toml (90%) rename crates/{valgrind => wmemcheck}/fuzz/fuzz_targets/buggy_accesses.rs (94%) rename crates/{valgrind => wmemcheck}/fuzz/fuzz_targets/valid_accesses.rs (94%) rename crates/{valgrind => wmemcheck}/src/lib.rs (66%) create mode 100644 docs/wmemcheck.md diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9d64ba405913..fdfe2a6f83cb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -266,6 +266,7 @@ jobs: - run: cargo check -p wasmtime --no-default-features --features component-model - run: cargo check -p wasmtime --no-default-features --features cranelift,wat,async,cache - run: cargo check -p wasmtime --no-default-features --features winch + - run: cargo check -p wasmtime --no-default-features --features wmemcheck - run: cargo check --features component-model - run: cargo check -p wasmtime --features incremental-cache diff --git a/Cargo.lock b/Cargo.lock index 2820595e5261..4dfe5e6dd49d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3205,10 +3205,6 @@ dependencies = [ "wat", ] -[[package]] -name = "wasm-valgrind" -version = "0.1.0" - [[package]] name = "wasmi" version = "0.20.0" @@ -3696,13 +3692,13 @@ dependencies = [ "rustix 0.38.4", "sptr", "wasm-encoder 0.31.1", - "wasm-valgrind", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-fiber", "wasmtime-jit-debug", "wasmtime-versioned-export-macros", "windows-sys", + "wmemcheck", ] [[package]] @@ -4231,6 +4227,10 @@ dependencies = [ "wast 35.0.2", ] +[[package]] +name = "wmemcheck" +version = "13.0.0" + [[package]] name = "zstd" version = "0.11.1+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index b2d0f7b386fb..6ba0134f1cea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,7 +100,7 @@ members = [ "crates/test-programs/wasi-http-tests", "crates/test-programs/command-tests", "crates/test-programs/reactor-tests", - "crates/valgrind", + "crates/wmemcheck", "crates/wasi-preview1-component-adapter", "crates/wasi-preview1-component-adapter/verify", "crates/winch", @@ -123,7 +123,7 @@ edition = "2021" rust-version = "1.66.0" [workspace.dependencies] -wasm-valgrind = { path = "crates/valgrind", version = "0.1.0" } +wmemcheck = { path = "crates/wmemcheck", version = "13.0.0" } wasmtime = { path = "crates/wasmtime", version = "13.0.0", default-features = false } wasmtime-cache = { path = "crates/cache", version = "=13.0.0" } wasmtime-cli-flags = { path = "crates/cli-flags", version = "=13.0.0" } @@ -274,7 +274,7 @@ component-model = [ "wasmtime-cli-flags/component-model" ] winch = ["wasmtime/winch"] -valgrind = ["wasmtime/valgrind"] +wmemcheck = ["wasmtime/wmemcheck"] [[test]] name = "host_segfault" diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 37fcf97a352e..6fe39be939b7 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -759,7 +759,7 @@ pub fn translate_operator( let heap_index = MemoryIndex::from_u32(*mem); let heap = state.get_heap(builder.func, *mem, environ)?; let val = state.pop1(); - environ.before_memory_grow(builder, val); + environ.before_memory_grow(builder, val, heap_index); state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?) } Operator::MemorySize { mem, mem_byte: _ } => { @@ -862,6 +862,7 @@ pub fn translate_operator( ); } Operator::V128Load8x8S { memarg } => { + //TODO(#6829): add before_load() and before_store() hooks for SIMD loads and stores. let (flags, _, base) = unwrap_or_return_unreachable_state!( state, prepare_addr(memarg, 8, builder, state, environ)? diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index 84c295117cd6..ff5eac0a9974 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -650,24 +650,24 @@ pub trait FuncEnvironment: TargetEnvironment { } /// Inserts call to check_malloc and check_free before the return of malloc - /// and free if wasmtime is compiled and run with valgrind. - fn handle_before_return(&mut self, retvals: &[ir::Value], builder: &mut FunctionBuilder) {} + /// and free if wasmtime is compiled and run with wmemcheck. + fn handle_before_return(&mut self, _retvals: &[ir::Value], _builder: &mut FunctionBuilder) {} /// Inserts call to check_load before a load instruction if wasmtime is - /// compiled and run with valgrind. - fn before_load(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) {} + /// compiled and run with wmemcheck. + fn before_load(&mut self, _builder: &mut FunctionBuilder, _val_size: u8, _addr: ir::Value, _offset: u64) {} /// Inserts call to check_store before a store instruction if wasmtime is - /// compiled and run with valgrind. - fn before_store(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) {} + /// compiled and run with wmemcheck. + fn before_store(&mut self, _builder: &mut FunctionBuilder, _val_size: u8, _addr: ir::Value, _offset: u64) {} /// Inserts call to update_stack_pointer when stack pointer is updated if - /// wasmtime is compiled and run with valgrind. - fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) {} + /// wasmtime is compiled and run with wmemcheck. + fn update_global(&mut self, _builder: &mut FunctionBuilder, _global_index: u32, _value: ir::Value) {} /// Inserts calls to update_mem_size after memory.grow if wasmtime is - /// compiled and run with valgrind. - fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, num_bytes: ir::Value) {} + /// compiled and run with wmemcheck. + fn before_memory_grow(&mut self, _builder: &mut FunctionBuilder, _num_bytes: ir::Value, _mem_index: MemoryIndex) {} } /// An object satisfying the `ModuleEnvironment` trait can be passed as argument to the diff --git a/cranelift/wasm/src/sections_translator.rs b/cranelift/wasm/src/sections_translator.rs index 466220b070dd..b0abcbf324af 100644 --- a/cranelift/wasm/src/sections_translator.rs +++ b/cranelift/wasm/src/sections_translator.rs @@ -388,7 +388,6 @@ pub fn parse_name_section<'data>( // We reserve `u32::MAX` for our own use in cranelift-entity. if index != u32::max_value() { environ.declare_func_name(FuncIndex::from_u32(index), name); - //this is where the function name is translated CLIF } } } diff --git a/crates/cranelift/Cargo.toml b/crates/cranelift/Cargo.toml index 4650c57f9d3d..e7318e4abc42 100644 --- a/crates/cranelift/Cargo.toml +++ b/crates/cranelift/Cargo.toml @@ -33,4 +33,4 @@ wasmtime-versioned-export-macros = { workspace = true } all-arch = ["cranelift-codegen/all-arch"] component-model = ["wasmtime-environ/component-model"] incremental-cache = ["cranelift-codegen/incremental-cache"] -valgrind = [] \ No newline at end of file +wmemcheck = [] diff --git a/crates/cranelift/src/builder.rs b/crates/cranelift/src/builder.rs index 432700bc834e..b2c86107cb7c 100644 --- a/crates/cranelift/src/builder.rs +++ b/crates/cranelift/src/builder.rs @@ -20,7 +20,7 @@ struct Builder { linkopts: LinkOptions, cache_store: Option>, clif_dir: Option, - valgrind: bool, + wmemcheck: bool, } #[derive(Clone, Default)] @@ -43,7 +43,7 @@ pub fn builder() -> Box { linkopts: LinkOptions::default(), cache_store: None, clif_dir: None, - valgrind: false, + wmemcheck: false, }) } @@ -93,7 +93,7 @@ impl CompilerBuilder for Builder { self.cache_store.clone(), self.linkopts.clone(), self.clif_dir.clone(), - self.valgrind, + self.wmemcheck, ))) } @@ -109,8 +109,8 @@ impl CompilerBuilder for Builder { Ok(()) } - fn valgrind(&mut self, enable: bool) { - self.valgrind = enable; + fn wmemcheck(&mut self, enable: bool) { + self.wmemcheck = enable; } } diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs index 53e3c7e21e5f..410a8d0edaf3 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs @@ -71,7 +71,7 @@ pub(crate) struct Compiler { linkopts: LinkOptions, cache_store: Option>, clif_dir: Option, - valgrind: bool, + wmemcheck: bool, } impl Drop for Compiler { @@ -109,7 +109,7 @@ impl Compiler { cache_store: Option>, linkopts: LinkOptions, clif_dir: Option, - valgrind: bool, + wmemcheck: bool, ) -> Compiler { Compiler { contexts: Default::default(), @@ -118,7 +118,7 @@ impl Compiler { linkopts, cache_store, clif_dir, - valgrind, + wmemcheck, } } } @@ -150,7 +150,7 @@ impl wasmtime_environ::Compiler for Compiler { context.func.collect_debug_info(); } - let mut func_env = FuncEnvironment::new(isa, translation, types, &self.tunables, self.valgrind); + let mut func_env = FuncEnvironment::new(isa, translation, types, &self.tunables, self.wmemcheck); // The `stack_limit` global value below is the implementation of stack // overflow checks in Wasmtime. diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 522720284b4f..16d57f63001d 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -20,7 +20,7 @@ use wasmtime_environ::{ BuiltinFunctionIndex, MemoryPlan, MemoryStyle, Module, ModuleTranslation, ModuleTypes, PtrSize, TableStyle, Tunables, TypeConvert, VMOffsets, WASM_PAGE_SIZE, }; -use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK}; // is this the right place to import Value from? +use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK}; use cfg_if::cfg_if; macro_rules! declare_function_signatures { @@ -154,7 +154,8 @@ pub struct FuncEnvironment<'module_environment> { fuel_consumed: i64, - valgrind: bool, + #[cfg(feature = "wmemcheck")] + wmemcheck: bool, } impl<'module_environment> FuncEnvironment<'module_environment> { @@ -163,7 +164,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { translation: &'module_environment ModuleTranslation<'module_environment>, types: &'module_environment ModuleTypes, tunables: &'module_environment Tunables, - valgrind: bool, + wmemcheck: bool, ) -> Self { let builtin_function_signatures = BuiltinFunctionSignatures::new( isa.pointer_type(), @@ -174,6 +175,11 @@ impl<'module_environment> FuncEnvironment<'module_environment> { }, CallConv::triple_default(isa.triple()), ); + + // Avoid unused warning in default build. + #[cfg(not(feature = "wmemcheck"))] + let _ = wmemcheck; + Self { isa, module: &translation.module, @@ -192,7 +198,8 @@ impl<'module_environment> FuncEnvironment<'module_environment> { // Start with at least one fuel being consumed because even empty // functions should consume at least some fuel. fuel_consumed: 1, - valgrind, + #[cfg(feature = "wmemcheck")] + wmemcheck, } } @@ -201,8 +208,6 @@ impl<'module_environment> FuncEnvironment<'module_environment> { } fn vmctx(&mut self, func: &mut Function) -> ir::GlobalValue { - //arbitrarily printing funcname/index from inside func_environ - // println!("from vmctx {:?}", self.translation.debuginfo.name_section.func_names); self.vmctx.unwrap_or_else(|| { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); self.vmctx = Some(vmctx); @@ -614,27 +619,46 @@ impl<'module_environment> FuncEnvironment<'module_environment> { self.epoch_check(builder); } - #[cfg(feature = "valgrind")] - fn check_malloc_exit(&mut self, builder: &mut FunctionBuilder, retvals: &[Value]) { + #[cfg(feature = "wmemcheck")] + fn hook_malloc_exit(&mut self, builder: &mut FunctionBuilder, retvals: &[Value]) { let check_malloc_sig = self.builtin_function_signatures.check_malloc(builder.func); let (vmctx, check_malloc) = self.translate_load_builtin_function_address( &mut builder.cursor(), BuiltinFunctionIndex::check_malloc(), ); - let len = builder.func.dfg.block_params(builder.func.layout.entry_block().unwrap())[2]; + let func_args = builder.func.dfg.block_params(builder.func.layout.entry_block().unwrap()); + let len = if func_args.len() < 3 { + return; + } else { + // If a function named `malloc` has at least one argument, we assume the + // first argument is the requested allocation size. + func_args[2] + }; + let retval = if retvals.len() < 1 { + return; + } else { + retvals[0] + }; builder .ins() - .call_indirect(check_malloc_sig, check_malloc, &[vmctx, retvals[0], len]); + .call_indirect(check_malloc_sig, check_malloc, &[vmctx, retval, len]); } - #[cfg(feature = "valgrind")] - fn check_free_exit(&mut self, builder: &mut FunctionBuilder) { + #[cfg(feature = "wmemcheck")] + fn hook_free_exit(&mut self, builder: &mut FunctionBuilder) { let check_free_sig = self.builtin_function_signatures.check_free(builder.func); let (vmctx, check_free) = self.translate_load_builtin_function_address( &mut builder.cursor(), BuiltinFunctionIndex::check_free(), ); - let ptr = builder.func.dfg.block_params(builder.func.layout.entry_block().unwrap())[2]; + let func_args = builder.func.dfg.block_params(builder.func.layout.entry_block().unwrap()); + let ptr = if func_args.len() < 3 { + return; + } else { + // If a function named `free` has at least one argument, we assume the + // first argument is a pointer to memory. + func_args[2] + }; builder .ins() .call_indirect(check_free_sig, check_free, &[vmctx, ptr]); @@ -871,6 +895,18 @@ impl<'module_environment> FuncEnvironment<'module_environment> { .ins() .call_indirect(free_start_sig, free_start, &[vmctx]); } + + fn current_func_name(&self, builder: &mut FunctionBuilder) -> Option<&str> { + let func_index = match &builder.func.name { + UserFuncName::User(user) => { + FuncIndex::from_u32(user.index) + } + _ => { + panic!("function name not a UserFuncName::User as expected") + } + }; + self.translation.debuginfo.name_section.func_names.get(&func_index).map(|s| *s) + } } struct Call<'a, 'func, 'module_env> { @@ -2393,18 +2429,10 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m self.epoch_function_entry(builder); } - let func_index = match &builder.func.name { - UserFuncName::User(user) => { - FuncIndex::from_u32(user.index) - } - _ => { - unreachable!() - } - }; - let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; - if func_name == "malloc" { + let func_name = self.current_func_name(builder); + if func_name == Some("malloc") { self.check_malloc_start(builder); - } else if func_name == "free" { + } else if func_name == Some("free") { self.check_free_start(builder); } @@ -2451,32 +2479,24 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } cfg_if! { - if #[cfg(feature = "valgrind")] { + if #[cfg(feature = "wmemcheck")] { fn handle_before_return( &mut self, retvals: &[Value], builder: &mut FunctionBuilder, ) { - if self.valgrind { - let func_index = match &builder.func.name { - UserFuncName::User(user) => { - FuncIndex::from_u32(user.index) - } - _ => { - unreachable!() - } - }; - let func_name = self.translation.debuginfo.name_section.func_names[&func_index]; - if func_name == "malloc" { - self.check_malloc_exit(builder, retvals); - } else if func_name == "free" { - self.check_free_exit(builder); + if self.wmemcheck { + let func_name = self.current_func_name(builder); + if func_name == Some("malloc") { + self.hook_malloc_exit(builder, retvals); + } else if func_name == Some("free") { + self.hook_free_exit(builder); } } } fn before_load(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) { - if self.valgrind { + if self.wmemcheck { let check_load_sig = self.builtin_function_signatures.check_load(builder.func); let (vmctx, check_load) = self.translate_load_builtin_function_address( &mut builder.cursor(), @@ -2491,7 +2511,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } fn before_store(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) { - if self.valgrind { + if self.wmemcheck { let check_store_sig = self.builtin_function_signatures.check_store(builder.func); let (vmctx, check_store) = self.translate_load_builtin_function_address( &mut builder.cursor(), @@ -2506,8 +2526,9 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } fn update_global(&mut self, builder: &mut FunctionBuilder, global_index: u32, value: ir::Value) { - if self.valgrind { + if self.wmemcheck { if global_index == 0 { + // We are making the assumption that global 0 is the auxiliary stack pointer. let update_stack_pointer_sig = self.builtin_function_signatures.update_stack_pointer(builder.func); let (vmctx, update_stack_pointer) = self.translate_load_builtin_function_address( &mut builder.cursor(), @@ -2520,8 +2541,8 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } } - fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, num_pages: ir::Value) { - if self.valgrind { + fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, num_pages: ir::Value, mem_index: MemoryIndex) { + if self.wmemcheck && mem_index.0 == 0 { let update_mem_size_sig = self.builtin_function_signatures.update_mem_size(builder.func); let (vmctx, update_mem_size) = self.translate_load_builtin_function_address( &mut builder.cursor(), @@ -2538,11 +2559,11 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m let _ = self.builtin_function_signatures.check_free(builder.func); } - fn before_load(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { + fn before_load(&mut self, builder: &mut FunctionBuilder, _val_size: u8, _addr: ir::Value, _offset: u64) { let _ = self.builtin_function_signatures.check_load(builder.func); } - fn before_store(&mut self, builder: &mut FunctionBuilder, _val_type: Type, _addr: ir::Value, _offset: u64) { + fn before_store(&mut self, builder: &mut FunctionBuilder, _val_size: u8, _addr: ir::Value, _offset: u64) { let _ = self.builtin_function_signatures.check_store(builder.func); } @@ -2550,7 +2571,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m let _ = self.builtin_function_signatures.update_stack_pointer(builder.func); } - fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, _num_pages: Value) { + fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, _num_pages: Value, _mem_index: MemoryIndex) { let _ = self.builtin_function_signatures.update_mem_size(builder.func); } } diff --git a/crates/environ/src/compilation.rs b/crates/environ/src/compilation.rs index 2bb0ae11e2a0..dc5ddc32cf38 100644 --- a/crates/environ/src/compilation.rs +++ b/crates/environ/src/compilation.rs @@ -128,8 +128,8 @@ pub trait CompilerBuilder: Send + Sync + fmt::Debug { /// Builds a new [`Compiler`] object from this configuration. fn build(&self) -> Result>; - /// Enables or disables valgrind during runtime according to the valgrind CLI flag. - fn valgrind(&mut self, enable: bool) {} + /// Enables or disables wmemcheck during runtime according to the wmemcheck CLI flag. + fn wmemcheck(&mut self, _enable: bool) {} } /// Description of compiler settings returned by [`CompilerBuilder::settings`]. diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index 4d7fd7ee7bbb..f8bc97fb6cc9 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/bytecodealliance/wasmtime" edition.workspace = true [dependencies] -wasm-valgrind = { workspace = true } +wmemcheck = { workspace = true } wasmtime-asm-macros = { workspace = true } wasmtime-environ = { workspace = true } wasmtime-fiber = { workspace = true, optional = true } @@ -71,4 +71,4 @@ component-model = [ "dep:encoding_rs", ] -valgrind = [] \ No newline at end of file +wmemcheck = [] diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index 6ad973f5dc8a..ed7da318729e 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -15,8 +15,8 @@ use crate::{ ExportFunction, ExportGlobal, ExportMemory, ExportTable, Imports, ModuleRuntimeInfo, SendSyncPtr, Store, VMFunctionBody, VMSharedSignatureIndex, WasmFault, }; -#[cfg(feature = "valgrind")] -use wasm_valgrind::Valgrind; +#[cfg(feature = "wmemcheck")] +use wmemcheck::Wmemcheck; use anyhow::Error; use anyhow::Result; use sptr::Strict; @@ -143,8 +143,10 @@ pub struct Instance { /// seems not too bad. vmctx_self_reference: SendSyncPtr, - #[cfg(feature = "valgrind")] - pub(crate) valgrind_state: Option, + #[cfg(feature = "wmemcheck")] + pub(crate) wmemcheck_state: Option, + // TODO: add support for multiple memories, wmemcheck_state corresponds to + // memory 0. /// Additional context used by compiled wasm code. This field is last, and /// represents a dynamically-sized array that extends beyond the nominal @@ -177,6 +179,9 @@ impl Instance { let dropped_elements = EntitySet::with_capacity(module.passive_elements.len()); let dropped_data = EntitySet::with_capacity(module.passive_data_map.len()); + #[cfg(not(feature = "wmemcheck"))] + let _ = memory_plans; + ptr::write( ptr, Instance { @@ -193,12 +198,11 @@ impl Instance { vmctx: VMContext { _marker: std::marker::PhantomPinned, }, - #[cfg(feature = "valgrind")] - valgrind_state: { - if req.valgrind { + #[cfg(feature = "wmemcheck")] + wmemcheck_state: { + if req.wmemcheck { let size = memory_plans.iter().next().map(|plan| plan.1.memory.minimum).unwrap_or(0) * 64 * 1024; - println!("this is the size: {}", size); - Some(Valgrind::new(size as usize)) + Some(Wmemcheck::new(size as usize)) } else { None } @@ -1146,10 +1150,9 @@ impl Instance { GlobalInit::I32Const(x) => { let index = module.global_index(index); if index.index() == 0 { - println!("stack pointer: {}", x); - #[cfg(feature = "valgrind")] { - if let Some(valgrind) = &mut self.valgrind_state { - valgrind.set_stack_size(x as usize); + #[cfg(feature = "wmemcheck")] { + if let Some(wmemcheck) = &mut self.wmemcheck_state { + wmemcheck.set_stack_size(x as usize); } } } diff --git a/crates/runtime/src/instance/allocator.rs b/crates/runtime/src/instance/allocator.rs index 70fd0ddbe7f7..bb21054a6013 100644 --- a/crates/runtime/src/instance/allocator.rs +++ b/crates/runtime/src/instance/allocator.rs @@ -54,8 +54,8 @@ pub struct InstanceAllocationRequest<'a> { /// compiler. More info on this in `wasmtime/src/store.rs` pub store: StorePtr, - /// Indicates '--valgrind' flag. - pub valgrind: bool, + /// Indicates '--wmemcheck' flag. + pub wmemcheck: bool, } /// A pointer to a Store. This Option<*mut dyn Store> is wrapped in a struct diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 284177c3a425..2f406d76e4af 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -58,8 +58,8 @@ use crate::externref::VMExternRef; use crate::table::{Table, TableElementType}; use crate::vmcontext::VMFuncRef; use crate::{Instance, TrapReason}; -#[cfg(feature = "valgrind")] -use wasm_valgrind::AccessError::{DoubleMalloc, InvalidRead, InvalidWrite, InvalidFree, OutOfBounds}; +#[cfg(feature = "wmemcheck")] +use wmemcheck::AccessError::{DoubleMalloc, InvalidRead, InvalidWrite, InvalidFree, OutOfBounds}; use anyhow::Result; use std::mem; use std::ptr::{self, NonNull}; @@ -68,6 +68,7 @@ use wasmtime_environ::{ DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Trap, }; use cfg_if::cfg_if; +#[cfg(feature = "wmemcheck")] use anyhow::bail; /// Actually public trampolines which are used by the runtime as the entrypoint @@ -493,12 +494,12 @@ unsafe fn new_epoch(instance: &mut Instance) -> Result { } cfg_if! { - if #[cfg(feature = "valgrind")] { - // Hook for validating malloc using valgrind_state. + if #[cfg(feature = "wmemcheck")] { + // Hook for validating malloc using wmemcheck_state. unsafe fn check_malloc(instance: &mut Instance, addr: u32, len: u32) -> Result { - if let Some(valgrind_state) = &mut instance.valgrind_state { - let result = valgrind_state.malloc(addr as usize, len as usize); - valgrind_state.memcheck_on(); + if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + let result = wmemcheck_state.malloc(addr as usize, len as usize); + wmemcheck_state.memcheck_on(); match result { Ok(()) => { return Ok(0); @@ -517,11 +518,11 @@ cfg_if! { Ok(0) } - // Hook for validating free using valgrind_state. + // Hook for validating free using wmemcheck_state. unsafe fn check_free(instance: &mut Instance, addr: u32) -> Result { - if let Some(valgrind_state) = &mut instance.valgrind_state { - let result = valgrind_state.free(addr as usize); - valgrind_state.memcheck_on(); + if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + let result = wmemcheck_state.free(addr as usize); + wmemcheck_state.memcheck_on(); match result { Ok(()) => { return Ok(0); @@ -537,10 +538,10 @@ cfg_if! { Ok(0) } - // Hook for validating load using valgrind_state. + // Hook for validating load using wmemcheck_state. fn check_load(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) -> Result { - if let Some(valgrind_state) = &mut instance.valgrind_state { - let result = valgrind_state.read(addr as usize + offset as usize, num_bytes as usize); + if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + let result = wmemcheck_state.read(addr as usize + offset as usize, num_bytes as usize); match result { Ok(()) => { return Ok(0); @@ -559,10 +560,10 @@ cfg_if! { Ok(0) } - // Hook for validating store using valgrind_state. + // Hook for validating store using wmemcheck_state. fn check_store(instance: &mut Instance, num_bytes: u32, addr: u32, offset: u32) -> Result { - if let Some(valgrind_state) = &mut instance.valgrind_state { - let result = valgrind_state.write(addr as usize + offset as usize, num_bytes as usize); + if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + let result = wmemcheck_state.write(addr as usize + offset as usize, num_bytes as usize); match result { Ok(()) => { return Ok(0); @@ -581,37 +582,40 @@ cfg_if! { Ok(0) } - // Hook for turning valgrind load/store validation off when entering a malloc function. + // Hook for turning wmemcheck load/store validation off when entering a malloc function. fn malloc_start(instance: &mut Instance) { - if let Some(valgrind_state) = &mut instance.valgrind_state { - valgrind_state.memcheck_off(); + if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + wmemcheck_state.memcheck_off(); } } - // Hook for turning valgrind load/store validation off when entering a free function. + // Hook for turning wmemcheck load/store validation off when entering a free function. fn free_start(instance: &mut Instance) { - if let Some(valgrind_state) = &mut instance.valgrind_state { - valgrind_state.memcheck_off(); + if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + wmemcheck_state.memcheck_off(); } } - // Hook for tracking wasm stack updates using valgrind_state. - fn update_stack_pointer(instance: &mut Instance, value: u32) { - if let Some(valgrind_state) = &mut instance.valgrind_state { - // instance.valgrind_state.update_stack_pointer(value as usize); - } + // Hook for tracking wasm stack updates using wmemcheck_state. + fn update_stack_pointer(_instance: &mut Instance, _value: u32) { + // TODO: stack-tracing has yet to be finalized. All memory below + // the address of the top of the stack is marked as valid for + // loads and stores. + // if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + // instance.wmemcheck_state.update_stack_pointer(value as usize); + // } } - // Hook updating valgrind_state memory state vector every time memory.grow is called. + // Hook updating wmemcheck_state memory state vector every time memory.grow is called. fn update_mem_size(instance: &mut Instance, num_pages: u32) { - if let Some(valgrind_state) = &mut instance.valgrind_state { - let kib: usize = 1024; - let num_bytes = num_pages as usize * kib * 64; - valgrind_state.update_mem_size(num_bytes); + if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + const KIB: usize = 1024; + let num_bytes = num_pages as usize * 64 * KIB; + wmemcheck_state.update_mem_size(num_bytes); } } } else { - // No-op for all valgrind hooks. + // No-op for all wmemcheck hooks. unsafe fn check_malloc(_instance: &mut Instance, _addr: u32, _len: u32) -> Result { Ok(0) } unsafe fn check_free(_instance: &mut Instance, _addr: u32) -> Result { Ok(0) } @@ -626,7 +630,7 @@ cfg_if! { fn update_stack_pointer(_instance: &mut Instance, _value: u32) {} - fn update_mem_size(instance: &mut Instance, _num_pages: u32) {} + fn update_mem_size(_instance: &mut Instance, _num_pages: u32) {} } } diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 320c6e479d99..0dc5db6aacf9 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -203,7 +203,7 @@ entity_impl!(GlobalIndex); /// Index type of a linear memory (imported or defined) inside the WebAssembly module. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] -pub struct MemoryIndex(u32); +pub struct MemoryIndex(pub u32); entity_impl!(MemoryIndex); /// Index type of a signature (imported or defined) inside the WebAssembly module. diff --git a/crates/valgrind/Cargo.toml b/crates/valgrind/Cargo.toml deleted file mode 100644 index da0a9553d316..000000000000 --- a/crates/valgrind/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "wasm-valgrind" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 5a127b4a916c..2c38ce945f6b 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -136,4 +136,4 @@ component-model = [ "dep:encoding_rs", ] -valgrind = ["wasmtime-runtime/valgrind", "wasmtime-cranelift/valgrind"] \ No newline at end of file +wmemcheck = ["wasmtime-runtime/wmemcheck", "wasmtime-cranelift/wmemcheck"] \ No newline at end of file diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 0f906b08a629..4993a713015e 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -110,7 +110,7 @@ pub struct Config { pub(crate) memory_init_cow: bool, pub(crate) memory_guaranteed_dense_image_size: u64, pub(crate) force_memory_init_memfd: bool, - pub(crate) valgrind: bool, + pub(crate) wmemcheck: bool, pub(crate) coredump_on_trap: bool, } @@ -125,7 +125,7 @@ struct CompilerConfig { #[cfg(any(feature = "cranelift", feature = "winch"))] cache_store: Option>, clif_dir: Option, - valgrind: bool, + wmemcheck: bool, } #[cfg(any(feature = "cranelift", feature = "winch"))] @@ -138,7 +138,7 @@ impl CompilerConfig { flags: HashSet::new(), cache_store: None, clif_dir: None, - valgrind: false, + wmemcheck: false, } } @@ -203,7 +203,7 @@ impl Config { memory_init_cow: true, memory_guaranteed_dense_image_size: 16 << 20, force_memory_init_memfd: false, - valgrind: false, + wmemcheck: false, coredump_on_trap: false, }; #[cfg(any(feature = "cranelift", feature = "winch"))] @@ -1482,10 +1482,12 @@ impl Config { self } + /// Enables memory error checking for wasm programs. + /// /// This option is disabled by default. - pub fn valgrind(&mut self, enable: bool) -> &mut Self { - self.valgrind = enable; - self.compiler_config.valgrind = enable; + pub fn wmemcheck(&mut self, enable: bool) -> &mut Self { + self.wmemcheck = enable; + self.compiler_config.wmemcheck = enable; self } @@ -1685,7 +1687,7 @@ impl Config { } compiler.set_tunables(self.tunables.clone())?; - compiler.valgrind(self.compiler_config.valgrind); + compiler.wmemcheck(self.compiler_config.wmemcheck); Ok((self, compiler.build()?)) } diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index 08e7b08927e8..13cde5749d91 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -274,7 +274,7 @@ impl Instance { imports, host_state: Box::new(Instance(instance_to_be)), store: StorePtr::new(store.traitobj()), - valgrind: store.engine().config().valgrind, + wmemcheck: store.engine().config().wmemcheck, })?; // The instance still has lots of setup, for example diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index 7ca7dd0d607b..7d525d99c52e 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -1143,7 +1143,7 @@ impl std::hash::Hash for HashedEngineCompileEnv<'_> { let config = self.0.config(); config.tunables.hash(hasher); config.features.hash(hasher); - config.valgrind.hash(hasher); + config.wmemcheck.hash(hasher); // Catch accidental bugs of reusing across crate versions. config.module_version.hash(hasher); diff --git a/crates/wasmtime/src/store.rs b/crates/wasmtime/src/store.rs index 15f963be49c7..788b69608a92 100644 --- a/crates/wasmtime/src/store.rs +++ b/crates/wasmtime/src/store.rs @@ -511,7 +511,7 @@ impl Store { imports: Default::default(), store: StorePtr::empty(), runtime_info: &shim, - valgrind: engine.config().valgrind, + wmemcheck: engine.config().wmemcheck, }) .expect("failed to allocate default callee"); diff --git a/crates/wasmtime/src/trampoline.rs b/crates/wasmtime/src/trampoline.rs index e712ac127abe..0c7e45933632 100644 --- a/crates/wasmtime/src/trampoline.rs +++ b/crates/wasmtime/src/trampoline.rs @@ -47,7 +47,7 @@ fn create_handle( host_state, store: StorePtr::new(store.traitobj()), runtime_info, - valgrind: false, + wmemcheck: false, }, )?; diff --git a/crates/wasmtime/src/trampoline/memory.rs b/crates/wasmtime/src/trampoline/memory.rs index 2813cf1d78f0..3bd085d966de 100644 --- a/crates/wasmtime/src/trampoline/memory.rs +++ b/crates/wasmtime/src/trampoline/memory.rs @@ -56,7 +56,7 @@ pub fn create_memory( host_state, store: StorePtr::new(store.traitobj()), runtime_info, - valgrind: false, + wmemcheck: false, }; unsafe { diff --git a/crates/wmemcheck/Cargo.toml b/crates/wmemcheck/Cargo.toml new file mode 100644 index 000000000000..cfbafd3c6e70 --- /dev/null +++ b/crates/wmemcheck/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "wmemcheck" +version.workspace = true +authors.workspace = true +description = "Memcheck implementation for Wasmtime" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" +documentation = "https://docs.rs/wasmtime-cranelift/" +edition.workspace = true + +[dependencies] diff --git a/crates/valgrind/fuzz/.gitignore b/crates/wmemcheck/fuzz/.gitignore similarity index 100% rename from crates/valgrind/fuzz/.gitignore rename to crates/wmemcheck/fuzz/.gitignore diff --git a/crates/valgrind/fuzz/Cargo.lock b/crates/wmemcheck/fuzz/Cargo.lock similarity index 98% rename from crates/valgrind/fuzz/Cargo.lock rename to crates/wmemcheck/fuzz/Cargo.lock index 47e030785c26..ba2ae31d0448 100644 --- a/crates/valgrind/fuzz/Cargo.lock +++ b/crates/wmemcheck/fuzz/Cargo.lock @@ -152,16 +152,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] -name = "wasm-valgrind-fuzz" +name = "wmemcheck-fuzz" version = "0.0.0" dependencies = [ "libfuzzer-sys", "rand 0.3.23", - "wasm_valgrind", + "wmemcheck", ] [[package]] -name = "wasm_valgrind" +name = "wmemcheck" version = "0.1.0" [[package]] diff --git a/crates/valgrind/fuzz/Cargo.toml b/crates/wmemcheck/fuzz/Cargo.toml similarity index 90% rename from crates/valgrind/fuzz/Cargo.toml rename to crates/wmemcheck/fuzz/Cargo.toml index 2171405d4738..1a354e69df84 100644 --- a/crates/valgrind/fuzz/Cargo.toml +++ b/crates/wmemcheck/fuzz/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "wasm-valgrind-fuzz" +name = "wmemcheck-fuzz" version = "0.0.0" publish = false edition = "2021" @@ -11,7 +11,7 @@ cargo-fuzz = true libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] } rand="0.3.14" -[dependencies.wasm_valgrind] +[dependencies.wmemcheck] path = ".." # Prevent this from interfering with workspaces diff --git a/crates/valgrind/fuzz/fuzz_targets/buggy_accesses.rs b/crates/wmemcheck/fuzz/fuzz_targets/buggy_accesses.rs similarity index 94% rename from crates/valgrind/fuzz/fuzz_targets/buggy_accesses.rs rename to crates/wmemcheck/fuzz/fuzz_targets/buggy_accesses.rs index 202e67937e8d..6dfc58e07a43 100644 --- a/crates/valgrind/fuzz/fuzz_targets/buggy_accesses.rs +++ b/crates/wmemcheck/fuzz/fuzz_targets/buggy_accesses.rs @@ -2,14 +2,14 @@ use libfuzzer_sys::fuzz_target; use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured}; -use wasm_valgrind::{Valgrind, MemState, AccessError}; +use wmemcheck::{Wmemcheck, MemState, AccessError}; const TEST_MAX_ADDR: usize = 1024 * 640 - 1; const TEST_MAX_STACK_SIZE: usize = 1024; fuzz_target!(|data: &[u8]| { let u = &mut Unstructured::new(data); - let mut valgrind_state = Valgrind::new(TEST_MAX_ADDR + 1, TEST_MAX_STACK_SIZE); + let mut wmemcheck_state = Wmemcheck::new(TEST_MAX_ADDR + 1, TEST_MAX_STACK_SIZE); let cmds = match BuggyCommandSequence::arbitrary(u) { Ok(val) => val, Err(_) => return, @@ -20,16 +20,16 @@ fuzz_target!(|data: &[u8]| { let cmd: &Command = cmd; match cmd { &Command::Malloc { addr, len } => { - assert_eq!(valgrind_state.malloc(addr, len), *result); + assert_eq!(wmemcheck_state.malloc(addr, len), *result); } &Command::Free { addr } => { - assert_eq!(valgrind_state.free(addr), *result); + assert_eq!(wmemcheck_state.free(addr), *result); } &Command::Read { addr, len } => { - assert_eq!(valgrind_state.read(addr, len), *result); + assert_eq!(wmemcheck_state.read(addr, len), *result); } &Command::Write { addr, len } => { - assert_eq!(valgrind_state.write(addr, len), *result); + assert_eq!(wmemcheck_state.write(addr, len), *result); } } } @@ -40,7 +40,7 @@ pub struct Allocation { addr: usize, len: usize, memstate: Vec, -} //TODO: model the stack as an allocation +} impl Allocation { fn new(addr: usize, len: usize) -> Allocation { diff --git a/crates/valgrind/fuzz/fuzz_targets/valid_accesses.rs b/crates/wmemcheck/fuzz/fuzz_targets/valid_accesses.rs similarity index 94% rename from crates/valgrind/fuzz/fuzz_targets/valid_accesses.rs rename to crates/wmemcheck/fuzz/fuzz_targets/valid_accesses.rs index 8b3d6e0c1a99..241ec3b803be 100644 --- a/crates/valgrind/fuzz/fuzz_targets/valid_accesses.rs +++ b/crates/wmemcheck/fuzz/fuzz_targets/valid_accesses.rs @@ -2,7 +2,7 @@ use libfuzzer_sys::fuzz_target; use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured, Error}; -use wasm_valgrind::{Valgrind, MemState}; +use wmemcheck::{Wmemcheck, MemState}; use std::cmp::*; const TEST_MAX_ADDR: usize = 1024 * 640 - 1; @@ -10,7 +10,7 @@ const TEST_MAX_STACK_SIZE: usize = 1024; fuzz_target!(|data: &[u8]| { let u = &mut Unstructured::new(data); - let mut valgrind_state = Valgrind::new(TEST_MAX_ADDR + 1, TEST_MAX_STACK_SIZE); + let mut wmemcheck_state = Wmemcheck::new(TEST_MAX_ADDR + 1, TEST_MAX_STACK_SIZE); let cmds = match CommandSequence::arbitrary(u) { Ok(val) => val, Err(_) => return, @@ -20,16 +20,16 @@ fuzz_target!(|data: &[u8]| { let cmd: &Command = cmd; match cmd { &Command::Malloc { addr, len } => { - assert!(valgrind_state.malloc(addr, len).is_ok()); + assert!(wmemcheck_state.malloc(addr, len).is_ok()); } &Command::Free { addr } => { - assert!(valgrind_state.free(addr).is_ok()); + assert!(wmemcheck_state.free(addr).is_ok()); } &Command::Read { addr, len } => { - assert!(valgrind_state.read(addr, len).is_ok()); + assert!(wmemcheck_state.read(addr, len).is_ok()); } &Command::Write { addr, len } => { - assert!(valgrind_state.write(addr, len).is_ok()); + assert!(wmemcheck_state.write(addr, len).is_ok()); } } } @@ -169,7 +169,7 @@ fn pick_read_range(state: &CommandSequenceState, u: &mut Unstructured<'_>) -> Re if state.allocations.is_empty() { return Err(Error::NotEnoughData); } - let mut alloc_index = u.choose_index(state.allocations.len())?; // may error when state.allocations.len() == 1 + let mut alloc_index = u.choose_index(state.allocations.len())?; let mut attempts = 0; while !state.allocations[alloc_index].memstate.contains(&MemState::ValidToReadWrite) { alloc_index = u.choose_index(state.allocations.len())?; diff --git a/crates/valgrind/src/lib.rs b/crates/wmemcheck/src/lib.rs similarity index 66% rename from crates/valgrind/src/lib.rs rename to crates/wmemcheck/src/lib.rs index 2e8875bc25b4..01e448b991aa 100644 --- a/crates/valgrind/src/lib.rs +++ b/crates/wmemcheck/src/lib.rs @@ -1,7 +1,7 @@ use std::cmp::*; use std::collections::HashMap; -pub struct Valgrind { +pub struct Wmemcheck { metadata: Vec, mallocs: HashMap, pub stack_pointer: usize, @@ -25,11 +25,11 @@ pub enum MemState { ValidToReadWrite, } -impl Valgrind { - pub fn new(mem_size: usize) -> Valgrind { +impl Wmemcheck { + pub fn new(mem_size: usize) -> Wmemcheck { let metadata = vec![MemState::Unallocated; mem_size]; let mallocs = HashMap::new(); - Valgrind { + Wmemcheck { metadata, mallocs, stack_pointer: 0, @@ -123,6 +123,7 @@ impl Valgrind { Ok(()) } + /// pub fn free(&mut self, addr: usize) -> Result<(), AccessError> { if !self.mallocs.contains_key(&addr) { return Err(AccessError::InvalidFree { addr: addr }); @@ -191,43 +192,43 @@ impl Valgrind { } #[test] -fn basic_valgrind() { - let mut valgrind_state = Valgrind::new(640 * 1024, 0); - - assert!(valgrind_state.malloc(0x1000, 32).is_ok()); - assert!(valgrind_state.write(0x1000, 4).is_ok()); - assert!(valgrind_state.read(0x1000, 4).is_ok()); - assert_eq!(valgrind_state.mallocs, HashMap::from([(0x1000, 32)])); - assert!(valgrind_state.free(0x1000).is_ok()); - assert!(valgrind_state.mallocs.is_empty()); +fn basic_wmemcheck() { + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); + + assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.write(0x1000, 4).is_ok()); + assert!(wmemcheck_state.read(0x1000, 4).is_ok()); + assert_eq!(wmemcheck_state.mallocs, HashMap::from([(0x1000, 32)])); + assert!(wmemcheck_state.free(0x1000).is_ok()); + assert!(wmemcheck_state.mallocs.is_empty()); } #[test] fn read_before_initializing() { - let mut valgrind_state = Valgrind::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); - assert!(valgrind_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); assert_eq!( - valgrind_state.read(0x1000, 4), + wmemcheck_state.read(0x1000, 4), Err(AccessError::InvalidRead { addr: 0x1000, len: 4 }) ); - assert!(valgrind_state.write(0x1000, 4).is_ok()); - assert!(valgrind_state.free(0x1000).is_ok()); + assert!(wmemcheck_state.write(0x1000, 4).is_ok()); + assert!(wmemcheck_state.free(0x1000).is_ok()); } #[test] fn use_after_free() { - let mut valgrind_state = Valgrind::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); - assert!(valgrind_state.malloc(0x1000, 32).is_ok()); - assert!(valgrind_state.write(0x1000, 4).is_ok()); - assert!(valgrind_state.write(0x1000, 4).is_ok()); - assert!(valgrind_state.free(0x1000).is_ok()); + assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.write(0x1000, 4).is_ok()); + assert!(wmemcheck_state.write(0x1000, 4).is_ok()); + assert!(wmemcheck_state.free(0x1000).is_ok()); assert_eq!( - valgrind_state.write(0x1000, 4), + wmemcheck_state.write(0x1000, 4), Err(AccessError::InvalidWrite { addr: 0x1000, len: 4 @@ -237,45 +238,45 @@ fn use_after_free() { #[test] fn double_free() { - let mut valgrind_state = Valgrind::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); - assert!(valgrind_state.malloc(0x1000, 32).is_ok()); - assert!(valgrind_state.write(0x1000, 4).is_ok()); - assert!(valgrind_state.free(0x1000).is_ok()); + assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.write(0x1000, 4).is_ok()); + assert!(wmemcheck_state.free(0x1000).is_ok()); assert_eq!( - valgrind_state.free(0x1000), + wmemcheck_state.free(0x1000), Err(AccessError::InvalidFree { addr: 0x1000 }) ); } #[test] fn out_of_bounds_malloc() { - let mut valgrind_state = Valgrind::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); assert_eq!( - valgrind_state.malloc(640 * 1024, 1), + wmemcheck_state.malloc(640 * 1024, 1), Err(AccessError::OutOfBounds { addr: 640 * 1024, len: 1 }) ); assert_eq!( - valgrind_state.malloc(640 * 1024 - 10, 15), + wmemcheck_state.malloc(640 * 1024 - 10, 15), Err(AccessError::OutOfBounds { addr: 640 * 1024 - 10, len: 15 }) ); - assert!(valgrind_state.mallocs.is_empty()); + assert!(wmemcheck_state.mallocs.is_empty()); } #[test] fn out_of_bounds_read() { - let mut valgrind_state = Valgrind::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); - assert!(valgrind_state.malloc(640 * 1024 - 24, 24).is_ok()); + assert!(wmemcheck_state.malloc(640 * 1024 - 24, 24).is_ok()); assert_eq!( - valgrind_state.read(640 * 1024 - 24, 25), + wmemcheck_state.read(640 * 1024 - 24, 25), Err(AccessError::OutOfBounds { addr: 640 * 1024 - 24, len: 25 @@ -285,74 +286,74 @@ fn out_of_bounds_read() { #[test] fn double_malloc() { - let mut valgrind_state = Valgrind::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); - assert!(valgrind_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); assert_eq!( - valgrind_state.malloc(0x1000, 32), + wmemcheck_state.malloc(0x1000, 32), Err(AccessError::DoubleMalloc { addr: 0x1000, len: 32 }) ); assert_eq!( - valgrind_state.malloc(0x1002, 32), + wmemcheck_state.malloc(0x1002, 32), Err(AccessError::DoubleMalloc { addr: 0x1002, len: 32 }) ); - assert!(valgrind_state.free(0x1000).is_ok()); + assert!(wmemcheck_state.free(0x1000).is_ok()); } #[test] fn error_type() { - let mut valgrind_state = Valgrind::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); - assert!(valgrind_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); assert_eq!( - valgrind_state.malloc(0x1000, 32), + wmemcheck_state.malloc(0x1000, 32), Err(AccessError::DoubleMalloc { addr: 0x1000, len: 32 }) ); assert_eq!( - valgrind_state.malloc(640 * 1024, 32), + wmemcheck_state.malloc(640 * 1024, 32), Err(AccessError::OutOfBounds { addr: 640 * 1024, len: 32 }) ); - assert!(valgrind_state.free(0x1000).is_ok()); + assert!(wmemcheck_state.free(0x1000).is_ok()); } #[test] fn update_sp_no_error() { - let mut valgrind_state = Valgrind::new(640 * 1024, 1024); - - assert_eq!(valgrind_state.max_stack_size, 1024); - assert!(valgrind_state.update_stack_pointer(768).is_ok()); - assert_eq!(valgrind_state.stack_pointer, 768); - assert!(valgrind_state.malloc(1024 * 2, 32).is_ok()); - assert!(valgrind_state.free(1024 * 2).is_ok()); - assert!(valgrind_state.update_stack_pointer(896).is_ok()); - assert_eq!(valgrind_state.stack_pointer, 896); - assert!(valgrind_state.update_stack_pointer(1024).is_ok()); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); + + assert_eq!(wmemcheck_state.max_stack_size, 1024); + assert!(wmemcheck_state.update_stack_pointer(768).is_ok()); + assert_eq!(wmemcheck_state.stack_pointer, 768); + assert!(wmemcheck_state.malloc(1024 * 2, 32).is_ok()); + assert!(wmemcheck_state.free(1024 * 2).is_ok()); + assert!(wmemcheck_state.update_stack_pointer(896).is_ok()); + assert_eq!(wmemcheck_state.stack_pointer, 896); + assert!(wmemcheck_state.update_stack_pointer(1024).is_ok()); } #[test] fn bad_stack_malloc() { - let mut valgrind_state = Valgrind::new(640 * 1024, 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); - assert!(valgrind_state.update_stack_pointer(0).is_ok()); - assert_eq!(valgrind_state.stack_pointer, 0); + assert!(wmemcheck_state.update_stack_pointer(0).is_ok()); + assert_eq!(wmemcheck_state.stack_pointer, 0); assert_eq!( - valgrind_state.malloc(512, 32), + wmemcheck_state.malloc(512, 32), Err(AccessError::OutOfBounds { addr: 512, len: 32 }) ); assert_eq!( - valgrind_state.malloc(1022, 32), + wmemcheck_state.malloc(1022, 32), Err(AccessError::OutOfBounds { addr: 1022, len: 32 @@ -362,56 +363,56 @@ fn bad_stack_malloc() { #[test] fn bad_stack_read_write() { - let mut valgrind_state = Valgrind::new(640 * 1024, 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); - assert!(valgrind_state.update_stack_pointer(512).is_ok()); - assert_eq!(valgrind_state.stack_pointer, 512); + assert!(wmemcheck_state.update_stack_pointer(512).is_ok()); + assert_eq!(wmemcheck_state.stack_pointer, 512); assert_eq!( - valgrind_state.read(256, 16), + wmemcheck_state.read(256, 16), Err(AccessError::InvalidRead { addr: 256, len: 16 }) ); assert_eq!( - valgrind_state.write(500, 32), + wmemcheck_state.write(500, 32), Err(AccessError::InvalidWrite { addr: 500, len: 32 }) ); } #[test] fn stack_full_empty() { - let mut valgrind_state = Valgrind::new(640 * 1024, 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); - assert!(valgrind_state.update_stack_pointer(0).is_ok()); - assert_eq!(valgrind_state.stack_pointer, 0); - assert!(valgrind_state.update_stack_pointer(1024).is_ok()); - assert_eq!(valgrind_state.stack_pointer, 1024) + assert!(wmemcheck_state.update_stack_pointer(0).is_ok()); + assert_eq!(wmemcheck_state.stack_pointer, 0); + assert!(wmemcheck_state.update_stack_pointer(1024).is_ok()); + assert_eq!(wmemcheck_state.stack_pointer, 1024) } #[test] fn stack_underflow() { - let mut valgrind_state = Valgrind::new(640 * 1024, 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); - assert!(valgrind_state.update_stack_pointer(800).is_ok()); + assert!(wmemcheck_state.update_stack_pointer(800).is_ok()); assert_eq!( - valgrind_state.update_stack_pointer(1025), + wmemcheck_state.update_stack_pointer(1025), Err(AccessError::OutOfBounds { addr: 800, len: 225 }) ); assert_eq!( - valgrind_state.update_stack_pointer(2000), + wmemcheck_state.update_stack_pointer(2000), Err(AccessError::OutOfBounds { addr: 800, len: 1200 }) ); - assert_eq!(valgrind_state.stack_pointer, 800); + assert_eq!(wmemcheck_state.stack_pointer, 800); } #[test] fn from_test_program() { - let mut valgrind_state = Valgrind::new(1024 * 1024 * 128, 70864); + let mut wmemcheck_state = Wmemcheck::new(1024 * 1024 * 128, 70864); - assert!(valgrind_state.write(70832, 1).is_ok()); - assert!(valgrind_state.read(1138, 1).is_ok()); + assert!(wmemcheck_state.write(70832, 1).is_ok()); + assert!(wmemcheck_state.read(1138, 1).is_ok()); } diff --git a/docs/wmemcheck.md b/docs/wmemcheck.md new file mode 100644 index 000000000000..40ba26e89425 --- /dev/null +++ b/docs/wmemcheck.md @@ -0,0 +1,8 @@ + +Wmemcheck provides debug output for invalid mallocs, reads, and writes. + +How to use: +1. When building Wasmtime, add the CLI flag "--features wmemcheck" to compile with wmemcheck configured. + > cargo build --features wmemcheck +2. When running your wasm module, add the CLI flag "--wmemcheck". + > wasmtime run --wmemcheck test.wasm diff --git a/src/commands/run.rs b/src/commands/run.rs index f589c311134a..4425ea1133ed 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -224,9 +224,12 @@ pub struct RunCommand { #[clap(long)] trap_on_grow_failure: bool, - /// Enable valgrind. + /// Enables memory error checking by including wmemcheck_state in + /// a runtime Instance. + /// + /// See wmemcheck.md for documentation on how to use. #[clap(long)] - valgrind: bool, + wmemcheck: bool, /// The WebAssembly module to run and arguments to pass to it. /// @@ -264,7 +267,7 @@ impl RunCommand { None => {} } - config.valgrind(self.valgrind); + config.wmemcheck(self.wmemcheck); let engine = Engine::new(&config)?; From f4947a5eb8cdf859a628e164870fffa7537f6fef Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Thu, 10 Aug 2023 11:30:47 -0700 Subject: [PATCH 26/34] ran cargo fmt --- cranelift/wasm/src/code_translator.rs | 17 ++++------- cranelift/wasm/src/environ/spec.rs | 36 ++++++++++++++++++++---- crates/cranelift/src/compiler.rs | 3 +- crates/cranelift/src/func_environ.rs | 32 +++++++++++++-------- crates/runtime/src/instance.rs | 23 +++++++++------ crates/runtime/src/instance/allocator.rs | 10 ++++++- crates/runtime/src/libcalls.rs | 6 ++-- crates/wasmtime/src/config.rs | 2 +- crates/wmemcheck/src/lib.rs | 2 +- src/commands/run.rs | 2 +- 10 files changed, 89 insertions(+), 44 deletions(-) diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 6fe39be939b7..0d5e78889744 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -2873,16 +2873,11 @@ fn translate_load( environ: &mut FE, ) -> WasmResult> { let mem_op_size = mem_op_size(opcode, result_ty); - let (flags, wasm_index, base) = match prepare_addr( - memarg, - mem_op_size, - builder, - state, - environ, - )? { - Reachability::Unreachable => return Ok(Reachability::Unreachable), - Reachability::Reachable((f, i, b)) => (f, i, b), - }; + let (flags, wasm_index, base) = + match prepare_addr(memarg, mem_op_size, builder, state, environ)? { + Reachability::Unreachable => return Ok(Reachability::Unreachable), + Reachability::Reachable((f, i, b)) => (f, i, b), + }; environ.before_load(builder, mem_op_size, wasm_index, memarg.offset); @@ -2911,7 +2906,7 @@ fn translate_store( ); environ.before_store(builder, mem_op_size, wasm_index, memarg.offset); - + builder .ins() .Store(opcode, val_ty, flags, Offset32::new(0), val, base); diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index ff5eac0a9974..f0e449451b16 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -653,21 +653,47 @@ pub trait FuncEnvironment: TargetEnvironment { /// and free if wasmtime is compiled and run with wmemcheck. fn handle_before_return(&mut self, _retvals: &[ir::Value], _builder: &mut FunctionBuilder) {} - /// Inserts call to check_load before a load instruction if wasmtime is + /// Inserts call to check_load before a load instruction if wasmtime is /// compiled and run with wmemcheck. - fn before_load(&mut self, _builder: &mut FunctionBuilder, _val_size: u8, _addr: ir::Value, _offset: u64) {} + fn before_load( + &mut self, + _builder: &mut FunctionBuilder, + _val_size: u8, + _addr: ir::Value, + _offset: u64, + ) { + } /// Inserts call to check_store before a store instruction if wasmtime is /// compiled and run with wmemcheck. - fn before_store(&mut self, _builder: &mut FunctionBuilder, _val_size: u8, _addr: ir::Value, _offset: u64) {} + fn before_store( + &mut self, + _builder: &mut FunctionBuilder, + _val_size: u8, + _addr: ir::Value, + _offset: u64, + ) { + } /// Inserts call to update_stack_pointer when stack pointer is updated if /// wasmtime is compiled and run with wmemcheck. - fn update_global(&mut self, _builder: &mut FunctionBuilder, _global_index: u32, _value: ir::Value) {} + fn update_global( + &mut self, + _builder: &mut FunctionBuilder, + _global_index: u32, + _value: ir::Value, + ) { + } /// Inserts calls to update_mem_size after memory.grow if wasmtime is /// compiled and run with wmemcheck. - fn before_memory_grow(&mut self, _builder: &mut FunctionBuilder, _num_bytes: ir::Value, _mem_index: MemoryIndex) {} + fn before_memory_grow( + &mut self, + _builder: &mut FunctionBuilder, + _num_bytes: ir::Value, + _mem_index: MemoryIndex, + ) { + } } /// An object satisfying the `ModuleEnvironment` trait can be passed as argument to the diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs index 410a8d0edaf3..3f4497efe98b 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs @@ -150,7 +150,8 @@ impl wasmtime_environ::Compiler for Compiler { context.func.collect_debug_info(); } - let mut func_env = FuncEnvironment::new(isa, translation, types, &self.tunables, self.wmemcheck); + let mut func_env = + FuncEnvironment::new(isa, translation, types, &self.tunables, self.wmemcheck); // The `stack_limit` global value below is the implementation of stack // overflow checks in Wasmtime. diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 16d57f63001d..fbb2100dde9e 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -1,9 +1,12 @@ +use cfg_if::cfg_if; use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::ir; use cranelift_codegen::ir::condcodes::*; use cranelift_codegen::ir::immediates::{Imm64, Offset32, Uimm64}; use cranelift_codegen::ir::types::*; -use cranelift_codegen::ir::{AbiParam, ArgumentPurpose, Function, InstBuilder, Signature, Value, UserFuncName}; +use cranelift_codegen::ir::{ + AbiParam, ArgumentPurpose, Function, InstBuilder, Signature, UserFuncName, Value, +}; use cranelift_codegen::isa::{self, CallConv, TargetFrontendConfig, TargetIsa}; use cranelift_entity::{EntityRef, PrimaryMap}; use cranelift_frontend::FunctionBuilder; @@ -21,7 +24,6 @@ use wasmtime_environ::{ TableStyle, Tunables, TypeConvert, VMOffsets, WASM_PAGE_SIZE, }; use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK}; -use cfg_if::cfg_if; macro_rules! declare_function_signatures { ( @@ -179,7 +181,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { // Avoid unused warning in default build. #[cfg(not(feature = "wmemcheck"))] let _ = wmemcheck; - + Self { isa, module: &translation.module, @@ -626,7 +628,10 @@ impl<'module_environment> FuncEnvironment<'module_environment> { &mut builder.cursor(), BuiltinFunctionIndex::check_malloc(), ); - let func_args = builder.func.dfg.block_params(builder.func.layout.entry_block().unwrap()); + let func_args = builder + .func + .dfg + .block_params(builder.func.layout.entry_block().unwrap()); let len = if func_args.len() < 3 { return; } else { @@ -651,7 +656,10 @@ impl<'module_environment> FuncEnvironment<'module_environment> { &mut builder.cursor(), BuiltinFunctionIndex::check_free(), ); - let func_args = builder.func.dfg.block_params(builder.func.layout.entry_block().unwrap()); + let func_args = builder + .func + .dfg + .block_params(builder.func.layout.entry_block().unwrap()); let ptr = if func_args.len() < 3 { return; } else { @@ -663,7 +671,6 @@ impl<'module_environment> FuncEnvironment<'module_environment> { .ins() .call_indirect(check_free_sig, check_free, &[vmctx, ptr]); } - fn epoch_ptr(&mut self, builder: &mut FunctionBuilder<'_>) -> ir::Value { let vmctx = self.vmctx(builder.func); @@ -898,14 +905,17 @@ impl<'module_environment> FuncEnvironment<'module_environment> { fn current_func_name(&self, builder: &mut FunctionBuilder) -> Option<&str> { let func_index = match &builder.func.name { - UserFuncName::User(user) => { - FuncIndex::from_u32(user.index) - } + UserFuncName::User(user) => FuncIndex::from_u32(user.index), _ => { panic!("function name not a UserFuncName::User as expected") } }; - self.translation.debuginfo.name_section.func_names.get(&func_index).map(|s| *s) + self.translation + .debuginfo + .name_section + .func_names + .get(&func_index) + .map(|s| *s) } } @@ -2494,7 +2504,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } } } - + fn before_load(&mut self, builder: &mut FunctionBuilder, val_size: u8, addr: ir::Value, offset: u64) { if self.wmemcheck { let check_load_sig = self.builtin_function_signatures.check_load(builder.func); diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index ed7da318729e..f36fff3c179d 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -15,8 +15,6 @@ use crate::{ ExportFunction, ExportGlobal, ExportMemory, ExportTable, Imports, ModuleRuntimeInfo, SendSyncPtr, Store, VMFunctionBody, VMSharedSignatureIndex, WasmFault, }; -#[cfg(feature = "wmemcheck")] -use wmemcheck::Wmemcheck; use anyhow::Error; use anyhow::Result; use sptr::Strict; @@ -31,10 +29,11 @@ use std::{mem, ptr}; use wasmtime_environ::{ packed_option::ReservedValue, DataIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, ElemIndex, EntityIndex, EntityRef, EntitySet, FuncIndex, GlobalIndex, - GlobalInit, HostPtr, MemoryIndex, Module, PrimaryMap, SignatureIndex, TableIndex, + GlobalInit, HostPtr, MemoryIndex, MemoryPlan, Module, PrimaryMap, SignatureIndex, TableIndex, TableInitialValue, Trap, VMOffsets, WasmHeapType, WasmRefType, WasmType, VMCONTEXT_MAGIC, - MemoryPlan, }; +#[cfg(feature = "wmemcheck")] +use wmemcheck::Wmemcheck; mod allocator; @@ -145,9 +144,8 @@ pub struct Instance { #[cfg(feature = "wmemcheck")] pub(crate) wmemcheck_state: Option, - // TODO: add support for multiple memories, wmemcheck_state corresponds to + // TODO: add support for multiple memories, wmemcheck_state corresponds to // memory 0. - /// Additional context used by compiled wasm code. This field is last, and /// represents a dynamically-sized array that extends beyond the nominal /// end of the struct (similar to a flexible array member). @@ -181,7 +179,7 @@ impl Instance { #[cfg(not(feature = "wmemcheck"))] let _ = memory_plans; - + ptr::write( ptr, Instance { @@ -201,7 +199,13 @@ impl Instance { #[cfg(feature = "wmemcheck")] wmemcheck_state: { if req.wmemcheck { - let size = memory_plans.iter().next().map(|plan| plan.1.memory.minimum).unwrap_or(0) * 64 * 1024; + let size = memory_plans + .iter() + .next() + .map(|plan| plan.1.memory.minimum) + .unwrap_or(0) + * 64 + * 1024; Some(Wmemcheck::new(size as usize)) } else { None @@ -1150,7 +1154,8 @@ impl Instance { GlobalInit::I32Const(x) => { let index = module.global_index(index); if index.index() == 0 { - #[cfg(feature = "wmemcheck")] { + #[cfg(feature = "wmemcheck")] + { if let Some(wmemcheck) = &mut self.wmemcheck_state { wmemcheck.set_stack_size(x as usize); } diff --git a/crates/runtime/src/instance/allocator.rs b/crates/runtime/src/instance/allocator.rs index bb21054a6013..4ed72d6964b1 100644 --- a/crates/runtime/src/instance/allocator.rs +++ b/crates/runtime/src/instance/allocator.rs @@ -125,7 +125,15 @@ pub unsafe trait InstanceAllocator { return Err(e); } - unsafe { Ok(Instance::new(req, index, memories, tables, &module.memory_plans)) } + unsafe { + Ok(Instance::new( + req, + index, + memories, + tables, + &module.memory_plans, + )) + } } /// Deallocates the provided instance. diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 2f406d76e4af..a3d13d294423 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -59,17 +59,17 @@ use crate::table::{Table, TableElementType}; use crate::vmcontext::VMFuncRef; use crate::{Instance, TrapReason}; #[cfg(feature = "wmemcheck")] -use wmemcheck::AccessError::{DoubleMalloc, InvalidRead, InvalidWrite, InvalidFree, OutOfBounds}; +use anyhow::bail; use anyhow::Result; +use cfg_if::cfg_if; use std::mem; use std::ptr::{self, NonNull}; use std::time::{Duration, Instant}; use wasmtime_environ::{ DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Trap, }; -use cfg_if::cfg_if; #[cfg(feature = "wmemcheck")] -use anyhow::bail; +use wmemcheck::AccessError::{DoubleMalloc, InvalidFree, InvalidRead, InvalidWrite, OutOfBounds}; /// Actually public trampolines which are used by the runtime as the entrypoint /// for libcalls. diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 4993a713015e..ec18597612d3 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1483,7 +1483,7 @@ impl Config { } /// Enables memory error checking for wasm programs. - /// + /// /// This option is disabled by default. pub fn wmemcheck(&mut self, enable: bool) -> &mut Self { self.wmemcheck = enable; diff --git a/crates/wmemcheck/src/lib.rs b/crates/wmemcheck/src/lib.rs index 01e448b991aa..11ec744b4b2b 100644 --- a/crates/wmemcheck/src/lib.rs +++ b/crates/wmemcheck/src/lib.rs @@ -123,7 +123,7 @@ impl Wmemcheck { Ok(()) } - /// + /// pub fn free(&mut self, addr: usize) -> Result<(), AccessError> { if !self.mallocs.contains_key(&addr) { return Err(AccessError::InvalidFree { addr: addr }); diff --git a/src/commands/run.rs b/src/commands/run.rs index 4425ea1133ed..8253111b861f 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -226,7 +226,7 @@ pub struct RunCommand { /// Enables memory error checking by including wmemcheck_state in /// a runtime Instance. - /// + /// /// See wmemcheck.md for documentation on how to use. #[clap(long)] wmemcheck: bool, From 6c896f264e172d77ac4ba30eba1cb121f4e70f9f Mon Sep 17 00:00:00 2001 From: Sophia Sunkin Date: Thu, 10 Aug 2023 12:00:20 -0700 Subject: [PATCH 27/34] addressing more feedback --- Cargo.lock | 10 +-- Cargo.toml | 2 +- cranelift/wasm/src/environ/spec.rs | 15 ++--- crates/runtime/Cargo.toml | 2 +- crates/runtime/src/instance.rs | 2 +- crates/runtime/src/libcalls.rs | 4 +- crates/wmemcheck/Cargo.toml | 2 +- crates/wmemcheck/src/lib.rs | 98 +++++++++++++----------------- src/commands/run.rs | 3 +- 9 files changed, 60 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4dfe5e6dd49d..55e9f944c3cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3697,8 +3697,8 @@ dependencies = [ "wasmtime-fiber", "wasmtime-jit-debug", "wasmtime-versioned-export-macros", + "wasmtime-wmemcheck", "windows-sys", - "wmemcheck", ] [[package]] @@ -3826,6 +3826,10 @@ dependencies = [ "wit-parser", ] +[[package]] +name = "wasmtime-wmemcheck" +version = "13.0.0" + [[package]] name = "wast" version = "35.0.2" @@ -4227,10 +4231,6 @@ dependencies = [ "wast 35.0.2", ] -[[package]] -name = "wmemcheck" -version = "13.0.0" - [[package]] name = "zstd" version = "0.11.1+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index 6ba0134f1cea..061c2e0551d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,7 +123,7 @@ edition = "2021" rust-version = "1.66.0" [workspace.dependencies] -wmemcheck = { path = "crates/wmemcheck", version = "13.0.0" } +wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "13.0.0" } wasmtime = { path = "crates/wasmtime", version = "13.0.0", default-features = false } wasmtime-cache = { path = "crates/cache", version = "=13.0.0" } wasmtime-cli-flags = { path = "crates/cli-flags", version = "=13.0.0" } diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index f0e449451b16..76191d6ca1d5 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -649,12 +649,10 @@ pub trait FuncEnvironment: TargetEnvironment { false } - /// Inserts call to check_malloc and check_free before the return of malloc - /// and free if wasmtime is compiled and run with wmemcheck. + /// Inserts code before a function return. fn handle_before_return(&mut self, _retvals: &[ir::Value], _builder: &mut FunctionBuilder) {} - /// Inserts call to check_load before a load instruction if wasmtime is - /// compiled and run with wmemcheck. + /// Inserts code before a load. fn before_load( &mut self, _builder: &mut FunctionBuilder, @@ -664,8 +662,7 @@ pub trait FuncEnvironment: TargetEnvironment { ) { } - /// Inserts call to check_store before a store instruction if wasmtime is - /// compiled and run with wmemcheck. + /// Inserts code before a store. fn before_store( &mut self, _builder: &mut FunctionBuilder, @@ -675,8 +672,7 @@ pub trait FuncEnvironment: TargetEnvironment { ) { } - /// Inserts call to update_stack_pointer when stack pointer is updated if - /// wasmtime is compiled and run with wmemcheck. + /// Inserts code before updating a global. fn update_global( &mut self, _builder: &mut FunctionBuilder, @@ -685,8 +681,7 @@ pub trait FuncEnvironment: TargetEnvironment { ) { } - /// Inserts calls to update_mem_size after memory.grow if wasmtime is - /// compiled and run with wmemcheck. + /// Inserts code before memory.grow. fn before_memory_grow( &mut self, _builder: &mut FunctionBuilder, diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index f8bc97fb6cc9..ed921ea1dffc 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/bytecodealliance/wasmtime" edition.workspace = true [dependencies] -wmemcheck = { workspace = true } +wasmtime-wmemcheck = { workspace = true } wasmtime-asm-macros = { workspace = true } wasmtime-environ = { workspace = true } wasmtime-fiber = { workspace = true, optional = true } diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index f36fff3c179d..7a4c48ffa69e 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -33,7 +33,7 @@ use wasmtime_environ::{ TableInitialValue, Trap, VMOffsets, WasmHeapType, WasmRefType, WasmType, VMCONTEXT_MAGIC, }; #[cfg(feature = "wmemcheck")] -use wmemcheck::Wmemcheck; +use wasmtime_wmemcheck::Wmemcheck; mod allocator; diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index a3d13d294423..f4c35e1bc59f 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -69,7 +69,9 @@ use wasmtime_environ::{ DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Trap, }; #[cfg(feature = "wmemcheck")] -use wmemcheck::AccessError::{DoubleMalloc, InvalidFree, InvalidRead, InvalidWrite, OutOfBounds}; +use wasmtime_wmemcheck::AccessError::{ + DoubleMalloc, InvalidFree, InvalidRead, InvalidWrite, OutOfBounds, +}; /// Actually public trampolines which are used by the runtime as the entrypoint /// for libcalls. diff --git a/crates/wmemcheck/Cargo.toml b/crates/wmemcheck/Cargo.toml index cfbafd3c6e70..af62cc4541cb 100644 --- a/crates/wmemcheck/Cargo.toml +++ b/crates/wmemcheck/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "wmemcheck" +name = "wasmtime-wmemcheck" version.workspace = true authors.workspace = true description = "Memcheck implementation for Wasmtime" diff --git a/crates/wmemcheck/src/lib.rs b/crates/wmemcheck/src/lib.rs index 11ec744b4b2b..742f090b68af 100644 --- a/crates/wmemcheck/src/lib.rs +++ b/crates/wmemcheck/src/lib.rs @@ -1,6 +1,7 @@ use std::cmp::*; use std::collections::HashMap; +/// Memory checker for wasm guest. pub struct Wmemcheck { metadata: Vec, mallocs: HashMap, @@ -9,23 +10,34 @@ pub struct Wmemcheck { pub flag: bool, } +/// Error types for memory checker. #[derive(Debug, PartialEq)] pub enum AccessError { + /// Malloc over already malloc'd memory. DoubleMalloc { addr: usize, len: usize }, + /// Read from uninitialized or undefined memory. InvalidRead { addr: usize, len: usize }, + /// Write to uninitialized memory. InvalidWrite { addr: usize, len: usize }, + /// Free of non-malloc'd pointer. InvalidFree { addr: usize }, + /// Access out of bounds of heap or stack. OutOfBounds { addr: usize, len: usize }, } +/// Memory state for memory checker. #[derive(Debug, Clone, PartialEq)] pub enum MemState { + /// Unallocated memory. Unallocated, + /// Initialized but undefined memory. ValidToWrite, + /// Initialized and defined memory. ValidToReadWrite, } impl Wmemcheck { + /// Initializes memory checker instance. pub fn new(mem_size: usize) -> Wmemcheck { let metadata = vec![MemState::Unallocated; mem_size]; let mallocs = HashMap::new(); @@ -38,6 +50,7 @@ impl Wmemcheck { } } + /// Updates memory checker memory state metadata when malloc is called. pub fn malloc(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { if !self.is_in_bounds_heap(addr, len) { return Err(AccessError::OutOfBounds { @@ -69,6 +82,7 @@ impl Wmemcheck { Ok(()) } + /// Updates memory checker memory state metadata when a load occurs. pub fn read(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { if !self.flag { return Ok(()); @@ -99,6 +113,7 @@ impl Wmemcheck { Ok(()) } + /// Updates memory checker memory state metadata when a store occurs. pub fn write(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { if !self.flag { return Ok(()); @@ -123,7 +138,7 @@ impl Wmemcheck { Ok(()) } - /// + /// Updates memory checker memory state metadata when free is called. pub fn free(&mut self, addr: usize) -> Result<(), AccessError> { if !self.mallocs.contains_key(&addr) { return Err(AccessError::InvalidFree { addr: addr }); @@ -149,6 +164,7 @@ impl Wmemcheck { self.stack_pointer <= addr && addr + len < self.max_stack_size } + /// Updates memory checker metadata when stack pointer is updated. pub fn update_stack_pointer(&mut self, new_sp: usize) -> Result<(), AccessError> { if new_sp > self.max_stack_size { return Err(AccessError::OutOfBounds { @@ -157,7 +173,6 @@ impl Wmemcheck { }); } else if new_sp < self.stack_pointer { for i in new_sp..self.stack_pointer + 1 { - // +1 to account for sp == max_stack_size (?) self.metadata[i] = MemState::ValidToReadWrite; } } else { @@ -169,22 +184,26 @@ impl Wmemcheck { Ok(()) } + /// Turns memory checking on. pub fn memcheck_on(&mut self) { self.flag = true; } + /// Turns memory checking off. pub fn memcheck_off(&mut self) { self.flag = false; } + /// Initializes stack and stack pointer in memory checker metadata. pub fn set_stack_size(&mut self, stack_size: usize) { self.max_stack_size = stack_size + 1; - //temporary solution to initialize the entire stack - //while keeping stack tracing plumbing in place + // TODO: temporary solution to initialize the entire stack + // while keeping stack tracing plumbing in place self.stack_pointer = stack_size; let _ = self.update_stack_pointer(0); } + /// Updates memory checker metadata size when memory.grow is called. pub fn update_mem_size(&mut self, num_bytes: usize) { let to_append = vec![MemState::Unallocated; num_bytes]; self.metadata.extend(to_append); @@ -193,8 +212,9 @@ impl Wmemcheck { #[test] fn basic_wmemcheck() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + wmemcheck_state.set_stack_size(1024); assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); assert!(wmemcheck_state.write(0x1000, 4).is_ok()); assert!(wmemcheck_state.read(0x1000, 4).is_ok()); @@ -205,7 +225,7 @@ fn basic_wmemcheck() { #[test] fn read_before_initializing() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); assert_eq!( @@ -221,7 +241,7 @@ fn read_before_initializing() { #[test] fn use_after_free() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); assert!(wmemcheck_state.write(0x1000, 4).is_ok()); @@ -238,7 +258,7 @@ fn use_after_free() { #[test] fn double_free() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); assert!(wmemcheck_state.write(0x1000, 4).is_ok()); @@ -251,7 +271,7 @@ fn double_free() { #[test] fn out_of_bounds_malloc() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); assert_eq!( wmemcheck_state.malloc(640 * 1024, 1), @@ -272,7 +292,7 @@ fn out_of_bounds_malloc() { #[test] fn out_of_bounds_read() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); assert!(wmemcheck_state.malloc(640 * 1024 - 24, 24).is_ok()); assert_eq!( @@ -286,7 +306,7 @@ fn out_of_bounds_read() { #[test] fn double_malloc() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); assert_eq!( @@ -308,7 +328,7 @@ fn double_malloc() { #[test] fn error_type() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 0); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); assert_eq!( @@ -330,9 +350,9 @@ fn error_type() { #[test] fn update_sp_no_error() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); - assert_eq!(wmemcheck_state.max_stack_size, 1024); + wmemcheck_state.set_stack_size(1024); assert!(wmemcheck_state.update_stack_pointer(768).is_ok()); assert_eq!(wmemcheck_state.stack_pointer, 768); assert!(wmemcheck_state.malloc(1024 * 2, 32).is_ok()); @@ -344,7 +364,9 @@ fn update_sp_no_error() { #[test] fn bad_stack_malloc() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + + wmemcheck_state.set_stack_size(1024); assert!(wmemcheck_state.update_stack_pointer(0).is_ok()); assert_eq!(wmemcheck_state.stack_pointer, 0); @@ -361,25 +383,11 @@ fn bad_stack_malloc() { ); } -#[test] -fn bad_stack_read_write() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); - - assert!(wmemcheck_state.update_stack_pointer(512).is_ok()); - assert_eq!(wmemcheck_state.stack_pointer, 512); - assert_eq!( - wmemcheck_state.read(256, 16), - Err(AccessError::InvalidRead { addr: 256, len: 16 }) - ); - assert_eq!( - wmemcheck_state.write(500, 32), - Err(AccessError::InvalidWrite { addr: 500, len: 32 }) - ); -} - #[test] fn stack_full_empty() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + + wmemcheck_state.set_stack_size(1024); assert!(wmemcheck_state.update_stack_pointer(0).is_ok()); assert_eq!(wmemcheck_state.stack_pointer, 0); @@ -387,32 +395,10 @@ fn stack_full_empty() { assert_eq!(wmemcheck_state.stack_pointer, 1024) } -#[test] -fn stack_underflow() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1024); - - assert!(wmemcheck_state.update_stack_pointer(800).is_ok()); - assert_eq!( - wmemcheck_state.update_stack_pointer(1025), - Err(AccessError::OutOfBounds { - addr: 800, - len: 225 - }) - ); - assert_eq!( - wmemcheck_state.update_stack_pointer(2000), - Err(AccessError::OutOfBounds { - addr: 800, - len: 1200 - }) - ); - assert_eq!(wmemcheck_state.stack_pointer, 800); -} - #[test] fn from_test_program() { - let mut wmemcheck_state = Wmemcheck::new(1024 * 1024 * 128, 70864); - + let mut wmemcheck_state = Wmemcheck::new(1024 * 1024 * 128); + wmemcheck_state.set_stack_size(70864); assert!(wmemcheck_state.write(70832, 1).is_ok()); assert!(wmemcheck_state.read(1138, 1).is_ok()); } diff --git a/src/commands/run.rs b/src/commands/run.rs index 8253111b861f..56666a19a577 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -224,8 +224,7 @@ pub struct RunCommand { #[clap(long)] trap_on_grow_failure: bool, - /// Enables memory error checking by including wmemcheck_state in - /// a runtime Instance. + /// Enables memory error checking. /// /// See wmemcheck.md for documentation on how to use. #[clap(long)] From e1a18553f168808de69b7c74387076ce48862942 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 10 Aug 2023 14:42:28 -0700 Subject: [PATCH 28/34] Remove fuzz crate from wmemcheck. --- crates/wmemcheck/fuzz/.gitignore | 4 - crates/wmemcheck/fuzz/Cargo.lock | 187 --------------- crates/wmemcheck/fuzz/Cargo.toml | 34 --- .../fuzz/fuzz_targets/buggy_accesses.rs | 218 ------------------ .../fuzz/fuzz_targets/valid_accesses.rs | 216 ----------------- 5 files changed, 659 deletions(-) delete mode 100644 crates/wmemcheck/fuzz/.gitignore delete mode 100644 crates/wmemcheck/fuzz/Cargo.lock delete mode 100644 crates/wmemcheck/fuzz/Cargo.toml delete mode 100644 crates/wmemcheck/fuzz/fuzz_targets/buggy_accesses.rs delete mode 100644 crates/wmemcheck/fuzz/fuzz_targets/valid_accesses.rs diff --git a/crates/wmemcheck/fuzz/.gitignore b/crates/wmemcheck/fuzz/.gitignore deleted file mode 100644 index 1a45eee7760d..000000000000 --- a/crates/wmemcheck/fuzz/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -target -corpus -artifacts -coverage diff --git a/crates/wmemcheck/fuzz/Cargo.lock b/crates/wmemcheck/fuzz/Cargo.lock deleted file mode 100644 index ba2ae31d0448..000000000000 --- a/crates/wmemcheck/fuzz/Cargo.lock +++ /dev/null @@ -1,187 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "arbitrary" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" -dependencies = [ - "derive_arbitrary", -] - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" -dependencies = [ - "jobserver", -] - -[[package]] -name = "derive_arbitrary" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "jobserver" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" -dependencies = [ - "libc", -] - -[[package]] -name = "libc" -version = "0.2.146" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" - -[[package]] -name = "libfuzzer-sys" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb09950ae85a0a94b27676cccf37da5ff13f27076aa1adbc6545dd0d0e1bd4e" -dependencies = [ - "arbitrary", - "cc", - "once_cell", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "proc-macro2" -version = "1.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -dependencies = [ - "libc", - "rand 0.4.6", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "syn" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" - -[[package]] -name = "wmemcheck-fuzz" -version = "0.0.0" -dependencies = [ - "libfuzzer-sys", - "rand 0.3.23", - "wmemcheck", -] - -[[package]] -name = "wmemcheck" -version = "0.1.0" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/crates/wmemcheck/fuzz/Cargo.toml b/crates/wmemcheck/fuzz/Cargo.toml deleted file mode 100644 index 1a354e69df84..000000000000 --- a/crates/wmemcheck/fuzz/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "wmemcheck-fuzz" -version = "0.0.0" -publish = false -edition = "2021" - -[package.metadata] -cargo-fuzz = true - -[dependencies] -libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] } -rand="0.3.14" - -[dependencies.wmemcheck] -path = ".." - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[profile.release] -debug = 1 - -[[bin]] -name = "valid_accesses" -path = "fuzz_targets/valid_accesses.rs" -test = false -doc = false - -[[bin]] -name = "buggy_accesses" -path = "fuzz_targets/buggy_accesses.rs" -test = false -doc = false \ No newline at end of file diff --git a/crates/wmemcheck/fuzz/fuzz_targets/buggy_accesses.rs b/crates/wmemcheck/fuzz/fuzz_targets/buggy_accesses.rs deleted file mode 100644 index 6dfc58e07a43..000000000000 --- a/crates/wmemcheck/fuzz/fuzz_targets/buggy_accesses.rs +++ /dev/null @@ -1,218 +0,0 @@ -#![no_main] - -use libfuzzer_sys::fuzz_target; -use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured}; -use wmemcheck::{Wmemcheck, MemState, AccessError}; - -const TEST_MAX_ADDR: usize = 1024 * 640 - 1; -const TEST_MAX_STACK_SIZE: usize = 1024; - -fuzz_target!(|data: &[u8]| { - let u = &mut Unstructured::new(data); - let mut wmemcheck_state = Wmemcheck::new(TEST_MAX_ADDR + 1, TEST_MAX_STACK_SIZE); - let cmds = match BuggyCommandSequence::arbitrary(u) { - Ok(val) => val, - Err(_) => return, - }; - println!("commands: {:?}", cmds); - assert_eq!(cmds.commands.len(), cmds.results.len()); - for (cmd, result) in cmds.commands.iter().zip(cmds.results.iter()) { - let cmd: &Command = cmd; - match cmd { - &Command::Malloc { addr, len } => { - assert_eq!(wmemcheck_state.malloc(addr, len), *result); - } - &Command::Free { addr } => { - assert_eq!(wmemcheck_state.free(addr), *result); - } - &Command::Read { addr, len } => { - assert_eq!(wmemcheck_state.read(addr, len), *result); - } - &Command::Write { addr, len } => { - assert_eq!(wmemcheck_state.write(addr, len), *result); - } - } - } -}); - -#[derive(Debug)] -pub struct Allocation { - addr: usize, - len: usize, - memstate: Vec, -} - -impl Allocation { - fn new(addr: usize, len: usize) -> Allocation { - Allocation { addr: addr, len: len, memstate: vec![MemState::ValidToWrite; len] } - } - fn no_overlaps(&self, other: &Allocation) -> bool { - other.addr + other.len <= self.addr || self.addr + self.len <= other.addr - } - fn is_in_bounds(&self) -> bool { - TEST_MAX_STACK_SIZE <= self.addr && self.addr + self.len - 1 <= TEST_MAX_ADDR - } -} - -#[derive(Debug)] -pub enum Command { - Malloc {addr: usize, len: usize}, - Read {addr: usize, len: usize}, - Write {addr: usize, len: usize}, - Free {addr: usize} -} - -#[derive(Debug)] -struct BuggyCommandSequence { - commands: Vec, - results: Vec> -} - -struct BuggyCommandSequenceState { - allocations: Vec, -} - -impl BuggyCommandSequenceState { - fn new() -> BuggyCommandSequenceState { - let allocations = Vec::new(); - BuggyCommandSequenceState { allocations } - } - fn update(&mut self, cmd: &Command) { - match cmd { - &Command::Malloc { addr, len } => { - let alloc = Allocation::new(addr, len); - let validity = is_malloc_valid(&alloc, &self); - if validity.is_ok() { - self.allocations.push(Allocation::new(addr, len)); - } - } - &Command::Free { addr } => { - let validity = is_free_valid(addr, &self); - if validity.is_ok() { - let index = self.allocations.iter().position(|alloc| alloc.addr == addr).unwrap(); - self.allocations.remove(index); - } - } - &Command::Write { addr, len } => { - let validity = is_write_valid(addr, len, &self); - if validity.is_ok() { - let index = self.allocations.iter().position(|alloc| alloc.addr <= addr && addr + len <= alloc.addr + alloc.len).unwrap(); - let alloc_addr = self.allocations[index].addr; - let write_to = &mut self.allocations[index].memstate; - for i in 0..len { - write_to[addr - alloc_addr + i] = MemState::ValidToReadWrite; - } - } - } - _ => {} - } - } -} - - -impl<'a> Arbitrary<'a> for BuggyCommandSequence { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - let mut commands = vec![]; - let mut results = vec![]; - let mut state = BuggyCommandSequenceState::new(); - for _ in 0..u.int_in_range(1..=20)? { - let cmd = match u.int_in_range(0..=3)? { - 0 => { - let malloc_addr = u.int_in_range(1..=TEST_MAX_ADDR)?; - let malloc_len = u.int_in_range(1..=TEST_MAX_ADDR)?; - let alloc = Allocation::new(malloc_addr, malloc_len); - results.push(is_malloc_valid(&alloc, &state)); - Command::Malloc { addr: malloc_addr, len: malloc_len } - } - 1 => { - let choose_rand_addr = u.ratio(1, 2)?; - let mut unalloc_addr = 0; - if choose_rand_addr { - unalloc_addr = u.choose_index(TEST_MAX_ADDR)?; - } else { - let some_alloc = u.choose_index(state.allocations.len())?; - unalloc_addr = state.allocations[some_alloc].addr; - } - results.push(is_free_valid(unalloc_addr, &state)); - Command::Free { addr: unalloc_addr } - } - 2 => { - let read_addr = u.choose_index(TEST_MAX_ADDR)?; - let read_len = u.int_in_range(1..=TEST_MAX_ADDR)?; - results.push(is_read_valid(read_addr, read_len, &state)); - Command::Read { addr: read_addr, len: read_len } - } - 3 => { - let write_addr = u.choose_index(TEST_MAX_ADDR)?; - let write_len = u.int_in_range(1..=TEST_MAX_ADDR)?; - results.push(is_write_valid(write_addr, write_len, &state)); - Command::Write { addr: write_addr, len: write_len } - } - _ => { - unreachable!() - } - }; - // println!("{:?} allocs: {:?} resutls: {:?}", cmd, state.allocations, results); - state.update(&cmd); - commands.push(cmd); - } - Ok(BuggyCommandSequence { commands, results }) - } -} - -fn no_allocs_in_range(state: &BuggyCommandSequenceState, other: &Allocation ) -> bool { - state.allocations.iter().all(|alloc| alloc.no_overlaps(other)) -} - -fn is_malloc_valid(alloc: &Allocation, state: &BuggyCommandSequenceState) -> Result<(), AccessError> { - if !alloc.is_in_bounds() { - return Err(AccessError::OutOfBounds { addr: alloc.addr, len: alloc.len }); - } else if !no_allocs_in_range(&state, &alloc) { - return Err(AccessError::DoubleMalloc { addr: alloc.addr, len: alloc.len }); - } else { - return Ok(()); - } -} - -fn is_free_valid(addr: usize, state: &BuggyCommandSequenceState) -> Result<(), AccessError> { - if !state.allocations.iter().any(|alloc| alloc.addr == addr) { - return Err(AccessError::InvalidFree { addr }); - } else { - return Ok(()); - } -} - -fn is_read_valid(addr: usize, len: usize, state: &BuggyCommandSequenceState) -> Result<(), AccessError> { - let dummy = Allocation::new(addr, len); - if !dummy.is_in_bounds() { - return Err(AccessError::OutOfBounds { addr, len }); - } - let in_range: Vec<_> = state.allocations.iter() - .filter(|alloc| alloc.addr <= addr && - addr + len <= alloc.addr + alloc.len && alloc.memstate.contains(&MemState::ValidToReadWrite)).collect(); - if in_range.is_empty() { - return Err(AccessError::InvalidRead { addr, len }); - } else { - let memstate_addr = addr - &in_range[0].addr; - for i in memstate_addr..memstate_addr + len { - // println!("{:?}", mem_index); - if in_range[0].memstate[i] != MemState::ValidToReadWrite { - return Err(AccessError::InvalidRead { addr, len }); - } - } - return Ok(()); - } -} - -fn is_write_valid(addr: usize, len: usize, state: &BuggyCommandSequenceState) -> Result<(), AccessError> { - let dummy = Allocation::new(addr, len); - //this doesn't include stack... have to change to include validity for stack read/writes - if !dummy.is_in_bounds() { - return Err(AccessError::OutOfBounds { addr, len }); - } - if !state.allocations.iter().any(|alloc| alloc.addr <= addr && addr + len <= alloc.addr + alloc.len) { - return Err(AccessError::InvalidWrite { addr, len }); - } else { - return Ok(()); - } -} \ No newline at end of file diff --git a/crates/wmemcheck/fuzz/fuzz_targets/valid_accesses.rs b/crates/wmemcheck/fuzz/fuzz_targets/valid_accesses.rs deleted file mode 100644 index 241ec3b803be..000000000000 --- a/crates/wmemcheck/fuzz/fuzz_targets/valid_accesses.rs +++ /dev/null @@ -1,216 +0,0 @@ -#![no_main] - -use libfuzzer_sys::fuzz_target; -use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured, Error}; -use wmemcheck::{Wmemcheck, MemState}; -use std::cmp::*; - -const TEST_MAX_ADDR: usize = 1024 * 640 - 1; -const TEST_MAX_STACK_SIZE: usize = 1024; - -fuzz_target!(|data: &[u8]| { - let u = &mut Unstructured::new(data); - let mut wmemcheck_state = Wmemcheck::new(TEST_MAX_ADDR + 1, TEST_MAX_STACK_SIZE); - let cmds = match CommandSequence::arbitrary(u) { - Ok(val) => val, - Err(_) => return, - }; - println!("commands: {:?}", cmds); - for cmd in cmds.commands.iter() { - let cmd: &Command = cmd; - match cmd { - &Command::Malloc { addr, len } => { - assert!(wmemcheck_state.malloc(addr, len).is_ok()); - } - &Command::Free { addr } => { - assert!(wmemcheck_state.free(addr).is_ok()); - } - &Command::Read { addr, len } => { - assert!(wmemcheck_state.read(addr, len).is_ok()); - } - &Command::Write { addr, len } => { - assert!(wmemcheck_state.write(addr, len).is_ok()); - } - } - } -}); - -#[derive(Debug)] -pub struct Allocation { - addr: usize, - len: usize, - memstate: Vec, -} - -impl Allocation { - fn new(addr: usize, len: usize) -> Allocation { - Allocation { addr: addr, len: len, memstate: vec![MemState::ValidToWrite; len] } - } - fn no_overlaps(&self, other: &Allocation) -> bool { - other.addr + other.len <= self.addr || self.addr + self.len <= other.addr - } - fn is_in_bounds(&self) -> bool { - TEST_MAX_STACK_SIZE <= self.addr && self.addr + self.len - 1 <= TEST_MAX_ADDR - } -} - -#[derive(Debug)] -enum Command { - Malloc {addr: usize, len: usize}, - Read {addr: usize, len: usize}, - Write {addr: usize, len: usize}, - Free {addr: usize} -} - -#[derive(Debug)] -struct CommandSequence { - commands: Vec, -} - -struct CommandSequenceState { - allocations: Vec, -} - -impl CommandSequenceState { - fn new() -> CommandSequenceState { - let allocations = Vec::new(); - CommandSequenceState { allocations } - } - fn update(&mut self, cmd: &Command) { - match cmd { - &Command::Malloc { addr, len } => { - self.allocations.push(Allocation::new(addr, len)); - } - &Command::Free { addr } => { - let index = self.allocations.iter().position(|alloc| alloc.addr == addr).unwrap(); - self.allocations.remove(index); - } - &Command::Write { addr, len } => { - let index = self.allocations.iter().position(|alloc| alloc.addr <= addr && addr + len <= alloc.addr + alloc.len).unwrap(); - let alloc_addr = self.allocations[index].addr; - let write_to = &mut self.allocations[index].memstate; - for i in 0..len { - write_to[addr - alloc_addr + i] = MemState::ValidToReadWrite; - } - } - _ => {} - } - } - } - -impl<'a> Arbitrary<'a> for CommandSequence { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - let mut commands = vec![]; - let mut state = CommandSequenceState::new(); - for _ in 0..u.arbitrary::()? { - let cmd = match u.int_in_range(0..=3)? { - 0 => { - let malloc_range = pick_free_addr_range(&state, u)?; - Command::Malloc { addr: malloc_range.0, len: malloc_range.1 } - } - 1 => { - let unalloc_index = u.choose_index(state.allocations.len())?; - let unalloc_addr = state.allocations[unalloc_index].addr; - Command::Free { addr: unalloc_addr } - } - 2 => { - let read_range = pick_read_range(&state, u)?; - Command::Read { addr: read_range.0, len: read_range.1 } - } - 3 => { - let write_index = u.choose_index(state.allocations.len())?; - let mut write_range = 1; - if state.allocations[write_index].len > 1 { - write_range = u.int_in_range(1..=state.allocations[write_index].len)?; - } - Command::Write { addr: state.allocations[write_index].addr, len: write_range } - } - _ => { - unreachable!() - } - }; - println!("{:?}", cmd); - state.update(&cmd); - commands.push(cmd); - } - Ok(CommandSequence { commands }) - } -} - -fn pick_free_addr_range(state: &CommandSequenceState, u: &mut Unstructured<'_>) -> Result<(usize, usize), Error> { - let mut addr = u.int_in_range(TEST_MAX_STACK_SIZE..=TEST_MAX_ADDR)?; - let dummy_alloc = Allocation::new(addr, 1); - let mut attempts = 0; - while !no_allocs_in_range(state, &dummy_alloc) { - addr = u.int_in_range(1024..=TEST_MAX_ADDR)?; - attempts += 1; - if attempts == 10 { - return Err(Error::NotEnoughData); - } - } - let mut len = 1; - if TEST_MAX_ADDR - addr > 1 { - len = u.int_in_range(1..=TEST_MAX_ADDR - addr)?; - } - attempts = 0; - while !no_allocs_in_range(state, &Allocation::new(addr, len)) { - if TEST_MAX_ADDR - addr > 1 { - len = u.int_in_range(1..=TEST_MAX_ADDR - addr)?; - } - attempts += 1; - if attempts == 10 { - return Err(Error::NotEnoughData); - } - } - Ok((addr, len)) -} - -fn pick_read_range(state: &CommandSequenceState, u: &mut Unstructured<'_>) -> Result<(usize, usize), Error> { - if state.allocations.is_empty() { - return Err(Error::NotEnoughData); - } - let mut alloc_index = u.choose_index(state.allocations.len())?; - let mut attempts = 0; - while !state.allocations[alloc_index].memstate.contains(&MemState::ValidToReadWrite) { - alloc_index = u.choose_index(state.allocations.len())?; - attempts += 1; - if attempts == min(state.allocations.len(), 10) { - return Err(Error::NotEnoughData); - } - } - let mut memstate_addr = u.int_in_range(0..=state.allocations[alloc_index].len - 1)?; - attempts = 0; - while let MemState::ValidToWrite = state.allocations[alloc_index].memstate[memstate_addr] { - memstate_addr = u.int_in_range(0..=state.allocations[alloc_index].len - 1)?; - attempts += 1; - if attempts == 10 { - return Err(Error::NotEnoughData); - } - } - if state.allocations[alloc_index].memstate.len() - memstate_addr <= 1 { - return Ok((state.allocations[alloc_index].addr + memstate_addr, 1)); - } - let mut len = u.int_in_range(0..=state.allocations[alloc_index].memstate.len() - memstate_addr)?; - attempts = 0; - while !ok_range(state, alloc_index, memstate_addr, memstate_addr + len) { - len = u.int_in_range(0..=state.allocations[alloc_index].memstate.len() - 1)?; - attempts += 1; - if attempts == 10 { - return Err(Error::NotEnoughData); - } - } - Ok((state.allocations[alloc_index].addr + memstate_addr, len)) -} - -fn ok_range(state: &CommandSequenceState, alloc_index: usize, start: usize, end: usize) -> bool { - for i in start..end { - if let MemState::ValidToWrite = state.allocations[alloc_index].memstate[i] { - return false; - } - } - true -} - -fn no_allocs_in_range(state: &CommandSequenceState, other: &Allocation ) -> bool { - state.allocations.iter().all(|alloc| alloc.no_overlaps(other)) -} \ No newline at end of file From 62e3461515c9d308552adf1610b5c66cda0132af Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 10 Aug 2023 14:47:05 -0700 Subject: [PATCH 29/34] Review feedback and test fix. --- crates/cranelift/src/func_environ.rs | 2 +- crates/runtime/src/instance/allocator/pooling.rs | 2 ++ crates/types/src/lib.rs | 2 +- crates/wasmtime/src/config.rs | 4 ++++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index fbb2100dde9e..39df50fb0b0c 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -2552,7 +2552,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } fn before_memory_grow(&mut self, builder: &mut FunctionBuilder, num_pages: ir::Value, mem_index: MemoryIndex) { - if self.wmemcheck && mem_index.0 == 0 { + if self.wmemcheck && mem_index.as_u32() == 0 { let update_mem_size_sig = self.builtin_function_signatures.update_mem_size(builder.func); let (vmctx, update_mem_size) = self.translate_load_builtin_function_address( &mut builder.cursor(), diff --git a/crates/runtime/src/instance/allocator/pooling.rs b/crates/runtime/src/instance/allocator/pooling.rs index fd99c0f3b423..c35cf6ffd2e4 100644 --- a/crates/runtime/src/instance/allocator/pooling.rs +++ b/crates/runtime/src/instance/allocator/pooling.rs @@ -1057,6 +1057,7 @@ mod test { }, host_state: Box::new(()), store: StorePtr::empty(), + wmemcheck: false, }) .expect("allocation should succeed"), ); @@ -1074,6 +1075,7 @@ mod test { }, host_state: Box::new(()), store: StorePtr::empty(), + wmemcheck: false, }) { Err(_) => {} _ => panic!("unexpected error"), diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 0dc5db6aacf9..320c6e479d99 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -203,7 +203,7 @@ entity_impl!(GlobalIndex); /// Index type of a linear memory (imported or defined) inside the WebAssembly module. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] -pub struct MemoryIndex(pub u32); +pub struct MemoryIndex(u32); entity_impl!(MemoryIndex); /// Index type of a signature (imported or defined) inside the WebAssembly module. diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index ec18597612d3..c9a5585630aa 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1550,6 +1550,10 @@ impl Config { { bail!("static memory guard size cannot be smaller than dynamic memory guard size"); } + #[cfg(not(feature = "wmemcheck"))] + if self.wmemcheck { + bail!("wmemcheck (memory checker) was requested but is not enabled in this build"); + } Ok(()) } From 0acc9da2165aaf166f24f5b4754df1d295673f34 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 10 Aug 2023 15:20:53 -0700 Subject: [PATCH 30/34] add wasmtime-wmemcheck crate to publish allowlist. --- scripts/publish.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/publish.rs b/scripts/publish.rs index 1f3ebdafe617..33d399453c44 100644 --- a/scripts/publish.rs +++ b/scripts/publish.rs @@ -59,6 +59,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[ "wasmtime-cache", "winch-codegen", "wasmtime-winch", + "wasmtime-wmemcheck", "wasmtime", // wasi-common/wiggle "wiggle", From e2c8af126afa6c88b8da93679706369557dd1a2d Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 10 Aug 2023 18:59:28 -0700 Subject: [PATCH 31/34] fix build without compiler features --- crates/wasmtime/src/config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index c9a5585630aa..e9813369db81 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1485,6 +1485,7 @@ impl Config { /// Enables memory error checking for wasm programs. /// /// This option is disabled by default. + #[cfg(any(feature = "cranelift", feature = "winch"))] pub fn wmemcheck(&mut self, enable: bool) -> &mut Self { self.wmemcheck = enable; self.compiler_config.wmemcheck = enable; From a222399c874a05b06028d0da8ca73f6a36ea38e2 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 10 Aug 2023 19:41:25 -0700 Subject: [PATCH 32/34] reorder crates in publish list --- scripts/publish.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/publish.rs b/scripts/publish.rs index 33d399453c44..598dd40c0901 100644 --- a/scripts/publish.rs +++ b/scripts/publish.rs @@ -52,6 +52,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[ "wasmtime-jit-debug", "wasmtime-fiber", "wasmtime-environ", + "wasmtime-wmemcheck", "wasmtime-runtime", "wasmtime-cranelift-shared", "wasmtime-cranelift", @@ -59,7 +60,6 @@ const CRATES_TO_PUBLISH: &[&str] = &[ "wasmtime-cache", "winch-codegen", "wasmtime-winch", - "wasmtime-wmemcheck", "wasmtime", // wasi-common/wiggle "wiggle", From b820b5052ba4d2afcd974002e43b06e91b4b996f Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Mon, 14 Aug 2023 08:31:35 -0700 Subject: [PATCH 33/34] Add trampolines for libcalls on s390x. --- crates/runtime/src/trampolines/s390x.S | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/runtime/src/trampolines/s390x.S b/crates/runtime/src/trampolines/s390x.S index b6b8bf01d0c2..3cf80d9d6e4b 100644 --- a/crates/runtime/src/trampolines/s390x.S +++ b/crates/runtime/src/trampolines/s390x.S @@ -60,3 +60,11 @@ LIBCALL_TRAMPOLINE(memory_atomic_wait32, impl_memory_atomic_wait32) LIBCALL_TRAMPOLINE(memory_atomic_wait64, impl_memory_atomic_wait64) LIBCALL_TRAMPOLINE(out_of_gas, impl_out_of_gas) LIBCALL_TRAMPOLINE(new_epoch, impl_new_epoch) +LIBCALL_TRAMPOLINE(check_malloc, impl_check_malloc) +LIBCALL_TRAMPOLINE(check_free, impl_check_free) +LIBCALL_TRAMPOLINE(check_load, impl_check_load) +LIBCALL_TRAMPOLINE(check_store, impl_check_store) +LIBCALL_TRAMPOLINE(malloc_start, impl_malloc_start) +LIBCALL_TRAMPOLINE(free_start, impl_free_start) +LIBCALL_TRAMPOLINE(update_stack_pointer, impl_update_stack_pointer) +LIBCALL_TRAMPOLINE(update_mem_size, impl_update_mem_size) From 7db34f6e4c0bf03dc961ed1703fb30cca8b395c0 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Mon, 14 Aug 2023 09:31:47 -0700 Subject: [PATCH 34/34] Make wasmtime-wmemcheck dep an exact version requirement. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 061c2e0551d0..5c7d3ff79f0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,7 +123,7 @@ edition = "2021" rust-version = "1.66.0" [workspace.dependencies] -wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "13.0.0" } +wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "=13.0.0" } wasmtime = { path = "crates/wasmtime", version = "13.0.0", default-features = false } wasmtime-cache = { path = "crates/cache", version = "=13.0.0" } wasmtime-cli-flags = { path = "crates/cli-flags", version = "=13.0.0" }