前言

可以看到

Args

args 也叫 calldata,是一段只读的可寻址的保存函数调用参数的空间,与栈不同的地方的是,如果要使用 calldata 里面的数据,必须手动指定偏移量和读取的字节数。

Memory

Memory 一个简单的字节数组,主要是在运行期间存储数据,将参数传递给内部函数。基于 32byte 进行寻址和扩展。

优化后:

pragma solidity ^0.4.11;

contract C {

uint64 a = 12;

uint64 c = 12;

uint64 b = 12;

uint64 d = 12;

function m() view public returns(uint64,uint64,uint64,uint64){

return (a,b,c,d);

}

}

深入理解 EVM 存储机制及安全问题

结构体

对于大小在 32 字节以内的结构体同样也是顺序存储,例如结构体变量索引定义在位置 0,结构体内部有两个成员,则这两个成员的依序为 0 和 1。

pragma solidity ^0.4.11;

contract C {

struct Info {

uint256 a ;

uint256 b ;

}

function m()  external returns(uint256,uint256){

Info storage info;

info.a = 12 ;

info.b = 24 ;

return(info.a,info.b);

}

}

深入理解 EVM 存储机制及安全问题

映射(map)

map 存储位置是通过 keccak256 (bytes32(key) + bytes32(position) ) 计算得到的,position 表示 key 对应 storage 类型变量存储的位置。

pragma solidity ^0.4.11;

contract Test {

mapping(uint256 => uint256) knownsec;

function go() public {

knownsec[0x60] = 0x40;

}

}

深入理解 EVM 存储机制及安全问题

数组

定长数组

同上,只要在 32 字节以内也是顺序存储,不过在编译时编译器会进行边界检查防止越界。

pragma solidity ^0.4.11;

contract C {

uint256[3] a = [12,24,48] ;

function m() public view returns(uint256,uint256,uint256){

return (a[0],a[1],a[2]);

}

}

深入理解 EVM 存储机制及安全问题

可变长度数组

由于可变长度数组长度不定,一般在编译可变长度数组时会提前预留存储空间,所以就会使用状态变量的位置存储可变长度数组的长度。

而具体的数据地址会通过计算 keccak256 (bytes32(position)) 算得数组首地址,再加数组长度偏移量获得具体的元素。

pragma solidity ^0.4.11;

contract C {

uint256[] a = [12,24,48] ;

function m() public view returns(uint256,uint256,uint256){

return (a[0],a[1],a[2]);

}

}

深入理解 EVM 存储机制及安全问题

字节数组和字符串

如果长度小于等于31字节 :

1.对于定长字节数组则是同定长数组一样;

2.对于可变字节数组和字符串,会在存储值位置补0一直到32字节,并用补0的最后一个字节存储字符串的编码长度。

pragma solidity ^0.4.4;

contract A{

string public name0 = “knownsec”;

bytes8 public name=0x6b6e6f776e736563;

bytes public g ;

function test() public {

g.push(0xAA);

g.push(0xBB);

g.push(0xCC);

}

function go() public view returns(bytes){

return g;

}

}

深入理解 EVM 存储机制及安全问题

当节数组和字符串长度大于31字节时

1.变量位置存储编码长度,并且编码长度公式更换为编码长度 = 字符数 * 2 + 1

2.真实存储值第一个位置通过公式 keccak256(bytes32(position)) 获取,剩余值在获取到的位置顺序存储,同样在最后存储位置补0到32字节。

string public name = “knownsecooooooooooooooooooooooooo”;

深入理解 EVM 存储机制及安全问题

安全问题

前面已经讲到

传参后:

深入理解 EVM 存储机制及安全问题

可以看到已经成功更改了地址。

总结

可以看到

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注