From a79b3cfe3ff7229813eb49399c3f9f8a45c4fec8 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 5 Sep 2024 17:10:34 -0700 Subject: [PATCH] Add a small harness that just loads all wasms from a workspace directory (#1454) This is just a small test harness to help people who want to run simple testcases they've generated outside soroban. Put your wasm file in `soroban-env-host/src/test/hostile_inputs` and run `cargo test test_misc_hostile_wasms` and it should just pick your wasm up and attempt to instantiate and run it. Requirements: - The wasm has to have the normal contract metadata section on the front! Absent that it will be rejected immediately. - The wasm of course has to comply with the limited profile soroban uses (few-if-any post-MVP features, no floating point, etc.) - The wasm has to expose a 0-arg function called "test" which is the only thing the test tries to execute. --- .github/workflows/rust.yml | 4 +- soroban-env-host/src/test/hostile.rs | 101 ++++++++++++++++++ .../test/hostile_inputs/example_add_i32.wasm | Bin 0 -> 584 bytes .../src/test/hostile_inputs/smoke.wasm | Bin 0 -> 68 bytes 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 soroban-env-host/src/test/hostile_inputs/example_add_i32.wasm create mode 100644 soroban-env-host/src/test/hostile_inputs/smoke.wasm diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 397d6a132..e83decf87 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -63,10 +63,10 @@ jobs: steps: - uses: actions/checkout@v3 - run: rustup update - - uses: stellar/binaries@v24 + - uses: stellar/binaries@v29 with: name: cargo-semver-checks - version: 0.32.0 + version: 0.35.0 - run: cargo semver-checks --exclude soroban-simulation build-and-test: diff --git a/soroban-env-host/src/test/hostile.rs b/soroban-env-host/src/test/hostile.rs index 0981db11d..a7d7081eb 100644 --- a/soroban-env-host/src/test/hostile.rs +++ b/soroban-env-host/src/test/hostile.rs @@ -1322,3 +1322,104 @@ fn test_stack_depth_stability() { (ScErrorType::Budget, ScErrorCode::ExceededLimit) )); } + +#[test] +fn test_misc_hostile_wasms() { + // This test loads and runs a bunch of hostile WASM modules + // found in the hostile_inputs subdirectory. It attempts to + // instantiate the contract and then run a 0-ary function in + // the contract called "test". + let mut bad_inputs = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + bad_inputs.push("src/test/hostile_inputs"); + eprintln!("loading hostile inputs from {:?}", bad_inputs); + let mut n_wasms = 0; + let mut n_instantiated_ok = 0; + let mut n_instantiated_external_error = 0; + let mut n_instantiated_internal_error = 0; + let mut n_executed_ok = 0; + let mut n_executed_external_error = 0; + let mut n_executed_internal_error = 0; + + for entry in std::fs::read_dir(bad_inputs).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.extension().unwrap() == "wasm" { + let host = Host::test_host_with_recording_footprint(); + let filename = path.file_name().unwrap().to_str().unwrap().to_string(); + let wasm_code = std::fs::read(path).unwrap(); + eprintln!("loaded {}-byte wasm {}", wasm_code.len(), filename); + n_wasms += 1; + host.as_budget().reset_unlimited().unwrap(); + let addr_res = host.register_test_contract_wasm_from_source_account( + &wasm_code, + generate_account_id(&host), + generate_bytes_array(&host), + ); + match addr_res { + Err(e) => { + if e.error.is_code(ScErrorCode::InternalError) { + eprintln!( + "instantiation failed with internal error for {}: {:?}", + filename, e + ); + n_instantiated_internal_error += 1; + } else { + eprintln!( + "instantiation failed with external error for {}: {:?}", + filename, e + ); + n_instantiated_external_error += 1; + } + continue; + } + Ok(contract_id) => { + n_instantiated_ok += 1; + let call_res = host.call( + contract_id, + Symbol::try_from_small_str("test").unwrap(), + test_vec![&host].into(), + ); + if let Err(e) = call_res { + if e.error.is_code(ScErrorCode::InternalError) { + eprintln!( + "execution failed with internal error for {}: {:?}", + filename, e + ); + n_executed_internal_error += 1; + } else { + eprintln!( + "execution failed with external error for {}: {:?}", + filename, e + ); + n_executed_external_error += 1; + } + } else { + n_executed_ok += 1; + eprintln!("execution succeeded for {}", filename); + } + } + } + } + } + eprintln!("loaded {} hostile Wasm modules", n_wasms); + eprintln!("instantiated {} contracts successfully", n_instantiated_ok); + eprintln!( + "instantiation failed with external error for {} contracts", + n_instantiated_external_error + ); + eprintln!( + "instantiation failed with internal error for {} contracts", + n_instantiated_internal_error + ); + eprintln!("executed {} contracts successfully", n_executed_ok); + eprintln!( + "execution failed with external error for {} contracts", + n_executed_external_error + ); + eprintln!( + "execution failed with internal error for {} contracts", + n_executed_internal_error + ); + assert_eq!(n_instantiated_internal_error, 0); + assert_eq!(n_executed_internal_error, 0); +} diff --git a/soroban-env-host/src/test/hostile_inputs/example_add_i32.wasm b/soroban-env-host/src/test/hostile_inputs/example_add_i32.wasm new file mode 100644 index 0000000000000000000000000000000000000000..ba6b3fc4e132b2fa351b6ef2863bb5159b7b71e3 GIT binary patch literal 584 zcmY*V&2G~`5S|~escH&~KoxL6>$X?YI7z$oR$D?;;>HWO8+!w4lr*xV2rfw^s;Vbm z199LTdf^3l1s(*Z`Dy8lv@`R4GvBNRTs=SlK+UH#o#OPAW;1yKXp8VOCPGc{BLD{s zNQx13_=0Dc&ga(<&ES4~u&=^_ADmZT2-uY+5atkU=6UJHF89NdG0O8#-i`9Et3A`^ zALL(1f$ZFc)bw|F59ruH_7}fq>Vv^mQoRjsP;>P?4g|c3%5e7W_m8KRH!_OD6l3CJ zL()en_G4O*arh9U$gl}5Ys0BN+Ywf?Aeha?MzZF@@^b;;e?W^0Y1Z)4s1#02V3drS z;N;yFijFzk14BPEb1CDGBM{#P0}CLyFt|!IMsl_Y-ajhNhvUi><9g(aNmDMqw#AvG zpcQ~_nW%N$y{l1D1+Sj0#r$wG@MCwY_iWKx-!8jHs;Zv&YAF^b4clqlePg4l>$1P3 u+pT6p{B>2dc5RUybh@3MKXh$d+QQky+IFW^`m%d?)N3crH_f91--Cb1f^ud6 literal 0 HcmV?d00001 diff --git a/soroban-env-host/src/test/hostile_inputs/smoke.wasm b/soroban-env-host/src/test/hostile_inputs/smoke.wasm new file mode 100644 index 0000000000000000000000000000000000000000..e7abcab3e58e625c9bae5ae0122eebf0574fa839 GIT binary patch literal 68 zcmWm4F%Ezr5Cp*8;{<}0U-BhV5JHq|p!PYwQ*9@MJURhz;Q`)Gh!Cl>j0q%9#f}w8 TE%zespIf+^oz1F5Pdp#JJB|s~ literal 0 HcmV?d00001