SWC智能合约漏洞库

SWC-119/影子状态变量

Solidity允许在继承时对状态变量进行歧义命名。定义有变量x的合约A可以继承 同样也定义有状态变量x的合约B。这将导致两个单独版本的x,一个可以从合约A访问, 而另一个则需要从合约B访问。在更复杂的合约系统中,这种情况可能不会引起注意, 并随后导致安全问题。

当在合约和函数层级存在多个定义时,影子状态变量也可能在单个合约内发生。

CWE漏洞分类

CWE-710:未正确遵循编码规范

整改方案

仔细检查合约系统的存储变量布局,并消除任何歧义。始终检查编译器警告,因为它们 可以在单个合约中标记影子状态变量问题。

参考文献

继承的状态变量的影子应该是一个错误 影子状态变量的警告

合约示例

ShadowingInFunctions.sol

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
    }
}

ShadowingInFunctions.yaml

description: Shadowing a state variable in functions
issues:
- id: SWC-119
  count: 4
  locations:
  - bytecode_offsets: {}
    line_numbers:
      ShadowingInFunctions.sol: [7]
  - bytecode_offsets: {}
    line_numbers:
      ShadowingInFunctions.sol: [11]
  - bytecode_offsets: {}
    line_numbers:
      ShadowingInFunctions.sol: [16]
  - bytecode_offsets: {}
    line_numbers:
      ShadowingInFunctions.sol: [17]

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.yaml

description: Shadowing a state variable in a inherited contract
issues:
- id: SWC-119
  count: 1
  locations:
  - bytecode_offsets: {}
    line_numbers:
      TokenSale.sol: [14]

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
    }
}

TokenSale_fixed.yaml

description: Shadowing a state variable in a inherited contract
issues:
- id: SWC-119
  count: 0
  locations: []