@@ -549,6 +549,17 @@ pub fn call_function<'a>(
549
549
}
550
550
let mut in_mem_offset = offset + arg_size;
551
551
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
+
552
563
// Convert the args into wasmtime values
553
564
let mut wasm_args = vec ! [ ] ;
554
565
for ( arg, ty) in args. iter ( ) . zip ( func_types. get_arg_types ( ) ) {
@@ -1486,6 +1497,94 @@ fn write_to_wasm(
1486
1497
}
1487
1498
}
1488
1499
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
+
1489
1588
/// Convert a Clarity `Value` into one or more Wasm `Val`. If this value
1490
1589
/// requires writing into the Wasm memory, write it to the provided `offset`.
1491
1590
/// 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(
1631
1730
let TypeSignature :: SequenceType ( SequenceSubtype :: ListType ( ltd) ) = ty else {
1632
1731
return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ;
1633
1732
} ;
1634
-
1635
1733
let mut buffer = vec ! [ Val :: I32 ( offset) ] ;
1636
1734
let mut written = 0 ;
1637
1735
let mut in_mem_written = 0 ;
0 commit comments