Skip to content

`xor(zext(cmp), -1)` misoptimization

Moderate
hedgar2017 published GHSA-22pj-7cvw-r3gc May 13, 2024

Package

zksolc (Solidity)

Affected versions

1.2.0 - 1.4.0

Patched versions

1.4.1

Description

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.

Severity

Moderate

CVE ID

CVE-2024-34704

Weaknesses

No CWEs