Solidity, in a deliberate way, does not support memory pointers “a la C”, neither it has any pointer arithmetic in place. This means that incrementing or decrementing a pointer variable is not a meaningful operation. You can do something similar in assembly, but you must manage the whole thing at the lowest level possible and without thinking to be able to sync the solidity variables and the assembly variables for any future version of Ethereum protocol.
First of all you are using a very old version of solidity, that behavior is no longer allowed since solidity 0.5.0 :
Uninitialized storage variables are now disallowed.
In your code Donation donation;
is an uninitalized storage variable, now it would be more something like Donation storage donation;
.
Anyway, a storage variable is quite simple : it's value is actually the storage slot to which it is refering to : from 0 to 2^256 in a format similar to uint256
, the way it is used internally by the compiler is only a matter of how to interpret what it is pointing to.
The real problem is that the default value is the zero value.. so an uninitialized storage variable is essentially pointing to storage slot 0 by default and given your structure layout, donation.timestamp is written to slot 0 while donation.etherAmount is written to slot 1.
This could either overwrite existing data (like you did to both donations
and owner
) with invalid ones or worse, provide a way for attackers to overwrite your owner slot with the address / value of their choice, simply because you relied on an undefined behavior : using an uninitialized storage variable.
So don't do that, and use a more recent / more secure version of solidity such as 0.5.0+ that won't allow you to write such code.
I hope that answers your question.
Best Answer
There isn't much to explain. An
uint256[] public array
in storage is organized as follow:Each
| X |
represents a 32 bytes slot.The problem was that old solidity version allowed an underflow when modifying the array's length.
For example
array
has 2 elements, so after callingpopLength()
two times length will be zero.If called a third time it will be
115792089237316195423570985008687907853269984665640564039457584007913129639935
which is2**256 - 1
.So with
array[X]
you could write almost anywhere in the contract storage.