mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-10-25 05:05:06 +00:00
Fix optimization specific SREM edge case (#527)
Existing test coverage didn't catch a signed remainder overflow semantics edge case behavior where at least one the operators is being constant folded by LLVM instead of solc. This PR fixes the SREM translation bug and adds missing test coverage for division ops with constants. Closes #524 --------- Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
1 parent
62a62770e3
commit
40e97d11eb
23 files changed
+1336
-21
No files matched your search
@@ -160,6 +160,15 @@ impl WriteLLVM for Remainder {
|
||||
}
|
||||
|
||||
/// Implements the signed remainder operator according to the EVM specification.
|
||||
///
|
||||
/// `srem(INT_MIN, -1)` is signed-overflow UB in LLVM even though the
|
||||
/// mathematical remainder is `0`, and EVM `SMOD` defines this case as `0`.
|
||||
/// Before performing the srem we therefore swap a `-1` divisor for `1`:
|
||||
/// `srem(x, 1) == 0 == SMOD(x, -1)` for all x, so the substitution preserves
|
||||
/// EVM semantics while never feeding the UB pair to LLVM's srem. Unlike a
|
||||
/// branch-based guard this leaves the srem unconditionally well-defined at
|
||||
/// the IR level, so constant propagation cannot fold its way into poison
|
||||
/// regardless of pass ordering. See paritytech/revive#524.
|
||||
pub struct SignedRemainder;
|
||||
|
||||
impl RuntimeFunction for SignedRemainder {
|
||||
@@ -180,9 +189,24 @@ impl RuntimeFunction for SignedRemainder {
|
||||
let operand_2 = Self::paramater(context, 1).into_int_value();
|
||||
|
||||
wrapped_division(context, operand_2, || {
|
||||
let is_neg_one = context.builder().build_int_compare(
|
||||
inkwell::IntPredicate::EQ,
|
||||
operand_2,
|
||||
context.word_type().const_all_ones(),
|
||||
"smod_divisor_is_neg_one",
|
||||
)?;
|
||||
let safe_divisor = context
|
||||
.builder()
|
||||
.build_select(
|
||||
is_neg_one,
|
||||
context.word_const(1),
|
||||
operand_2,
|
||||
"smod_safe_divisor",
|
||||
)?
|
||||
.into_int_value();
|
||||
Ok(context
|
||||
.builder()
|
||||
.build_int_signed_rem(operand_1, operand_2, "SMOD")?)
|
||||
.build_int_signed_rem(operand_1, safe_divisor, "SMOD")?)
|
||||
})
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user