文章前言
返回值调用验证问题多出现在和转币相关的智能合约中,故又称作静默失败发送或未经检查发送,在Solidity中存在transfer()、send()、call.value()等转币方法,都可以用于向某一地址发送Ether,其区别在于:
- transfer发送失败时会throw,并且进行状态回滚,只会传递2300gas供调用,防止重入攻击
- send发送失败时会返回false,只会传递2300gas供调用,防止重入攻击
- call.value发送失败时会返回false,传递所有可用gas进行调用(可通过传入gas_value参数进行限制),不能有效防止重入攻击。
演示示例
示例代码如下:
function withdraw(uint256 _amount) public {
require(balances[msg.sender] >= _amount);
balances[msg.sender] -= _amount;
etherLeft -= _amount;
msg.sender.send(_amount);
}
上面代码忘记检查send函数的返回值,如果Ether发送失败,由于没有自定义回滚机制,etherLeft将出现异常,从而导致msg.sender用户的币白白转丢,但是接受者的账户却没有收到任何代币。
防御措施
使用send和call.value进行转账操作时对返回值进行检查。