通过WASM从JS直接访问C结构体内存偏移出错,如何排查?
问题:WASM中访问C结构体Union字段返回无效数据
用户定义了以下C结构体与枚举:
typedef struct { ValueType type; union { bool boolean; double number; Obj* obj; } as; } Value;
typedef enum { VALUE_BOOL, VALUE_NIL, VALUE_NUMBER, VALUE_OBJ } ValueType;
通过WASM,用户在js_library.js中实现了C声明的extern void accessStruct(Value value);函数,初始实现可正确打印ValueType字段的整数值。但用户修改代码后:
function accessStruct(value) { console.log(Module.getValue(value, "i32")); const v = value + 32; console.log(Module.getValue(v, "i64")); }
用户认为ValueType占4字节(32位),当类型为VALUE_NUMBER时,通过上述代码应能读取union中的double值,但实际得到无效数据,需排查错误原因。
错误原因分析
- 混淆位与字节的概念:你把
ValueType的32位宽度直接当成了32字节的偏移量——32位等于4字节,union字段的起始偏移不可能是32字节,这是最基础的概念错误。 - 结构体内存对齐的影响:C编译器会对结构体成员做内存对齐优化。你的
Value结构体中,union里最大的成员是double(8字节)或Obj*(WASM LP64模型下为8字节),因此整个结构体的对齐单位是8字节。type字段仅占4字节,编译器会在它后面填充4字节的空白,让union字段的起始地址对齐到8字节边界。也就是说,union的起始偏移是value + 8,而非你以为的value + 4,更不是value + 32。 - 数据类型读取错误:你用
i64类型读取double值,double是64位浮点类型,和64位整数的二进制编码完全不同,强行按整数读取必然得到无效数据。
修正示例
如果要读取number字段,正确的代码应该是:
function accessStruct(value) { const type = Module.getValue(value, "i32"); console.log(type); if (type === /* VALUE_NUMBER对应的枚举数值 */) { // union起始偏移为8字节,按double类型读取 const num = Module.getValue(value + 8, "double"); console.log(num); } }
内容的提问来源于stack exchange,提问作者redixhumayun
相关产品推荐
相关产品推荐

