【问题标题】:Shared library causing segfault共享库导致段错误
【发布时间】:2024-01-22 21:50:01
【问题描述】:

我创建了一个小型共享库,它重载了 malloc 和 co。它编译成功,但是当我尝试用它执行其他程序时,它会导致段错误。

到目前为止,我为解决该问题所采取的步骤:

1. Make sure the .so is executable.
2. Tried debugging using Valgrind and gdb.(see GDB output below)
3. Looked at other related questions on SO and tried to adopt the suggestions given. 

使用

执行 Test.cpp
 LD_PRELOAD=/home/absolute/path/mylib.so ./a.out 

导致段错误。

Test.cpp

#include <stdlib.h>
#include <iostream>

int main () {

  size_t size = sizeof(int);
  void* ptr = malloc(size);
  std::cout<<"Called malloc() " << ptr << std::endl;
  free(ptr);
return 0;

}

这是我的一些共享库代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <iostream>

#include "runtime/Firstfit_heap.h"
#include "system/Auslagern.h"
#include "system/VirtualMem.h"

extern "C" {
    void* malloc(size_t size) noexcept;
 }

 Auslagern swap(4,6);
 VirtualMem mem(4, 6, swap, true);
 Firstfit_heap heap(mem);

 void* malloc(size_t size) noexcept{

        void* handle = (void*) -1l;
        auto fptr = (void* (*)(size_t))dlsym(handle, "malloc");
        if (fptr == NULL) {
            return NULL;
        }
        char* foo = "malloc\n";
        write(2, foo, 7);
     // I THINK THE ERROR IS IN THE NEXT LINE BECAUSE "malloc" is printed to the console before the segfault(core dump)
        void* ptr  = fptr(size);
        std::cout<<"malloc"<<std::endl;
        return ptr;
      }

我的所有 .cpp 文件的编译和链接标志(在 makefile 中):

  CXXFLAGS = -fPIC -g -Wall -std=c++1z
  LDFLAGS = -shared
  LIBS = $(XLIBS) $(PTHREADLIBS) -lboost_program_options -lrt -lc -ldl

Gdb 输出:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000002 in ?? ()

Valgrind 输出:

 ==19131== Jump to the invalid address stated on the next line
 ==19131==    at 0x2: ???
 ==19131==    by 0xFFF000082: ???
 ==19131==    by 0xFFF000092: ???
 ==19131==  Address 0x2 is not stack'd, malloc'd or (recently) free'd
 ==19131== 
 ==19131== 
  ==19131== Process terminating with default action of signal 11 (SIGSEGV)
 ==19131==  Bad permissions for mapped region at address 0x2
 ==19131==    at 0x2: ???
 ==19131==    by 0xFFF000082: ???
 ==19131==    by 0xFFF000092: ???

因为没有用于 mylib.so 的代码,所以我无法判断哪条指令试图寻址 0x2,并且无法想到任何可以帮助我更接近解决方案的方法。 任何指向我写作方向的帮助都会非常有用。

TIA。

【问题讨论】:

    标签: c++ segmentation-fault shared-libraries


    【解决方案1】:

    这段代码:

    void* malloc(size_t size) noexcept {
        auto fptr = (void* (*)(size_t))dlsym(handle, "malloc");
    

    保证在任何 dlsym 实现本身 mallocs 内存上永远重复并耗尽堆栈。

    这段代码:

        void* ptr  = fptr(size);
        std::cout<<"malloc"<<std::endl;
    

    保证对任何本身具有mallocs 内存的std::cout 实现执行相同的操作。

    在 Linux 上,您的程序崩溃不是因为上述两个原因,而是因为在 libstdc++.so.6 本身被初始化之前调用了 std::cout

    TL;DR: malloc 在过程的早期就被调用了,你需要非常小心你可以从它的实现中调用哪些函数。最好只使用系统调用。

    附: 您应该学习使用调试器(例如 GDB)。 Valgrind 不是解决这类问题的最佳工具。

    Gdb 输出:

    Program received signal SIGSEGV, Segmentation fault. 0x0000000000000002 in ?? ()

    这告诉您程序跳转到地址0x2 并崩溃(该地址没有可执行代码)。

    您的第一个问题应该是“我是怎么到这里的?”,最有可能回答的命令是wherebacktrace

    附言 这段代码:

    char* foo = "malloc\n";
    

    甚至不应该使用任何合理的 C++ 编译器进行编译。

    【讨论】:

    • 感谢您的评论。这是 gdb 回溯; (gdb) 回溯 #0 0x0000000000000002 在 ?? () #1 0x00007ffffffffe18d 在?? () #2 0x00007ffffffffe1c2 在??我还不太明白这个问题:我已经删除了任何 std::cout 行,但最终还是出现了段错误。回溯对我来说并不是真的有用,因为我不知道错误发生在哪里。你能指出我正确的方向吗?附言我在 Ubuntu 16.04 上使用 g++ 7.2.0 版。
    • 当我用 nm 查看共享库的对象符号时,我注意到所有 libc 函数,例如 mmap、fsnyc,都是未定义的。这是问题的一部分吗?如何确保 libc 已初始化?
    • @InfoGirl 当我删除对std::cout 的调用时,我无法再重现您的崩溃。如果您将测试程序直接链接到mylib.so(而不是LD_PRELOADing),您可能可以获得更好的堆栈跟踪。
    • 我意识到问题出在 FIrstfit_heap 上,当我将其注释掉 + std::cout 时它可以工作。该类的构造函数是:Firstfit_heap(Memory& mem):Heap(mem) { ...} 但我需要该类使用我自己的分配函数。什么会导致类的这种行为?
    • @InfoGirl 你可能应该问一个单独的问题,并显示相关代码。