调用LLVM IR函数返回结构体时出现bus error的原因排查
自定义语言返回结构体触发Bus Error的原因分析
问题场景
我在自定义语言中编写了如下代码:
type Struct: x: Bool Struct { x: true }
前端生成的对应LLVM IR代码:
%Struct = type { i1 } define %Struct @execute() { %1 = alloca %Struct, align 8 %Struct.x = getelementptr inbounds %Struct, ptr %1, i32 0, i32 0 store i1 true, ptr %Struct.x, align 1 %2 = load %Struct, ptr %1, align 1 ret %Struct %2 }
调用该函数时会触发63069 bus error。
但编写代码Struct { x: true }.x时,生成的LLVM IR代码可正常执行:
%Struct = type { i1 } define i1 @execute() { %1 = alloca %Struct, align 8 %Struct.x = getelementptr inbounds %Struct, ptr %1, i32 0, i32 0 store i1 true, ptr %Struct.x, align 1 %x = getelementptr inbounds %Struct, ptr %1, i32 0, i32 0 %2 = load i1, ptr %x, align 1 ret i1 %2 }
调试器显示的错误翻译为:
线程1:EXC_BAD_ACCESS(代码=2,地址=0x16f237ff7)
问题原因
核心问题出在结构体的内存对齐与返回值处理上:
- 结构体大小与对齐不匹配:
%Struct类型是仅含1字节i1的结构体,但alloca时指定了align 8,将结构体实例放在8字节对齐的地址上。直接load %Struct并返回整个结构体时,LLVM会尝试按8字节对齐要求加载数据,但实际只有1字节有效数据,剩下7字节是未初始化的栈空间,触发内存访问越界。 - 调用约定的适配问题:多数平台调用约定中,小型结构体的返回依赖寄存器,但结构体对齐要求高于实际大小时,LLVM生成的代码会错误访问超出结构体实际范围的内存,导致Bus Error。
- 正常案例对比:返回单个
i1值时,仅加载1字节数据,对齐要求与实际大小匹配,不会触发越界,因此可正常执行。
修复方案
- 调整
alloca的对齐值,匹配结构体自然对齐:将alloca %Struct, align 8改为alloca %Struct, align 1(i1的自然对齐为1字节)。 - 显式指定结构体对齐属性:比如用
%Struct = type <{ i1 }> align 8,让结构体实际大小填充到8字节,确保加载时访问的内存合法。
内容的提问来源于stack exchange,提问作者gavrilikhin.d
相关产品推荐
相关产品推荐

