3

I'm having an issue with a smart contract I've created where variables are being affected by a function that does not access them. I am using Remix to test this.

//Solidity Version
pragma solidity ^0.4.0;

//Contract Code
contract TicTacToe{

//Struct for cell
struct Cell {
    uint row;
    uint column;
    address played;
}

//Struct for game board
struct GameBoard {
    bool gameWon;
    address _player1;
    address _player2;
    Cell[] board;
}
//These variables are being affected due to newGame();
uint private numberOfGames = 0; //I set this to private and created a getter (getGameNum()), but same occurs if public.
GameBoard[] public _games; //This is also being affected - newGame() will fill the array, even though only one item is being pushed.

//Publig getter for numberOfGames uint.
function getGameNum() public returns(uint){
    return numberOfGames;
}

//Function that creates an array. This will eventually add it to _games but until issue is resolved, I'm leaving it.
function newGame() public {
    //Create a temporary board (to be pushed later)
    GameBoard tempBoard;
    //Fill attributes of board
    tempBoard._player1 = msg.sender;
    tempBoard._player2 = msg.sender;
    tempBoard.gameWon = false;

    uint counter = 0;
    //For each row
    for (uint row = 1; row <= 3; row++) {
        //For each column
        for (uint column = 1; column <= 3; column++) {
            tempBoard.board.length++;
            tempBoard.board[counter].row = row;
            tempBoard.board[counter].column = column;
            tempBoard.board[counter].played = 0x0;
            counter++;
        }
    }
}
}

"numberOfGames" is correctly set to 0 on contract creating (you can verify this using getGameNum() ). However, when newGame() is called, the value is changed to 295530007198671819985454669347690311693110848207872. Likewise, the _games array is filled when the newGame() function is called, even when the function doesn't interact with that array.

Any reason why this would be happening?

2
  • 1
    I'm not very familiar with the intricacies of storage vs memory, or value vs reference types, but, if you declare a variable on your contract GameBoard private tempBoard;, keeping it in storage, rather than declaring one in your function GameBoard tempBoard;, it seems to solve the problem. I'm not saying this is a good solution to your problem, but consider reading into storage vs memory, and value vs reference types. Commented Apr 6, 2018 at 6:44
  • Thanks @AnAllergyToAnalogy - that simple move seems to have worked! Not ideal with how the full contract currently works, but I can re-write it to work. Thanks for the storage vs memory, value vs reference tips too, I'll take a look! Cheers
    – Micah
    Commented Apr 6, 2018 at 7:15

1 Answer 1

3

This line should give you a warning from the Solidity compiler:

GameBoard tempBoard;

The warning tells you that this implicitly uses a storage variable and encourages you to explicitly label this as such:

GameBoard storage tempBoard;

The next warning tells you that this is an uninitialized storage reference. That means it points to slot 0 in storage. Writing to it will overwrite the storage values at slot 0, etc.

E.g.

tempBoard._player1 = msg.sender;
tempBoard._player2 = msg.sender;

is just like doing:

numberOfGames = uint256(msg.sender);
_games.length = uint256(msg.sender);

This is why numberOfGames is modified and the _games array suddenly has a non-zero length.

In short, don't do this. You want to use a memory variable:

GameBoard memory tempBoard;

EDIT

Sorry, missed the bool at the beginning of the struct. So my "is just like doing" lines of code are actually slightly incorrect. But the bool and address should both be packed into the same storage slot, overwriting numberOfGames, so I believe you'll still see msg.sender in that variable (because the bool is false, so just 0).

2
  • Nice catch. Do you have any references to some (half-)official sites which explain what unitialized storage references do? I found only github.com/ethereum/solidity/issues/1789 (unsure even of its results - does it say they will produce error in future releases or not?) Commented Apr 6, 2018 at 8:26
  • I'm unclear from that issue whether this will become an error in the future or not. (I hope it does.) An uninitialized storage reference just points to slot 0. Sorry, don't have a good reference describing that.
    – user19510
    Commented Apr 6, 2018 at 8:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.