Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

♻️ More memory-safe annotations #1353

Merged
merged 2 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions prep/memory-safe-scan.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env node
const { readSync, forEachWalkSync, hasAnyPathSequence } = require('./common.js');

async function main() {
const pathSequencesToIgnore = ['g', 'legacy'];

const loggedSrcPaths = [];
forEachWalkSync(['src'], srcPath => {
if (!srcPath.match(/\.sol$/i)) return;
if (hasAnyPathSequence(srcPath, pathSequencesToIgnore)) return;

const src = readSync(srcPath);
const assemblyTagRe = /(\/\/\/\s*?@solidity\s*?memory-safe-assembly\s+?)?assembly\s*?(\(.*?\))?\{/gm;
for (let m = null; (m = assemblyTagRe.exec(src)) !== null; ) {
if ((m[0] + '').indexOf('memory-safe') === -1) {
if (loggedSrcPaths.indexOf(srcPath) === -1) {
loggedSrcPaths.push(srcPath);
console.log(srcPath + ':');
}
console.log(' line:', src.slice(0, m.index).split(/\n/).length);
}
}
});
};

main().catch(e => {
console.error(e);
process.exit(1);
});
2 changes: 2 additions & 0 deletions src/accounts/EIP7702Proxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ contract EIP7702Proxy {
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

constructor(address initialImplementation, address initialAdmin) payable {
/// @solidity memory-safe-assembly
assembly {
sstore(_ERC1967_IMPLEMENTATION_SLOT, shr(96, shl(96, initialImplementation)))
sstore(_ERC1967_ADMIN_SLOT, shr(96, shl(96, initialAdmin)))
Expand All @@ -50,6 +51,7 @@ contract EIP7702Proxy {

fallback() external payable virtual {
uint256 s = __self;
/// @solidity memory-safe-assembly
assembly {
mstore(0x40, returndatasize()) // Optimization trick to change `6040608052` into `3d604052`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean 6080604052 (mstore(0x40, 0x80))?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes. Nice find!

// Workflow for calling on the proxy itself.
Expand Down
3 changes: 3 additions & 0 deletions src/accounts/ERC6551Proxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ contract ERC6551Proxy {

fallback() external payable virtual {
bytes32 implementation;
/// @solidity memory-safe-assembly
assembly {
mstore(0x40, returndatasize()) // Optimization trick to change `6040608052` into `3d604052`.
implementation := sload(_ERC1967_IMPLEMENTATION_SLOT)
}
if (implementation == bytes32(0)) {
implementation = _defaultImplementation;
/// @solidity memory-safe-assembly
assembly {
// Only initialize if the calldatasize is zero, so that staticcalls to
// functions (which will have 4-byte function selectors) won't revert.
Expand All @@ -60,6 +62,7 @@ contract ERC6551Proxy {
if iszero(calldatasize()) { sstore(_ERC1967_IMPLEMENTATION_SLOT, implementation) }
}
}
/// @solidity memory-safe-assembly
assembly {
calldatacopy(returndatasize(), returndatasize(), calldatasize())
// forgefmt: disable-next-item
Expand Down
1 change: 1 addition & 0 deletions src/tokens/ERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ abstract contract ERC721 {
///
/// Emits a {Approval} event.
function _approve(address by, address account, uint256 id) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Clear the upper 96 bits.
let bitmaskAddress := shr(96, not(0))
Expand Down
1 change: 1 addition & 0 deletions src/tokens/ext/zksync/ERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ abstract contract ERC721 {
///
/// Emits a {Approval} event.
function _approve(address by, address account, uint256 id) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Clear the upper 96 bits.
let bitmaskAddress := shr(96, not(0))
Expand Down
2 changes: 2 additions & 0 deletions src/utils/DynamicArrayLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ library DynamicArrayLib {

/// @dev Directly returns `a` without copying.
function directReturn(uint256[] memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let retStart := sub(a, 0x20)
mstore(retStart, 0x20)
Expand Down Expand Up @@ -988,6 +989,7 @@ library DynamicArrayLib {

/// @dev Directly returns `a` without copying.
function directReturn(DynamicArray memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let arrData := mload(a)
let retStart := sub(arrData, 0x20)
Expand Down
8 changes: 4 additions & 4 deletions src/utils/ECDSA.sol
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ library ECDSA {

/// @dev Returns the canonical hash of `signature`.
function canonicalHash(bytes memory signature) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
/// @solidity memory-safe-assembly
assembly {
let l := mload(signature)
for {} 1 {} {
Expand Down Expand Up @@ -369,7 +369,7 @@ library ECDSA {
pure
returns (bytes32 result)
{
// @solidity memory-safe-assembly
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
mstore(0x00, calldataload(signature.offset)) // `r`.
Expand Down Expand Up @@ -400,7 +400,7 @@ library ECDSA {

/// @dev Returns the canonical hash of `signature`.
function canonicalHash(bytes32 r, bytes32 vs) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, r) // `r`.
let v := add(shr(255, vs), 27)
Expand All @@ -414,7 +414,7 @@ library ECDSA {

/// @dev Returns the canonical hash of `signature`.
function canonicalHash(uint8 v, bytes32 r, bytes32 s) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, r) // `r`.
if iszero(lt(s, _HALF_N_PLUS_1)) {
Expand Down
2 changes: 2 additions & 0 deletions src/utils/LibBytes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,7 @@ library LibBytes {

/// @dev Directly returns `a` without copying.
function directReturn(bytes memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the bytes does not start from the scratch space.
let retStart := sub(a, 0x20)
Expand All @@ -660,6 +661,7 @@ library LibBytes {

/// @dev Directly returns `a` with minimal copying.
function directReturn(bytes[] memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let n := mload(a) // `a.length`.
let o := add(a, 0x20) // Start of elements in `a`.
Expand Down
1 change: 1 addition & 0 deletions src/utils/LibString.sol
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,7 @@ library LibString {

/// @dev Directly returns `a` without copying.
function directReturn(string memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the string does not start from the scratch space.
let retStart := sub(a, 0x20)
Expand Down
2 changes: 2 additions & 0 deletions src/utils/g/DynamicArrayLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ library DynamicArrayLib {

/// @dev Directly returns `a` without copying.
function directReturn(uint256[] memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let retStart := sub(a, 0x20)
mstore(retStart, 0x20)
Expand Down Expand Up @@ -992,6 +993,7 @@ library DynamicArrayLib {

/// @dev Directly returns `a` without copying.
function directReturn(DynamicArray memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let arrData := mload(a)
let retStart := sub(arrData, 0x20)
Expand Down
2 changes: 2 additions & 0 deletions src/utils/g/LibBytes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ library LibBytes {

/// @dev Directly returns `a` without copying.
function directReturn(bytes memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the bytes does not start from the scratch space.
let retStart := sub(a, 0x20)
Expand All @@ -664,6 +665,7 @@ library LibBytes {

/// @dev Directly returns `a` with minimal copying.
function directReturn(bytes[] memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let n := mload(a) // `a.length`.
let o := add(a, 0x20) // Start of elements in `a`.
Expand Down
1 change: 1 addition & 0 deletions src/utils/g/LibString.sol
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,7 @@ library LibString {

/// @dev Directly returns `a` without copying.
function directReturn(string memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the string does not start from the scratch space.
let retStart := sub(a, 0x20)
Expand Down
Loading