Forráskód Böngészése

Handle `abi.encode()` with empty args (#1801)

This is a small bugfix for the case when `abi.encode()` is called with
empty arguments.

Without this change, if you run the following command, you get a panic:
```sh
$ cargo run compile --target=polkadot testdata/solidity/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol
...
thread 'main' panicked at src/codegen/encoding/mod.rs:169:46:
index out of bounds: the len is 0 but the index is 0
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
The cause of the panic is this function:
```sol
    function f0() public pure returns (bytes memory) {
        return abi.encode();
    }
```
With the change, the command completes successfully.

Signed-off-by: Samuel Moelius <samuel.moelius@trailofbits.com>
Samuel Moelius 5 hónapja
szülő
commit
12a6d83b91

+ 7 - 0
src/codegen/encoding/mod.rs

@@ -166,6 +166,13 @@ fn calculate_size_args(
     vartab: &mut Vartable,
     cfg: &mut ControlFlowGraph,
 ) -> Expression {
+    if args.is_empty() {
+        return Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: BigInt::zero(),
+        };
+    }
     let mut size = encoder.get_expr_size(0, &args[0], ns, vartab, cfg);
     for (i, item) in args.iter().enumerate().skip(1) {
         let additional = encoder.get_expr_size(i, item, ns, vartab, cfg);

+ 58 - 0
tests/codegen_testcases/solidity/abi_encode_v2.sol

@@ -0,0 +1,58 @@
+// RUN: --target polkadot --emit cfg
+
+pragma abicoder               v2;
+
+
+contract C {
+    struct S {
+        uint256 a;
+        uint256[] b;
+    }
+
+    // CHECK: C::function::f0
+    function f0() public pure returns (bytes memory) {
+        return abi.encode();
+    }
+
+    function f1() public pure returns (bytes memory) {
+        return abi.encode(1, 2);
+    }
+
+    function f2() public pure returns (bytes memory) {
+        string memory x = "abc";
+        return abi.encode(1, x, 2);
+    }
+
+    function f3() public pure returns (bytes memory r) {
+        // test that memory is properly allocated
+        string memory x = "abc";
+        r = abi.encode(1, x, 2);
+        bytes memory y = "def";
+        require(y[0] == "d");
+        y[0] = "e";
+        require(y[0] == "e");
+    }
+
+    S s;
+
+    function f4() public returns (bytes memory r) {
+        string memory x = "abc";
+        s.a = 7;
+        s.b.push(2);
+        s.b.push(3);
+        r = abi.encode(1, x, s, 2);
+        bytes memory y = "def";
+        require(y[0] == "d");
+        y[0] = "e";
+        require(y[0] == "e");
+    }
+}
+// ----
+// f0() -> 0x20, 0x0
+// f1() -> 0x20, 0x40, 0x1, 0x2
+// f2() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc"
+// f3() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc"
+// f4() -> 0x20, 0x160, 0x1, 0x80, 0xc0, 0x2, 0x3, "abc", 0x7, 0x40, 0x2, 0x2, 0x3
+// gas irOptimized: 112630
+// gas legacy: 114794
+// gas legacyOptimized: 112572