SWC-109/未初始化的存储指针
未初始化的局部存储变量可能指向合约中期望之外的存储位置,这可能导致有意或无意的漏洞。
CWE漏洞分类
整改方案
首先检查合约是否需要使用存储对象,因为在许多情况下实际上并非如此。如果局部变量已足够, 请使用memory属性显式标记变量的存储位置。如果需要存储变量,则在声明时对其进行初始化, 并另外指定存储位置storage。
注意:从0.5.0版及更高版本开始,此问题已得到系统解决,因为带有未初始化存储指针的合约 不能成功编译。
参考文献
合约示例
crypto_roulette.sol
/*
* @source: https://github.com/thec00n/smart-contract-honeypots/blob/master/CryptoRoulette.sol
*/
pragma solidity ^0.4.19;
// CryptoRoulette
//
// Guess the number secretly stored in the blockchain and win the whole contract balance!
// A new number is randomly chosen after each try.
//
// To play, call the play() method with the guessed number (1-20). Bet price: 0.1 ether
contract CryptoRoulette {
uint256 private secretNumber;
uint256 public lastPlayed;
uint256 public betPrice = 0.1 ether;
address public ownerAddr;
struct Game {
address player;
uint256 number;
}
Game[] public gamesPlayed;
function CryptoRoulette() public {
ownerAddr = msg.sender;
shuffle();
}
function shuffle() internal {
// randomly set secretNumber with a value between 1 and 20
secretNumber = uint8(sha3(now, block.blockhash(block.number-1))) % 20 + 1;
}
function play(uint256 number) payable public {
require(msg.value >= betPrice && number <= 10);
Game game;
game.player = msg.sender;
game.number = number;
gamesPlayed.push(game);
if (number == secretNumber) {
// win!
msg.sender.transfer(this.balance);
}
shuffle();
lastPlayed = now;
}
function kill() public {
if (msg.sender == ownerAddr && now > lastPlayed + 1 days) {
suicide(msg.sender);
}
}
function() public payable { }
}
crypto_roulette.yaml
description: Test for uninitialised storage variable
issues:
- id: SWC-109
count: 1
locations:
- bytecode_offsets: {}
line_numbers:
crypto_roulette.sol: [39]
crypto_roulette_fixed.sol
/*
* @source: https://github.com/thec00n/smart-contract-honeypots/blob/master/CryptoRoulette.sol
*/
pragma solidity ^0.4.19;
// CryptoRoulette
//
// Guess the number secretly stored in the blockchain and win the whole contract balance!
// A new number is randomly chosen after each try.
//
// To play, call the play() method with the guessed number (1-20). Bet price: 0.1 ether
contract CryptoRoulette {
uint256 private secretNumber;
uint256 public lastPlayed;
uint256 public betPrice = 0.1 ether;
address public ownerAddr;
struct Game {
address player;
uint256 number;
}
Game[] public gamesPlayed;
function CryptoRoulette() public {
ownerAddr = msg.sender;
shuffle();
}
function shuffle() internal {
// randomly set secretNumber with a value between 1 and 20
secretNumber = uint8(sha3(now, block.blockhash(block.number-1))) % 20 + 1;
}
function play(uint256 number) payable public {
require(msg.value >= betPrice && number <= 10);
Game memory game;
game.player = msg.sender;
game.number = number;
gamesPlayed.push(game);
if (number == secretNumber) {
// win!
msg.sender.transfer(this.balance);
}
shuffle();
lastPlayed = now;
}
function kill() public {
if (msg.sender == ownerAddr && now > lastPlayed + 1 days) {
suicide(msg.sender);
}
}
function() public payable { }
}
crypto_roulette_fixed.yaml
description: Test for uninitialised storage variable
issues:
- id: SWC-109
count: 0
locations: []