PPL语言编译-1触发SEGV错误:LLVM IR或运行时库问题排查
问题描述
我正在开发一款名为PPL的编程语言,默认支持任意宽度的整数字面量,通过指向GMP库mpz_class的指针实现。但编译表达式-1时,地址 sanitizer报告SEGV错误:
==92833==ERROR: AddressSanitizer: SEGV on unknown address 0x000100000006 (pc 0x000105564bc4 bp 0x000105019f14 sp 0x00016ce45e50 T0) ==92833==The signal is caused by a UNKNOWN memory access. #0 0x105564bc4 in __gmpz_neg+0x14 (libgmp.10.dylib:arm64+0x14bc4) (BuildId: efc29ca33b2a3664976db890d76d3d0832000000200000000100000000000c00)
相关运行时代码
// Temporary solution for not leaking memory, // as I haven't implemented memory management yet std::unordered_set<mpz_class> values; // PPL's big integer type using Integer = const mpz_class *; extern "C" { // Used to create integer from literal Integer _IntegerConstructorFromCString(const char *string) { assert(string); // Inserts value and returns pointer to it return &*values.emplace(mpz_class(string)).first; } /// - <:Integer> -> Integer Integer _MinusInteger(Integer value) { // I checked in debugger, here value is 0x000100000006, // which isn't a pointer I returned from _IntegerConstructorFromCString assert(value); // Inserts value and returns pointer to it return &*values.emplace(-*value).first; } } // extern "C"
编译器生成的LLVM IR
@.str = private unnamed_addr constant [2 x i8] c"1\00", align 1 // Code for "-1" top level expression define void @_top_level_code() { // Create integer from "1" %1 = call ptr @_IntegerConstructorFromCString(ptr getelementptr inbounds ([2 x i8], ptr @.str, i32 0, i32 0)) // Get -1 %2 = call ptr @"- <:Integer>"(ptr %1) ret void } // Function from runtime declare ptr @_MinusInteger(ptr %0) // PPL's operator that hides runtime function invokation define ptr @"- <:Integer>"(ptr %a) { %1 = load ptr, ptr %a, align 8 %2 = call ptr @_MinusInteger(ptr %1) ret ptr %2 }
疑问:我的代码哪里存在问题?是否出在未使用alloca访问函数参数,或是某处未正确解引用指针?(因均为不透明类型,难以判断)
问题分析与解决
问题根源在LLVM IR的运算符实现函数"- <:Integer>"中,它执行了多余的指针加载操作,混淆了指针本身和指向指针的指针:
调用链路中的错误逻辑:
_top_level_code里,%1是_IntegerConstructorFromCString返回的Integer(即const mpz_class*),本身就是指向GMP整数对象的有效指针- 该指针被传给
"- <:Integer>"的参数%a,但函数里却做了load ptr, ptr %a操作——这相当于把%a当成指针的指针来读取,取出的内容是无效的垃圾地址(也就是调试中看到的0x000100000006) - 把这个垃圾地址传给
_MinusInteger后,解引用*value必然触发段错误
修复方案:
删除多余的load操作,直接将参数%a传给_MinusInteger。修改后的LLVM IR运算符函数如下:define ptr @"- <:Integer>"(ptr %a) { %1 = call ptr @_MinusInteger(ptr %a) ret ptr %1 }额外说明:
运行时代码本身没有问题,Integer类型定义为const mpz_class*合理,_IntegerConstructorFromCString和_MinusInteger的实现逻辑正确,错误完全来自LLVM IR层面的指针处理失误。
内容的提问来源于stack exchange,提问作者gavrilikhin.d
相关产品推荐
相关产品推荐

