In older Solidity versions (before 0.5.0), local variables of reference types (structs, arrays, mappings) would default to pointing to storage slot 0 if not explicitly initialized. Writing to such a pointer would overwrite the variable stored at slot 0 — often the contract owner.
Slot 0 is typically where the first state variable is stored. If a function creates an uninitialized local storage struct and writes to it, that write goes to slot 0 — potentially overwriting the owner address with attacker-controlled data.
// VULNERABLE — uninitialized struct defaults to storage slot 0
contract Vulnerable {
address public owner; // slot 0
address public pendingOwner; // slot 1
struct Proposal {
address target;
uint value;
}
function propose(address _target, uint _value) public {
Proposal p; // UNINITIALIZED — p.target is slot 0 (owner)!
p.target = _target; // overwrites owner!
p.value = _value; // overwrites pendingOwner!
}
}
// SAFE — always initialize storage pointers explicitly
// Option 1: Use memory for local variables
function propose(address _target, uint _value) public {
Proposal memory p; // stored in memory, not storage
p.target = _target;
p.value = _value;
proposals.push(p);
}
// Option 2: Solidity 0.5.0+ now requires explicit storage/memory declaration
// and warns about uninitialized storage pointers
memory or storage keywords and warns about uninitialized pointers.memory unless you specifically need to modify storage.