Skip to content

Commit d0e39dc

Browse files
committed
More rewrites for array/map clash
1 parent 7fa6a95 commit d0e39dc

File tree

2 files changed

+33
-38
lines changed

2 files changed

+33
-38
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6161
via masking
6262
- More rewrite rules for (PLT (Lit 0) _) and (PEq (Lit 1) _)
6363
- Simplification can now be turned off from the cli via --no-simplify
64+
- More rewrite rules for array and map lookups.
6465

6566
## Fixed
6667
- We now try to simplify expressions fully before trying to cast them to a concrete value

src/EVM/Expr.hs

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -639,20 +639,26 @@ readStorage w st = go (simplifyNoLitToKeccak w) (simplifyNoLitToKeccak st)
639639
(a, b) | surelyEqual a b -> Just val
640640
(a, b) | surelyNotEqual a b -> go slot prev
641641

642-
-- slot is for a map + map -> skip write
643-
(MappingSlot idA _, MappingSlot idB _) | isMap' idB, isMap' idA, idsDontMatch idA idB -> go slot prev
644-
(MappingSlot idA keyA, MappingSlot idB keyB) | isMap' idB, isMap' idA, surelyNotEqual keyA keyB -> go slot prev
642+
(MappingSlot idA _, MappingSlot idB _) | isMap' idB, isMap' idA, idsDontMatch idA idB -> go slot prev
643+
(MappingSlot idA keyA, MappingSlot idB keyB) | isMap' idB, isMap' idA, idA == idB, surelyNotEqual keyA keyB -> go slot prev
644+
(MappingSlot idA _, ArraySlotZero idB) | isMap' idA, isArray idB -> go slot prev
645645

646-
-- special case of array + map -> skip write
647-
(ArraySlotWithOffs idA _, Keccak k) | isMap k, isArray idA -> go slot prev
648-
(ArraySlotWithOffs2 idA _ _, Keccak k) | isMap k, isArray idA -> go slot prev
649-
(ArraySlotZero idA, Keccak k) | isMap k, isArray idA -> go slot prev
650-
651-
-- special case of map + array -> skip write
652-
(Keccak k, ArraySlotWithOffs idA _) | isMap k, isArray idA -> go slot prev
653-
(Keccak k, ArraySlotWithOffs2 idA _ _) | isMap k, isArray idA -> go slot prev
654-
(ArraySlotWithOffs idA _, Keccak k) | isMap k, isArray idA -> go slot prev
655-
(ArraySlotWithOffs2 idA _ _, Keccak k) | isMap k, isArray idA -> go slot prev
646+
(ArraySlotZero idA, ArraySlotZero idB) | isArray idA, isArray idB, idA /= idB -> go slot prev
647+
(ArraySlotZero idA, ArraySlotWithOffs idB (Lit off)) | isArray idA, isArray idB, idA /= idB, off < 256, off /= 0 -> go slot prev
648+
(ArraySlotZero idA, ArraySlotWithOffs idB (Lit off)) | isArray idA, idA == idB, off /= 0 -> go slot prev
649+
(ArraySlotZero idA, MappingSlot idB _) | isArray idA, isMap' idB -> go slot prev
650+
(ArraySlotZero idA, Keccak idB) | isArray idA, isMap idB -> go slot prev
651+
652+
(ArraySlotWithOffs idA (Lit off), ArraySlotZero idB) | isArray idA, isArray idB, idA /= idB, off < 256 -> go slot prev
653+
(ArraySlotWithOffs idA (Lit off), ArraySlotZero idB) | isArray idA, idA == idB, off /= 0 -> go slot prev
654+
(ArraySlotWithOffs idA (Lit offA), ArraySlotWithOffs idB (Lit offB)) | isArray idA, isArray idB, idA /= idB, offA < 256, offB < 256 -> go slot prev
655+
(ArraySlotWithOffs idA offA, ArraySlotWithOffs idB offB) | isArray idA, idA == idB, surelyNotEqual offA offB -> go slot prev
656+
(ArraySlotWithOffs idB offB2, ArraySlotWithOffs2 idA offA1 offA2) | isArray idA, idA == idB, surelyNotEqual (Add (Lit offA1) offA2) offB2 -> go slot prev
657+
(ArraySlotWithOffs idA (Lit off), Keccak idB) | isArray idA, isMap idB, off < 256 -> go slot prev
658+
(ArraySlotWithOffs idA (Lit off), MappingSlot idB _) | isArray idA, isMap' idB, off < 256 -> go slot prev
659+
660+
(Keccak idA, ArraySlotZero idB) | isMap idA, isArray idB -> go slot prev
661+
(Keccak idA, ArraySlotWithOffs idB (Lit offs)) | isMap idA, isArray idB, offs < 256 -> go slot prev
656662

