@@ -549,6 +549,17 @@ pub fn call_function<'a>(
549549 }
550550 let mut in_mem_offset = offset + arg_size;
551551
552+ // Ensure that the memory has enough space for the arguments
553+ let mut total_required_bytes = 0 ;
554+ for ( arg, ty) in args. iter ( ) . zip ( func_types. get_arg_types ( ) ) {
555+ total_required_bytes += get_required_bytes ( ty, arg) ?;
556+ }
557+ ensure_memory (
558+ & memory,
559+ & mut store,
560+ total_required_bytes + in_mem_offset as usize ,
561+ ) ?;
562+
552563 // Convert the args into wasmtime values
553564 let mut wasm_args = vec ! [ ] ;
554565 for ( arg, ty) in args. iter ( ) . zip ( func_types. get_arg_types ( ) ) {
@@ -1486,6 +1497,94 @@ fn write_to_wasm(
14861497 }
14871498}
14881499
1500+ /// Ensure the memory is large enough to write the given number of bytes.
1501+ fn ensure_memory (
1502+ memory : & Memory ,
1503+ store : & mut impl AsContextMut ,
1504+ required_bytes : usize ,
1505+ ) -> Result < ( ) , Error > {
1506+ // Round up division.
1507+ let required_pages = ( ( required_bytes + 65535 ) / 65536 ) as u64 ;
1508+ let current_pages = memory. size ( store. as_context_mut ( ) ) ;
1509+ // If the current memory is not large enough, grow it by the required
1510+ // number of pages.
1511+ if current_pages < required_pages {
1512+ memory
1513+ . grow ( store. as_context_mut ( ) , required_pages - current_pages)
1514+ . map_err ( |e| Error :: Wasm ( WasmError :: UnableToWriteMemory ( e. into ( ) ) ) ) ?;
1515+ }
1516+ Ok ( ( ) )
1517+ }
1518+
1519+ /// Get the number of bytes required to write the given value to memory.
1520+ /// This is used to ensure that the memory has enough space for the arguments.
1521+ fn get_required_bytes ( ty : & TypeSignature , value : & Value ) -> Result < usize , Error > {
1522+ match value {
1523+ Value :: UInt ( _) | Value :: Int ( _) | Value :: Bool ( _) => {
1524+ // These types don't require memory allocation
1525+ Ok ( 0 )
1526+ }
1527+ Value :: Optional ( o) => {
1528+ let TypeSignature :: OptionalType ( inner_ty) = ty else {
1529+ return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ;
1530+ } ;
1531+
1532+ if let Some ( inner_value) = o. data . as_ref ( ) {
1533+ get_required_bytes ( inner_ty, inner_value)
1534+ } else {
1535+ Ok ( 0 )
1536+ }
1537+ }
1538+ Value :: Response ( r) => {
1539+ let TypeSignature :: ResponseType ( inner_tys) = ty else {
1540+ return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ;
1541+ } ;
1542+ get_required_bytes (
1543+ if r. committed {
1544+ & inner_tys. 0
1545+ } else {
1546+ & inner_tys. 1
1547+ } ,
1548+ & r. data ,
1549+ )
1550+ }
1551+ Value :: Sequence ( SequenceData :: String ( CharType :: ASCII ( s) ) ) => Ok ( s. data . len ( ) ) ,
1552+ Value :: Sequence ( SequenceData :: String ( CharType :: UTF8 ( s) ) ) => Ok ( s. data . len ( ) ) ,
1553+ Value :: Sequence ( SequenceData :: Buffer ( b) ) => Ok ( b. data . len ( ) ) ,
1554+ Value :: Sequence ( SequenceData :: List ( l) ) => {
1555+ let TypeSignature :: SequenceType ( SequenceSubtype :: ListType ( ltd) ) = ty else {
1556+ return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ;
1557+ } ;
1558+ let element_size = get_type_in_memory_size ( ltd. get_list_item_type ( ) , true ) as usize ;
1559+ let total_bytes = element_size * l. data . len ( ) ;
1560+ Ok ( total_bytes)
1561+ }
1562+ Value :: Principal ( PrincipalData :: Standard ( _) ) => Ok ( STANDARD_PRINCIPAL_BYTES ) ,
1563+ Value :: Principal ( PrincipalData :: Contract ( p) )
1564+ | Value :: CallableContract ( CallableData {
1565+ contract_identifier : p,
1566+ ..
1567+ } ) => Ok ( PRINCIPAL_BYTES + 1 + p. name . len ( ) as usize ) ,
1568+ Value :: Tuple ( TupleData { data_map, .. } ) => {
1569+ let TypeSignature :: TupleType ( tuple_ty) = ty else {
1570+ return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ;
1571+ } ;
1572+
1573+ let mut total_bytes = 0 ;
1574+ for ( name, ty) in tuple_ty. get_type_map ( ) {
1575+ match data_map. get ( name) {
1576+ Some ( value) => total_bytes += get_required_bytes ( ty, value) ?,
1577+ None => return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ,
1578+ }
1579+ }
1580+ if data_map. len ( ) != tuple_ty. get_type_map ( ) . len ( ) {
1581+ return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ;
1582+ }
1583+ Ok ( total_bytes)
1584+ }
1585+ }
1586+ }
1587+
14891588/// Convert a Clarity `Value` into one or more Wasm `Val`. If this value
14901589/// requires writing into the Wasm memory, write it to the provided `offset`.
14911590/// Return a vector of `Val`s that can be passed to a Wasm function, and the
@@ -1631,7 +1730,6 @@ fn pass_argument_to_wasm(
16311730 let TypeSignature :: SequenceType ( SequenceSubtype :: ListType ( ltd) ) = ty else {
16321731 return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ;
16331732 } ;
1634-
16351733 let mut buffer = vec ! [ Val :: I32 ( offset) ] ;
16361734 let mut written = 0 ;
16371735 let mut in_mem_written = 0 ;
0 commit comments