Skip to content

Commit d8e6e8b

Browse files
committed
fix: ensure memory is allocated for writing args
1 parent f04ad0b commit d8e6e8b

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

clarity/src/vm/clarity_wasm.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,25 @@ fn write_to_wasm(
14861486
}
14871487
}
14881488

1489+
/// Ensure the memory is large enough to write the given number of bytes.
1490+
fn ensure_memory(
1491+
memory: &Memory,
1492+
store: &mut impl AsContextMut,
1493+
required_bytes: usize,
1494+
) -> Result<(), Error> {
1495+
// Round up division.
1496+
let required_pages = ((required_bytes + 65535) / 65536) as u64;
1497+
let current_pages = memory.size(store.as_context_mut());
1498+
// If the current memory is not large enough, grow it by the required
1499+
// number of pages.
1500+
if current_pages < required_pages {
1501+
memory
1502+
.grow(store.as_context_mut(), required_pages - current_pages)
1503+
.map_err(|e| Error::Wasm(WasmError::UnableToWriteMemory(e.into())))?;
1504+
}
1505+
Ok(())
1506+
}
1507+
14891508
/// Convert a Clarity `Value` into one or more Wasm `Val`. If this value
14901509
/// requires writing into the Wasm memory, write it to the provided `offset`.
14911510
/// Return a vector of `Val`s that can be passed to a Wasm function, and the
@@ -1585,6 +1604,9 @@ fn pass_argument_to_wasm(
15851604
Ok((buffer, new_offset, new_in_mem_offset))
15861605
}
15871606
Value::Sequence(SequenceData::String(CharType::ASCII(s))) => {
1607+
let required_bytes = (in_mem_offset as usize) + s.data.len();
1608+
ensure_memory(&memory, &mut store, required_bytes)?;
1609+
15881610
// For a string, write the bytes into the memory, then pass the
15891611
// offset and length to the Wasm function.
15901612
let buffer = vec![Val::I32(in_mem_offset), Val::I32(s.data.len() as i32)];
@@ -1599,6 +1621,9 @@ fn pass_argument_to_wasm(
15991621
Ok((buffer, offset, adjusted_in_mem_offset))
16001622
}
16011623
Value::Sequence(SequenceData::String(CharType::UTF8(s))) => {
1624+
let required_bytes = (in_mem_offset as usize) + s.data.len();
1625+
ensure_memory(&memory, &mut store, required_bytes)?;
1626+
16021627
// For a utf8 string, convert the chars to big-endian i32, convert this into a list of
16031628
// bytes, then pass the offset and length to the wasm function
16041629
let bytes: Vec<u8> = String::from_utf8(s.items().iter().flatten().copied().collect())
@@ -1614,6 +1639,9 @@ fn pass_argument_to_wasm(
16141639
Ok((buffer, offset, adjusted_in_mem_offset))
16151640
}
16161641
Value::Sequence(SequenceData::Buffer(b)) => {
1642+
let required_bytes = (in_mem_offset as usize) + b.data.len();
1643+
ensure_memory(&memory, &mut store, required_bytes)?;
1644+
16171645
// For a buffer, write the bytes into the memory, then pass the
16181646
// offset and length to the Wasm function.
16191647
let buffer = vec![Val::I32(in_mem_offset), Val::I32(b.data.len() as i32)];
@@ -1631,6 +1659,13 @@ fn pass_argument_to_wasm(
16311659
let TypeSignature::SequenceType(SequenceSubtype::ListType(ltd)) = ty else {
16321660
return Err(Error::Wasm(WasmError::ValueTypeMismatch));
16331661
};
1662+
let total_bytes = l
1663+
.data
1664+
.iter()
1665+
.map(|_| get_type_in_memory_size(ltd.get_list_item_type(), true))
1666+
.sum::<i32>() as usize;
1667+
let required_bytes = (in_mem_offset as usize) + total_bytes;
1668+
ensure_memory(&memory, &mut store, required_bytes)?;
16341669

16351670
let mut buffer = vec![Val::I32(offset)];
16361671
let mut written = 0;

0 commit comments

Comments
 (0)