mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-11-03 09:21:11 +00:00
add integration test for i32 operand overflow in PVM linker const fold (#552)
Closes #551 --------- Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
1 parent
3d70def08c
commit
541955d31b
5 files changed
+94
-26
No files matched your search
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
/// Regression: at `-O3` (the `OptimizerSettings::cycles()` middle/back-end
|
||||
/// level used by the differential harness) LLVM proves the low 64 bits of
|
||||
/// `(a2 + (a0 << 64)) ^ a2` cancel to zero and narrows the surviving
|
||||
/// `| 0x80000000 | 0x80000001` work down to native i32 lane operations.
|
||||
/// The constant `0x80000000` (`2^31`) is materialized with `lui x, 0x80000`.
|
||||
/// During link time the polkavm-linker (`program_from_elf.rs`) constant-folds
|
||||
/// the narrowed 32-bit op through `OperationKind::apply_const`, whose `op32!`
|
||||
/// macro does `i64 -> i32` via `try_into().expect("operand overflow")`. The
|
||||
/// tracked constant for `0x80000000` does not fit the signed i32 range, so the
|
||||
/// fold panics with `operand overflow: TryFromIntError` — an ICE instead of a
|
||||
/// clean compile. solc's EVM backend has no such narrowing (everything is
|
||||
/// 256-bit), so the same source compiles cleanly there.
|
||||
contract LinkerI32BoundaryFoldBug {
|
||||
function test(int256 a0, int256 a2) external pure returns (int256) {
|
||||
int256 t1 = (a2 + (a0 * int256(18446744073709551616))) ^ a2; // low-64 cancel
|
||||
t1 = t1 | int256(2147483648); // 0x80000000 (i32 sign boundary)
|
||||
t1 = t1 | int256(2147483649); // 0x80000001
|
||||
return t1;
|
||||
}
|
||||
}
|
||||
@@ -329,6 +329,20 @@ case!(
|
||||
const_return_overflow_bug,
|
||||
);
|
||||
|
||||
sol!(
|
||||
contract LinkerI32BoundaryFoldBug {
|
||||
function test(int256 a0, int256 a2) external pure returns (int256);
|
||||
}
|
||||
);
|
||||
case!(
|
||||
"LinkerI32BoundaryFoldBug.sol",
|
||||
LinkerI32BoundaryFoldBug,
|
||||
testCall,
|
||||
linker_i32_boundary_fold_bug,
|
||||
a0: I256,
|
||||
a2: I256
|
||||
);
|
||||
|
||||
// `PanicInterveneBug` has only a `fallback()` — invoked by sending
|
||||
// raw calldata that doesn't match any selector. Empty calldata works.
|
||||
case!(
|
||||
|
||||
@@ -494,6 +494,36 @@ fn const_return_offset_overflow_traps() {
|
||||
run_differential(actions);
|
||||
}
|
||||
|
||||
/// Regression: at `-O3` LLVM proves the low 64 bits of
|
||||
/// `(a2 + (a0 << 64)) ^ a2` cancel and narrows the trailing
|
||||
/// `| 0x80000000 | 0x80000001` down to native i32 lane operations,
|
||||
/// materializing `0x80000000` (`2^31`) via `lui x, 0x80000`. The
|
||||
/// polkavm-linker's constant propagation then folds the narrowed 32-bit
|
||||
/// op through `OperationKind::apply_const`, whose `op32!` macro converts
|
||||
/// `i64 -> i32` with `try_into().expect("operand overflow")`. The tracked
|
||||
/// constant `0x80000000` does not fit the signed i32 range, so the fold
|
||||
/// panics (`operand overflow: TryFromIntError`) — an ICE instead of a
|
||||
/// clean compile. solc's EVM backend has no such narrowing (all ops are
|
||||
/// 256-bit) so the same source compiles cleanly there.
|
||||
#[test]
|
||||
fn linker_i32_boundary_constant_fold() {
|
||||
let mut actions = instantiate(
|
||||
"contracts/LinkerI32BoundaryFoldBug.sol",
|
||||
"LinkerI32BoundaryFoldBug",
|
||||
);
|
||||
let a0 = I256::try_from(0x0123456789abcdef_i64).unwrap();
|
||||
let a2 = I256::try_from(-0x7654321076543210_i64).unwrap();
|
||||
actions.push(Call {
|
||||
origin: TestAddress::Alice,
|
||||
dest: TestAddress::Instantiated(0),
|
||||
value: 0,
|
||||
gas_limit: None,
|
||||
storage_deposit_limit: None,
|
||||
data: Contract::linker_i32_boundary_fold_bug(a0, a2).calldata,
|
||||
});
|
||||
run_differential(actions);
|
||||
}
|
||||
|
||||
/// Regression: `simplify.rs::find_panic_pattern_backwards` walks the
|
||||
/// statement list backwards from `revert(0, 0x24)` and accepts an
|
||||
/// `mstore` at offsets ≠ 0 / 4 as "safe filler" — it skips it in the
|
||||
|
||||
Reference in new issue
Block a user