文章前言
Solidity允许在继承时对状态变量进行歧义命名,定义有变量x的合约A可以继承同样含有状态变量x的合约B,这将导致两个单独版本的x,一个可以从合约A访问, 而另一个则需要从合约B访问,在更复杂的合约系统中,这种情况可能不会引起注意, 并随后导致严重的安全问题。
漏洞示例
下面进行一个简单的测试,首先我们来看局部变量与全局变量之间的关系:
pragma solidity 0.4.24;contract ShadowingInFunctions {uint n = 2;uint x = 3;function test1() constant returns (uint n) {return n; // Will return 0}function test2() constant returns (uint n) {n = 1;return n; // Will return 1}function test3() constant returns (uint x) {uint n = 4;return n+x; // Will return 4}}
首先部署合约:
调用test1函数来测试当同名的全局变量与局部变量同时存在且局部变量未初始化时局部变量作何回应——0:

调用test2函数来测试当同名的全局变量与局部变量同时存在且局部变量初始化时局部变量作何回应—局部变量:

调用test3函数来测试当同名的全局变量与局部变量同时存在且局部变量已初始化并与另一个全局变量进行数值运算时作何回应——当前局部变量与所需的全局变量进行数值运算:

下面我们再来看一个示例,合约TokenSale.sol代码如下:
pragma solidity 0.4.24;contract Tokensale {uint hardcap = 10000 ether;function Tokensale() {}function fetchCap() public constant returns(uint) {return hardcap;}}contract Presale is Tokensale {uint hardcap = 1000 ether;function Presale() Tokensale() {}}
部署以上两个合约:

之后调用Tokensale合约的fetchCap函数来查看hardcap的数值—10000000000000000000000=10000ether:

之后调用继承自TokenSale合约的Presale合约中 fetchCap函数来查看继承合约中的hardcap的数值是多少:
10000000000000000000000=10000ether:

由此可见Presale合约中的同名变量hardcap并未起到预期的作用,在调用fetchCap时使用的变量hardcap依旧源自fetchCap函数所处的合约上下文环境
防御措施
检查合约系统的存储变量布局,并消除歧义,下面是修改上面示例二中修改后的合约代码:
TokenSale_fixed.sol
pragma solidity 0.4.25;//We fix the problem by eliminating the declaration which overrides the prefered hardcap.contract Tokensale {uint public hardcap = 10000 ether;function Tokensale() {}function fetchCap() public constant returns(uint) {return hardcap;}}contract Presale is Tokensale {//uint hardcap = 1000 ether;//If the hardcap variables were both needed we would have to rename one to fix this.function Presale() Tokensale() {hardcap = 1000 ether; //We set the hardcap from the constructor for the Tokensale to be 1000 instead of 10000}}
首先部署上述两个合约:
之后调用fetchCap进行测试,效果如下所示:
文末小结
在复杂性合约逻辑设计过程中,对于变量名称的定义建议具备\\”专名专用\\”的特性,同时对全局变量与局部变量进行合理使用,同时需要注意变量的初始化。
原创文章,作者:七芒星实验室,如若转载,请注明出处:https://www.sudun.com/ask/34354.html