contract C { uint public x; function f(bool a) public { x = 1; // This write is removed due to the bug. g(a); x = 2; } function g(bool a) internal { // The relevant part of this function is that it can // both return to the caller and terminate the transaction. // The bug will show its effects in the cases in which // the transaction is terminated (i.e. if a is false). // In this case the write x = 1 above will be missing. if (a) return; assembly { return(0,0) } } }
contract C { function bug() public returns (uint a, uint b) { assembly { mstore(0, 0) // The optimizer computes the value at compile time: // 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563 a := keccak256(0, 32) // The optimizer incorrectly uses the cached value // and transforms the next line to // b := 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563 // instead of // b := 0xe2b9f9f9430b05bfa9a3abd3bac9a181434d23a707ef1cde8bd25d30203538d8 b := keccak256(0, 23) } } }
contract C { function bug() public view returns (bool ret) { assembly { let x := calldataload(0) mstore(0, x) mstore(0x20, x) let a := keccak256(0, 4) // even though the memory location is different, // the 32-byte content is the same. let b := keccak256(0x20, 8) // Here `a` and `b` were considered equal, // leading to `ret` being incorrectly set to true. ret := eq(a, b) } } }
contract C { bytes data; function f() public returns (bytes memory) { // Empty byte array bytes memory t; // Store something else in memory after it uint[2] memory x; x[0] = type(uint).max; // Copy the empty byte array to storage, // this will copy too much from memory. data = t; // Create a new byte array element, // this will only update the length value. data.push(); // Now, `data[0]` is `0xff` instead of `0`. return data; } }