https://github.com/MikePopoloski/slang/issues/497
最近我一直在用一个叫slang的库处理一些SystemVerilog代码,这几天发现我的工具出了点问题,所以想连着slang库调试一下,没想到链接了Debug版的slang库之后,我的工具就坏了,一跑就出内存错误。用gdb查是发生在一个析构函数上,valgrind提示代码中使用了未初始化的内存,但从代码上看是经过了初始化的。
后来发现slang支持使用sanitizer编译,就把ASAN打开,ASAN只是提示了free()释放了未分配的内存,也没给出有用的信息。
后来我修改代码,在出现问题的类的构造和析构函数都打出this指针,以便后续知道是哪个对象的析构出了问题,而且也便于以后加watchpoint,这时候才发现,析构函数析构了之前没构造的对象。但是在gdb里面,我看到应该析构的几个对象的地址和构造时打出来的this指针是一样的,看了析构函数的反汇编又不一致。这时我想到这个issue里面slang作者说的ABI不匹配的问题。我搜了下这个工程的CMake文件,发现在编译Debug版的时候编译选项加了 ``-DDEBUG``, 在代码里面这个选项使某些类中的 ``#ifdef DEBUG`` 条件编译增加了类成员,使得类大小增大和成员偏移地址的改变。而我的程序使用了原有的头文件,和编译好的slang的库是不匹配的,自然就出问题了。加上 ``-DDEBUG`` 编译之后,我的程序就能用了。
这就是为什么很多软件构建时要使用系统库的时候,一般都要调用 pkg-config 或者某些库自带的 python-config, llvm-config 等配置工具来获取编译选项,这不只是要找头文件路径的问题,其他编译选项也很重要。
另外一种做法是在配置之后生成一个头文件,让所有用到可配置的宏的源码文件都包含它,我的系统中安装的很多库也用这种做法。
最近我一直在用一个叫slang的库处理一些SystemVerilog代码,这几天发现我的工具出了点问题,所以想连着slang库调试一下,没想到链接了Debug版的slang库之后,我的工具就坏了,一跑就出内存错误。用gdb查是发生在一个析构函数上,valgrind提示代码中使用了未初始化的内存,但从代码上看是经过了初始化的。
后来发现slang支持使用sanitizer编译,就把ASAN打开,ASAN只是提示了free()释放了未分配的内存,也没给出有用的信息。
后来我修改代码,在出现问题的类的构造和析构函数都打出this指针,以便后续知道是哪个对象的析构出了问题,而且也便于以后加watchpoint,这时候才发现,析构函数析构了之前没构造的对象。但是在gdb里面,我看到应该析构的几个对象的地址和构造时打出来的this指针是一样的,看了析构函数的反汇编又不一致。这时我想到这个issue里面slang作者说的ABI不匹配的问题。我搜了下这个工程的CMake文件,发现在编译Debug版的时候编译选项加了 ``-DDEBUG``, 在代码里面这个选项使某些类中的 ``#ifdef DEBUG`` 条件编译增加了类成员,使得类大小增大和成员偏移地址的改变。而我的程序使用了原有的头文件,和编译好的slang的库是不匹配的,自然就出问题了。加上 ``-DDEBUG`` 编译之后,我的程序就能用了。
这就是为什么很多软件构建时要使用系统库的时候,一般都要调用 pkg-config 或者某些库自带的 python-config, llvm-config 等配置工具来获取编译选项,这不只是要找头文件路径的问题,其他编译选项也很重要。
另外一种做法是在配置之后生成一个头文件,让所有用到可配置的宏的源码文件都包含它,我的系统中安装的很多库也用这种做法。