@@ -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 ( ) ) {
@@ -1505,6 +1516,72 @@ fn ensure_memory(
1505
1516
Ok ( ( ) )
1506
1517
}
1507
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 total_bytes = l
1559
+ . data
1560
+ . iter ( )
1561
+ . map ( |_| get_type_in_memory_size ( ltd. get_list_item_type ( ) , true ) )
1562
+ . sum :: < i32 > ( ) as usize ;
1563
+ Ok ( total_bytes)
1564
+ }
1565
+ Value :: Principal ( PrincipalData :: Standard ( _) ) => Ok ( STANDARD_PRINCIPAL_BYTES ) ,
1566
+ Value :: Principal ( PrincipalData :: Contract ( p) )
1567
+ | Value :: CallableContract ( CallableData {
1568
+ contract_identifier : p,
1569
+ ..
1570
+ } ) => Ok ( PRINCIPAL_BYTES + 1 + p. name . len ( ) as usize ) ,
1571
+ Value :: Tuple ( TupleData { data_map, .. } ) => {
1572
+ let TypeSignature :: TupleType ( tuple_ty) = ty else {
1573
+ return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ;
1574
+ } ;
1575
+
1576
+ let mut total_bytes = 0 ;
1577
+ for ( name, ty) in tuple_ty. get_type_map ( ) {
1578
+ total_bytes += get_required_bytes ( ty, & data_map[ name] ) ?;
1579
+ }
1580
+ Ok ( total_bytes)
1581
+ }
1582
+ }
1583
+ }
1584
+
1508
1585
/// Convert a Clarity `Value` into one or more Wasm `Val`. If this value
1509
1586
/// requires writing into the Wasm memory, write it to the provided `offset`.
1510
1587
/// Return a vector of `Val`s that can be passed to a Wasm function, and the
@@ -1604,9 +1681,6 @@ fn pass_argument_to_wasm(
1604
1681
Ok ( ( buffer, new_offset, new_in_mem_offset) )
1605
1682
}
1606
1683
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
-
1610
1684
// For a string, write the bytes into the memory, then pass the
1611
1685
// offset and length to the Wasm function.
1612
1686
let buffer = vec ! [ Val :: I32 ( in_mem_offset) , Val :: I32 ( s. data. len( ) as i32 ) ] ;
@@ -1621,9 +1695,6 @@ fn pass_argument_to_wasm(
1621
1695
Ok ( ( buffer, offset, adjusted_in_mem_offset) )
1622
1696
}
1623
1697
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
-
1627
1698
// For a utf8 string, convert the chars to big-endian i32, convert this into a list of
1628
1699
// bytes, then pass the offset and length to the wasm function
1629
1700
let bytes: Vec < u8 > = String :: from_utf8 ( s. items ( ) . iter ( ) . flatten ( ) . copied ( ) . collect ( ) )
@@ -1639,9 +1710,6 @@ fn pass_argument_to_wasm(
1639
1710
Ok ( ( buffer, offset, adjusted_in_mem_offset) )
1640
1711
}
1641
1712
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
-
1645
1713
// For a buffer, write the bytes into the memory, then pass the
1646
1714
// offset and length to the Wasm function.
1647
1715
let buffer = vec ! [ Val :: I32 ( in_mem_offset) , Val :: I32 ( b. data. len( ) as i32 ) ] ;
@@ -1659,14 +1727,6 @@ fn pass_argument_to_wasm(
1659
1727
let TypeSignature :: SequenceType ( SequenceSubtype :: ListType ( ltd) ) = ty else {
1660
1728
return Err ( Error :: Wasm ( WasmError :: ValueTypeMismatch ) ) ;
1661
1729
} ;
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) ?;
1669
-
1670
1730
let mut buffer = vec ! [ Val :: I32 ( offset) ] ;
1671
1731
let mut written = 0 ;
1672
1732
let mut in_mem_written = 0 ;
0 commit comments