遍历所有的节点处理变量读写关系的示例
这个框架与11节中slither检测器之三——批量函数调用检测的框架基本相同。
常用的框架结构。遍历每个合约,遍历合约的每个函数对象,从每个函数对象的入口点开始进入检测函数。检测函数的架构通常如下,通常使用递归
的方式调用:
def _detect_xxx(
node: Node,
explored: Set[Node],
written: Dict[Variable, Node],
ret: List[Tuple[Variable, Node, Node]],
):
node: 当前正在检测的节点。
explored: 已经遍历过的节点,通常为Set类型或者List类型。
written: 不一定存在这个参数,可能用来存储中间变量。
ret: 返回结果。
检测函数实现中,常用的框架是:
# 如果这个节点处理过,就直接跳过
if node in explored:
return
# 处理当前节点
explored.add(node)
………………………………………………………………
这里对当前节点的不同的检测逻辑
………………………………………………………………
# 递归处理子节点
for son in node.sons:
_detect_xxxx(son, explored, dict(written), ret)
什么为变量重写呢?指给一个变量刚刚被赋过值,再没有被使用的情况下,又再次被赋值。
变量覆盖可能会带来一些风险和问题:
如下面的代码中,a=b,a=c两行的代码处,变量a首先被赋值成b,再a没有被使用的情况下,又再次被赋值成c,明显a被进行了非必要的赋值
,这种毫无意义代码会加大代码执行的gas费
,在极端情况下这种代码可能还意味着程序员没有理清代码逻辑,可能对错误的变量进行了错误的赋值。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Buggy{
uint256 a;
function my_func() public {
// ...
uint b =2;
uint c = 3;
a = b;
a = c;
// ..
}
}
那么,怎么才能检测出这种变量被重写的问题呢?slither中内置了名为write-after-write
的检测器,使用slither xxx.sol —detect write-after-write
可以对xxx.sol文件进行该类变量重写的检测,使用示例如下:
首先使用第1部分介绍的框架遍历所有的Node节点。
遍历Node第1部分的框架的逻辑为:
_detect_write_after_write
方法。主要在_detect_write_after_write
函数中实现。
先看一个辅助函数_remove_states,函数攻击是将written中,取消所有的**状态变量**
的所有写属性的记录。
def _remove_states(written: Dict[Variable, Node]):
for key in list(written.keys()):
if isinstance(key, StateVariable):
del written[key]
_detect_write_after_write
的主要功能是遍历所有的Node节点,对每个Node递归调用_detect_write_after_write
,同时对遍历到的ir,调用_handle_ir
处理。
在该函数中使用字典变量written 来记录需要被检测的变量。...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!