As a security-minded Solidity developer, this is your sign to be very careful when using unchecked blocks and inline assembly. As of 0.8.0 and later the compiler will automatically handle under/overflows. But what happens if a variable allowed to overflow is then used in yul? The EVM actually has no concept of narrow types, so low level yul code operates on the full 256-bit word size. Can you see where this is going yet? In this heavily simplified scenario I came across in my current @CyfrinAudits engagement, the length variable silently overflows uint8 within the unchecked block and wraps around to 254 as expected. However, when used to resize the array within the subsequent inline assembly block, the dirty upper bits persist as if the overflow never occurred! This results in the length of the array being considerably larger than expected, even though we might expect it to be bounded modulo the maximum value representable by the length variable. Using the foundry debugger and cast --to-base <0xfe|0x01fe> dec, we can confirm that our assumptions were incorrect and the upper bits do indeed remain dirty when writing the length to memory. While this example can be simplified even further, the key takeaway is to always be very suspicious of unchecked/assembly blocks and consider how the upper bits of narrow types may become dirty, even for something as simple in yul as an assignment. This can sometimes feel like an esoteric bug that is impossible to spot without deep knowledge of the EVM and Solidity compiler internals, so once realising what was afoot I found this concrete example to be quite helpful. Drop me a comment below if you have any questions, but hopefully you found it helpful too!
7,76K