2022年9月5日,Solidity团队通过 差分Fuzzing 发现了 Solidity’s Yul 优化器 的Bug。

该Bug影响范围在 0.8.13 ≤ version < 0.8.17, 严重性为 中难度-高危害。

简述

有solidity代码如下:

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 {
		if (a) return;
		assembly { return(0,0) }
	}
}

在预期情况下,调用f(false)将使x变量值为1。

但有Bug的实际结果为0.

可见,该Bug使EVM 回退了 x = 1; 的Storage写入操作。

触发条件

  1. 自定义的汇编代码中包含 return(0,0) 或者 stop()
  2. 这段汇编代码中不包含变量读写。(do not interact with any surrounding Solidity variables)

Untitled

  1. 至少有两个控制流: 其一为汇编return(0,0),其二为自定义函数function调用前的一个Storage的额外写操作。( 例如举例中。有两个控制流,a == false 时,走汇编return(0,0)的分支。a == True时 走 x = 2 即 写入一个 g函数调用之前曾写入( x = 1; )的Storage。

当IR优化器识别到了类似上图的控制流。会认为 x = 1 是废话,于是将其”优化掉”。

技术细节

此处的“优化掉”,指Yul优化器的Unused Store Eliminator步骤。Link

该步骤一般记作 S, 用作删除【冗余】的Storage写操作。

一个Storage写操作如果符合以下任意条件,则判定为【冗余】

  1. 其后有同一个Storage的写操作,而且在此之前没有对旧值的读。
{
    x = 1; // 这句就是冗余,会被优化掉。 
    x = 2;
}
  1. 其后必revert。