Impact
We found a bug in EraVM LLVM back end leading to possible invalid stack access. This issue occurred because the addresses used to access the stack were not properly converted to cells, where each cell represents 32 bytes.
To convert stack accesses from byte addressing (emitted by LLVM) to cell addressing, we implemented the EraVMBytesToCells
pass in LLVM. This pass detects stack accesses and converts them to cell addressing by generating a right shift by 5 (or a division by 32, which was generated in earlier versions of the compiler). However, if the address comes from the context.sp
instruction, this conversion is not necessary as the address is already cell-addressed.
The issue here is that there was a lack of support for pseudo select instructions, which resulted in the generation of the following code where r3
and r2
are not cell-addressed:
add stack[r3], r0, r1
add.ne stack[r2], r0, r1
To address this issue, we have implemented support for pseudo select instructions that involve stack accesses. Additionally, we have marked the output register with IsEarlyClobber
flag. This flag prevents the register allocator from assigning the same physical register to both the output register and the stack address register, ensuring proper expansion. As a result of these modifications, the following instructions are now being generated:
shr.s 5, r2, r2
shr.s 5, r3, r3
add stack[r3], r0, r1
add.ne stack[r2], r0, r1
Since we deal with a backend optimization bug, it’s hard to lift it to the language semantic and describe precisely which pieces of Vyper, Solidity and Yul are affected. To determine if a contract is affected by this bug, you will need to generate assembly file and look for the following code:
stack[rN] ; where rN is register and N can be a number from 1 to 15
If the definition of rN
doesn’t come from the context.sp
, shr.s 5
, or div.s 32
instructions, it is likely that the bug exists in the contract.
Analysis has shown that no contracts were affected by the date of publishing this advisory.
Patches
Fixed in version 1.5.0.
Workarounds
Upgrading and redeploying affected contracts is the only way.
Impact
We found a bug in EraVM LLVM back end leading to possible invalid stack access. This issue occurred because the addresses used to access the stack were not properly converted to cells, where each cell represents 32 bytes.
To convert stack accesses from byte addressing (emitted by LLVM) to cell addressing, we implemented the
EraVMBytesToCells
pass in LLVM. This pass detects stack accesses and converts them to cell addressing by generating a right shift by 5 (or a division by 32, which was generated in earlier versions of the compiler). However, if the address comes from thecontext.sp
instruction, this conversion is not necessary as the address is already cell-addressed.The issue here is that there was a lack of support for pseudo select instructions, which resulted in the generation of the following code where
r3
andr2
are not cell-addressed:To address this issue, we have implemented support for pseudo select instructions that involve stack accesses. Additionally, we have marked the output register with
IsEarlyClobber
flag. This flag prevents the register allocator from assigning the same physical register to both the output register and the stack address register, ensuring proper expansion. As a result of these modifications, the following instructions are now being generated:Since we deal with a backend optimization bug, it’s hard to lift it to the language semantic and describe precisely which pieces of Vyper, Solidity and Yul are affected. To determine if a contract is affected by this bug, you will need to generate assembly file and look for the following code:
stack[rN] ; where rN is register and N can be a number from 1 to 15
If the definition of
rN
doesn’t come from thecontext.sp
,shr.s 5
, ordiv.s 32
instructions, it is likely that the bug exists in the contract.Analysis has shown that no contracts were affected by the date of publishing this advisory.
Patches
Fixed in version 1.5.0.
Workarounds
Upgrading and redeploying affected contracts is the only way.