657663
-- Fixed SMALL value will never match Keccak (well, it might, but that's VERY low chance)
658664
(Lit a, Keccak _) | a < 256 -> go slot prev
@@ -663,40 +669,27 @@ readStorage w st = go (simplifyNoLitToKeccak w) (simplifyNoLitToKeccak st)
663669
-- occurring here is 2^32/2^256 = 2^-224, which is close enough to zero
664670
-- for our purposes. This lets us completely simplify reads from write
665671
-- chains involving writes to arrays at literal offsets.
666-
(Lit a, Add (Lit b) (Keccak _)) | a < 256, b < maxW32 -> go slot prev
667-
(Add (Lit a) (Keccak _) ,Lit b) | b < 256, a < maxW32 -> go slot prev
672+
(Lit a, Add (Lit offB) (Keccak _)) | a < 256, offB < maxW32 -> go slot prev
673+
(Add (Lit offA) (Keccak _), Lit b) | b < 256, offA < maxW32 -> go slot prev
668674

669675
-- Finding two Keccaks that are < 256 away from each other should be VERY hard
670676
-- This simplification allows us to deal with maps of structs
671-
(Add (Lit a2) (Keccak _), Add (Lit b2) (Keccak _)) | a2 /= b2, abs (a2-b2) < 256 -> go slot prev
672-
(Add (Lit a2) (Keccak _), (Keccak _)) | a2 > 0, a2 < 256 -> go slot prev
673-
((Keccak _), Add (Lit b2) (Keccak _)) | b2 > 0, b2 < 256 -> go slot prev
674-
675-
-- zero offs vs zero offs
676-
(ArraySlotZero idA, ArraySlotZero idB) | isArray idA, isArray idB, idA /= idB -> go slot prev
677-
678-
-- zero offs vs non-zero offs
679-
(ArraySlotZero idA, ArraySlotWithOffs idB _) | isArray idA, isArray idB, idA /= idB -> go slot prev
680-
(ArraySlotZero idA, ArraySlotWithOffs idB (Lit offB)) | isArray idA, idA == idB, offB /= 0 -> go slot prev
681-
(ArraySlotZero idA, ArraySlotWithOffs2 idB _ _) | isArray idA, isArray idB, idA /= idB -> go slot prev
677+
(Add (Lit a) (Keccak _), Add (Lit b) (Keccak _)) | a /= b, abs (a-b) < 256 -> go slot prev
678+
(Add (Lit a) (Keccak _), (Keccak _)) | a > 0, a < 256 -> go slot prev
679+
((Keccak _), Add (Lit b) (Keccak _)) | b > 0, b < 256 -> go slot prev
682680

683-
-- non-zero offs vs zero offs
684-
(ArraySlotWithOffs idA _, ArraySlotZero idB) | isArray idA, isArray idB, idA /= idB -> go slot prev
685-
(ArraySlotWithOffs idA (Lit offA), ArraySlotZero idB) | isArray idA, idA == idB, offA /= 0 -> go slot prev
686-
687-
-- non-zero offs vs non-zero offs, different ids
688-
(ArraySlotWithOffs idA _, ArraySlotWithOffs idB _) | isArray idA, isArray idB, idA /= idB -> go slot prev
689-
690-
-- non-zero offs vs non-zero offs, same ids
691-
(ArraySlotWithOffs idA a, ArraySlotWithOffs idB b) | isArray idA, idA == idB,
692-
surelyNotEqual a b -> go slot prev
693-
(ArraySlotWithOffs idB offB2, ArraySlotWithOffs2 idA offA1 offA2) | isArray idA, idA == idB,
694-
surelyNotEqual (Add (Lit offA1) offA2) offB2 -> go slot prev
695681
(ArraySlotWithOffs2 idA offA1 offA2, ArraySlotWithOffs idB offB2) | isArray idA, idA == idB,
696682
surelyNotEqual (Add (Lit offA1) offA2) offB2 -> go slot prev
697683
(ArraySlotWithOffs2 idA offA1 offA2, ArraySlotWithOffs2 idB offB1 offB2) | isArray idA, idA == idB,
698684
surelyNotEqual (Add (Lit offA1) offA2) (Add (Lit offB1) offB2) -> go slot prev
699685

686+
-- DANGEROUS: offset could possibly be VERY large and SPECIFIC in order to make them clash
687+
-- This would constitute a hack, and would require a specifically badly written code
688+
(MappingSlot idA _, ArraySlotWithOffs idB _) | isMap' idA, isArray idB -> go slot prev
689+
(MappingSlot idA _, ArraySlotWithOffs2 idB _ _) | isMap' idA, isArray idB -> go slot prev
690+
(ArraySlotWithOffs idA _, MappingSlot idB _) | isArray idA, isMap' idB -> go slot prev
691+
(ArraySlotWithOffs2 idA _ _, MappingSlot idB _) | isArray idA, isMap' idB -> go slot prev
692+
700693
-- we are unable to determine statically whether or not we can safely move deeper in the write chain, so return an abstract term
701694
_ -> Just $ SLoad slot s
702695

@@ -731,6 +724,7 @@ pattern ArraySlotWithOffs2 id offs1 offs2 = Add (Lit offs1) (Add offs2 (Keccak (
731724
-- special pattern to match the 0th element because the `Add` term gets simplified out
732725
pattern ArraySlotZero :: ByteString -> Expr EWord
733726
pattern ArraySlotZero id = Keccak (ConcreteBuf id)
727+
734728
-- checks if two mapping ids match or not
735729
idsDontMatch :: ByteString -> ByteString -> Bool
736730
idsDontMatch a b = BS.length a >= 64 && BS.length b >= 64 && diff32to64Byte a b

0 commit comments

Comments
 (0)