2021年2月5日,Nicolas Venturo 报告了一个错误,该错误允许覆盖函数将参数的数据位置从memory 更改为 calldata。
该错误是在 Solidity 0.6.9 中引入的,并引入了对所有变量(而不仅仅是外部函数的参数)使用 calldata 数据位置的功能。
我们将此错误的严重性评定为“非常低”。
哪些合约受影响?
该错误的影响是内存指针被解释为 calldata 指针,反之亦然。只有当您在继承期间更改函数的数据位置并在仅了解基合约中原始函数签名的位置执行内部调用时,才会发生这种情况。
一种情况是,您有一个基合约,在其中对同一基合约的虚拟函数执行内部调用,并且有一个派生合约覆盖基合约的函数并更改数据位置。
abstract contract I { // The base contract uses "calldata" function f(uint[] calldata x) virtual internal; } contract C is I { // The derived contract uses "memory" and the compiler // does not complain - this is the bug in the compiler. function f(uint[] memory x) override internal { // If you use `x`, it will access memory // even if `D.g` passed us a calldata pointer. // This leads to the wrong data being accessed. } } abstract contract D is I { function g(uint[] calldata x) external { // Since D only "knows" `I`, the signature of `f` // uses calldata, while the virtual lookup ends // up with `C.f`, which uses memory. This results // in the calldata pointer `x` being passed and // interpreted as a memory pointer. f(x); } } contract X is C, D { }
在上面的示例中,该错误只会出现在 X 中,它将 C 中有问题的覆盖与 D 中的虚拟函数调用结合起来。
任何涵盖受影响函数调用的测试都可能能够检测到此问题。
外部调用不受影响,并且实际上更改 external 函数的 calldata 和 memory 之间的数据位置并不是问题。这也是引入该错误的方式:编译器在继承中没有区分 calldata 和 memory,因为它对 external 函数没有影响,并且 calldata 仅允许在 external 函数内部使用。