Skip to content

Commit

Permalink
fix: short-return type in asserts!
Browse files Browse the repository at this point in the history
  • Loading branch information
csgui committed Oct 2, 2024
1 parent 3d8adaa commit e63e671
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 10 deletions.
74 changes: 65 additions & 9 deletions clar2wasm/src/error_mapping.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use clarity::vm::errors::{CheckErrors, Error, RuntimeErrorType, ShortReturnType, WasmError};
use clarity::vm::types::ResponseData;
use clarity::vm::Value;
use clarity::vm::types::{ListTypeData, SequenceSubtype, TypeSignature};
use wasmtime::{AsContextMut, Instance, Trap};

use crate::wasm_utils::read_identifier_from_wasm;
use crate::wasm_utils::{read_from_wasm, read_identifier_from_wasm};

const LOG2_ERROR_MESSAGE: &str = "log2 must be passed a positive integer";
const SQRTI_ERROR_MESSAGE: &str = "sqrti must be passed a positive integer";
Expand Down Expand Up @@ -150,12 +149,69 @@ fn from_runtime_error_code(
// TODO: UInt(42) value below is just a placeholder.
// It should be replaced by the current "thrown-value" when issue #385 is resolved.
// Tests that reach this code are currently ignored.
ErrorMap::ShortReturnAssertionFailure => Error::ShortReturn(
ShortReturnType::AssertionFailed(Value::Response(ResponseData {
committed: false,
data: Box::new(Value::UInt(42)),
})),
),
ErrorMap::ShortReturnAssertionFailure => {
let val_offset = instance
.get_global(&mut store, "runtime-error-arg-offset")
.and_then(|glob| glob.get(&mut store).i32())
.unwrap_or_else(|| {
panic!("Could not find $runtime-error-arg-offset global with i32 value")
});

let val_len = instance
.get_global(&mut store, "runtime-error-arg-len")
.and_then(|glob| glob.get(&mut store).i32())
.unwrap_or_else(|| {
panic!("Could not find $runtime-error-arg-len global with i32 value")
});

let typesig_offset = instance
.get_global(&mut store, "runtime-error-typesig-offset")
.and_then(|glob| glob.get(&mut store).i32())
.unwrap_or_else(|| {
panic!("Could not find $runtime-error-typesig-offset global with i32 value")
});

let typesig_len = instance
.get_global(&mut store, "runtime-error-typesig-len")
.and_then(|glob| glob.get(&mut store).i32())
.unwrap_or_else(|| {
panic!("Could not find $runtime-error-typesig-len global with i32 value")
});

let memory = instance
.get_memory(&mut store, "memory")
.unwrap_or_else(|| panic!("Could not find wasm instance memory"));

let typesig = read_identifier_from_wasm(
memory,
&mut store,
typesig_offset,
typesig_len,
)
.unwrap_or_else(|e| panic!("Could not recover stringified type: {e}"));

dbg!(typesig.clone());

let ty = match typesig.as_str() {
"uint" => TypeSignature::UIntType,
"int" => TypeSignature::IntType,
"bool" => TypeSignature::BoolType,
_ => panic!("Unknown type signature")
};

let v = read_from_wasm(
memory,
&mut store,
&ty,
val_offset,
val_len,
clarity::types::StacksEpochId::Epoch25
)
.unwrap_or_else(|e| panic!("Could not recover value: {e}"));

Error::ShortReturn(
ShortReturnType::AssertionFailed(v),
)},
ErrorMap::ArithmeticPowError => Error::Runtime(
RuntimeErrorType::Arithmetic(POW_ERROR_MESSAGE.into()),
Some(Vec::new()),
Expand Down
40 changes: 39 additions & 1 deletion clar2wasm/src/wasm_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,16 +628,54 @@ impl WasmGenerator {
if let Some(block_id) = self.early_return_block_id {
builder.instr(walrus::ir::Br { block: block_id });
} else {
// This must be from a top-leve statement, so it should cause a runtime error
// This must be from a top-level statement, so it should cause a runtime error
builder
.i32_const(ErrorMap::ShortReturnAssertionFailure as i32)
.call(self.func_by_name("stdlib.runtime-error"));

builder.unreachable();
}

Ok(())
}

pub fn asserts_return_early(&mut self, builder: &mut InstrSeqBuilder, expr: &SymbolicExpression) -> Result<(), GeneratorError> {
if let Some(block_id) = self.early_return_block_id {
builder.instr(walrus::ir::Br { block: block_id });
return Ok(());
}

let ty = self
.get_expr_type(expr)
.ok_or_else(|| {
GeneratorError::TypeError("asserts! thrown-value must be typed".to_owned())
})?
.clone();

dbg!(ty.clone());

let (val_offset, val_len) = self.create_call_stack_local(builder, &ty, false, true);
self.write_to_memory(builder, val_offset, 0, &ty)?;

let (typesig_offset, typesig_len) = self.add_string_literal(ty.to_string().as_str())?;

builder
.local_get(val_offset)
.global_set(get_global(&self.module, "runtime-error-arg-offset")?)
.i32_const(val_len)
.global_set(get_global(&self.module, "runtime-error-arg-len")?)
.i32_const(typesig_offset as i32)
.global_set(get_global(&self.module, "runtime-error-typesig-offset")?)
.i32_const(typesig_len as i32)
.global_set(get_global(&self.module, "runtime-error-typesig-len")?)
.i32_const(ErrorMap::ShortReturnAssertionFailure as i32)
.call(self.func_by_name("stdlib.runtime-error"));

builder.unreachable();

Ok(())
}

/// Gets the result type of the given `SymbolicExpression`.
pub fn get_expr_type(&self, expr: &SymbolicExpression) -> Option<&TypeSignature> {
self.contract_analysis
Expand Down

0 comments on commit e63e671

Please sign in to comment.