Skip to content

Commit

Permalink
Clean dirty addresses and booleans (#5195)
Browse files Browse the repository at this point in the history
Co-authored-by: Hadrien Croubois <[email protected]>
  • Loading branch information
cairoeth and Amxx authored Sep 18, 2024
1 parent 809ded8 commit 3f90169
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 7 deletions.
4 changes: 2 additions & 2 deletions contracts/utils/SlotDerivation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ library SlotDerivation {
*/
function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x00, and(key, shr(96, not(0))))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
Expand All @@ -81,7 +81,7 @@ library SlotDerivation {
*/
function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x00, iszero(iszero(key)))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
Expand Down
5 changes: 5 additions & 0 deletions scripts/generate/helpers/sanitize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
address: expr => `and(${expr}, shr(96, not(0)))`,
bool: expr => `iszero(iszero(${expr}))`,
bytes: (expr, size) => `and(${expr}, shl(${256 - 8 * size}, not(0)))`,
};
9 changes: 5 additions & 4 deletions scripts/generate/templates/Packing.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const format = require('../format-lines');
const sanitize = require('../helpers/sanitize');
const { product } = require('../../helpers');
const { SIZES } = require('./Packing.opts');

Expand Down Expand Up @@ -44,8 +45,8 @@ function pack_${left}_${right}(bytes${left} left, bytes${right} right) internal
left + right
} result) {
assembly ("memory-safe") {
left := and(left, shl(${256 - 8 * left}, not(0)))
right := and(right, shl(${256 - 8 * right}, not(0)))
left := ${sanitize.bytes('left', left)}
right := ${sanitize.bytes('right', right)}
result := or(left, shr(${8 * left}, right))
}
}
Expand All @@ -55,7 +56,7 @@ const extract = (outer, inner) => `\
function extract_${outer}_${inner}(bytes${outer} self, uint8 offset) internal pure returns (bytes${inner} result) {
if (offset > ${outer - inner}) revert OutOfRangeAccess();
assembly ("memory-safe") {
result := and(shl(mul(8, offset), self), shl(${256 - 8 * inner}, not(0)))
result := ${sanitize.bytes('shl(mul(8, offset), self)', inner)}
}
}
`;
Expand All @@ -64,7 +65,7 @@ const replace = (outer, inner) => `\
function replace_${outer}_${inner}(bytes${outer} self, bytes${inner} value, uint8 offset) internal pure returns (bytes${outer} result) {
bytes${inner} oldValue = extract_${outer}_${inner}(self, offset);
assembly ("memory-safe") {
value := and(value, shl(${256 - 8 * inner}, not(0)))
value := ${sanitize.bytes('value', inner)}
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
}
}
Expand Down
2 changes: 2 additions & 0 deletions scripts/generate/templates/Slot.opts.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ const TYPES = [
{ type: 'bytes', isValueType: false },
].map(type => Object.assign(type, { name: type.name ?? capitalize(type.type) }));

Object.assign(TYPES, Object.fromEntries(TYPES.map(entry => [entry.type, entry])));

module.exports = { TYPES };
3 changes: 2 additions & 1 deletion scripts/generate/templates/SlotDerivation.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const format = require('../format-lines');
const sanitize = require('../helpers/sanitize');
const { TYPES } = require('./Slot.opts');

const header = `\
Expand Down Expand Up @@ -77,7 +78,7 @@ const mapping = ({ type }) => `\
*/
function deriveMapping(bytes32 slot, ${type} key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x00, ${(sanitize[type] ?? (x => x))('key')})
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
Expand Down
14 changes: 14 additions & 0 deletions scripts/generate/templates/SlotDerivation.t.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ function testSymbolicDeriveMapping${name}(${type} key) public {
}
`;

const mappingDirty = ({ type, name }) => `\
function testSymbolicDeriveMapping${name}Dirty(bytes32 dirtyKey) public {
${type} key;
assembly {
key := dirtyKey
}
// run the "normal" test using a potentially dirty value
testSymbolicDeriveMapping${name}(key);
}
`;

const boundedMapping = ({ type, name }) => `\
mapping(${type} => bytes) private _${type}Mapping;
Expand Down Expand Up @@ -107,6 +119,8 @@ module.exports = format(
})),
),
).map(type => (type.isValueType ? mapping(type) : boundedMapping(type))),
mappingDirty(TYPES.bool),
mappingDirty(TYPES.address),
),
).trimEnd(),
'}',
Expand Down
20 changes: 20 additions & 0 deletions test/utils/SlotDerivation.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,24 @@ contract SlotDerivationTest is Test, SymTest {

assertEq(baseSlot.deriveMapping(key), derivedSlot);
}

function testSymbolicDeriveMappingBooleanDirty(bytes32 dirtyKey) public {
bool key;
assembly {
key := dirtyKey
}

// run the "normal" test using a potentially dirty value
testSymbolicDeriveMappingBoolean(key);
}

function testSymbolicDeriveMappingAddressDirty(bytes32 dirtyKey) public {
address key;
assembly {
key := dirtyKey
}

// run the "normal" test using a potentially dirty value
testSymbolicDeriveMappingAddress(key);
}
}

0 comments on commit 3f90169

Please sign in to comment.