Impact
The problem occurred during instruction selection in the DAGCombine
phase while visiting the XOR operation. The issue arises when attempting to fold the expression !(x cc y)
into (x !cc y)
. To perform this transformation, the second operand of XOR should be a constant representing the true value. However, it was incorrectly assumed that -1 represents the true value, when in fact, 1 is the correct representation, so this transformation for this case should be skipped.
Before doing wrong optimization, Selection DAG nodes look like this:
t16: i256 = setcc t2, Constant:i256<0>, seteq:ch
t10: i256 = xor t16, Constant:i256<-1>
After performing wrong optimization in the DAGCombine
, it is folded into:
t18: i256 = setcc t2, Constant:i256<0>, setne:ch
As the result, we are generating following assembly and the output can be 1
or 0
:
sub! r1, r0, r1
add 0, r0, r1
add.ne 1, r0, r1
Instead of where the output can be 1 ^ -1
or 0 ^ -1
:
sub! r1, r0, r1
add 0, r0, r1
add.eq 1, r0, r1
sub.s 1, r0, r2
xor r1, r2, r1
To fix this issue, we needed to set that EraVM represents true and false values with 1 and 0, instead of using default LLVM behaviour where only bit 0 counts, the rest can hold garbage.
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 an optimized LLVM IR file and look for the following pattern:
%cmp = icmp cond i256 %a, %b <- Where cond can be eq, ne, etc.
%zext = zext i1 %cmp to i256
%not = xor i256 %zext, -1
If this pattern is found xor(zext(cmp))
, 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.4.1.
Workarounds
Upgrading and redeploying affected contracts is the only way.
Impact
The problem occurred during instruction selection in the
DAGCombine
phase while visiting the XOR operation. The issue arises when attempting to fold the expression!(x cc y)
into(x !cc y)
. To perform this transformation, the second operand of XOR should be a constant representing the true value. However, it was incorrectly assumed that -1 represents the true value, when in fact, 1 is the correct representation, so this transformation for this case should be skipped.Before doing wrong optimization, Selection DAG nodes look like this:
After performing wrong optimization in the
DAGCombine
, it is folded into:As the result, we are generating following assembly and the output can be
1
or0
:Instead of where the output can be
1 ^ -1
or0 ^ -1
:To fix this issue, we needed to set that EraVM represents true and false values with 1 and 0, instead of using default LLVM behaviour where only bit 0 counts, the rest can hold garbage.
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 an optimized LLVM IR file and look for the following pattern:
If this pattern is found
xor(zext(cmp))
, 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.4.1.
Workarounds
Upgrading and redeploying affected contracts is the only way.