Wasm3与Emscripten的栈差异及数组越界行为对比
Wasm3与Emscripten数组负索引访问差异的原因
这种差异既不是Wasm3内置了特殊保护机制,也不是单纯栈处理方式不同,核心是两者对WebAssembly线性内存的越界访问处理逻辑不同,结合C语言未定义行为的特性导致:
C语言未定义行为的前提
在C标准中,数组负索引访问属于未定义行为——语言本身不规定操作结果,完全由编译器和运行时环境决定。Wasm作为编译目标,同样没有强制要求越界内存访问的统一结果,因此不同Wasm Runtime可自行实现处理逻辑。Wasm3的处理逻辑
Wasm3在内存寻址时,对负偏移访问做了特殊兜底:它会将负的内存偏移量强制修正为0,或通过截断、取模等方式让访问落在数组起始位置。这就导致ar[-1]、ar[-2]等负索引访问最终都读取到ar[0]的值;对于正索引越界(比如i=6),Wasm3也统一返回0,这是它对越界访问的标准化处理。Emscripten的处理逻辑
Emscripten编译生成的Wasm运行在标准Wasm线性内存环境中,数组ar的起始地址位于线性内存的数据区域。使用负索引时,计算出的内存地址会低于数组起始位置,而该区域恰好是Wasm栈的存储位置(Emscripten内存布局中,栈通常放在数据区下方),因此读取到的是栈上的随机临时值,也就是你看到的无规律整数。
测试代码
#include <stdio.h> int ar[]={1,2,3,4,5}; int visit(int n){ return ar[n]; } int main() { for(int i=6; i>-5;i--){ printf("Loop num: %d\n",i); int temp = visit(i); printf("Loop val: %d\n",temp); } }
测试结果对比
| Emscripten | Wasm3 |
|---|---|
| Loop num: 6 Loop val: 5 | Loop num: 6 Loop val: 0 |
| Loop num: 5 Loop val: 0 | Loop num: 5 Loop val: 0 |
| Loop num: 4 Loop val: 5 | Loop num: 4 Loop val: 5 |
| Loop num: 3 Loop val: 4 | Loop num: 3 Loop val: 4 |
| Loop num: 2 Loop val: 3 | Loop num: 2 Loop val: 3 |
| Loop num: 1 Loop val: 2 | Loop num: 1 Loop val: 2 |
| Loop num: 0 Loop val: 1 | Loop num: 0 Loop val: 1 |
| Loop num: -1 Loop val: 117894759 | Loop num: -1 Loop val: 1 |
| Loop num: -2 Loop val: 2457754 | Loop num: -2 Loop val: 1 |
| Loop num: -3 Loop val: 25634578 | Loop num: -3 Loop val: 1 |
| Loop num: -4 Loop val: 85773057694 | Loop num: -4 Loop val: 1 |
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

