Title
Shadowing State Variables
Relationships
CWE-710: Improper Adherence to Coding Standards
Description
Solidity allows for ambiguous naming of state variables when inheritance is used. Contract A
with a variable x
could inherit contract B
that also has a state variable x
defined. This would result in two separate versions of x
, one of them being accessed from contract A
and the other one from contract B
. In more complex contract systems this condition could go unnoticed and subsequently lead to security issues.
Shadowing state variables can also occur within a single contract when there are multiple definitions on the contract and function level.
Remediation
Review storage variable layouts for your contract systems carefully and remove any ambiguities. Always check for compiler warnings as they can flag the issue within a single contract.
References
- Issue on Solidity's Github - Shadowing of inherited state variables should be an error (override keyword)
- Issue on Solidity's Github - Warn about shadowing state variables
Samples
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
}
}
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_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
}
}