在alpine linux上编程段错误。 我该如何解决?
我一直在使用C / C ++ 编写一个 webrtc数据通道库,并用C 编写了一个程序 :
- 从同一进程创建两个对等体。
- 建立它们之间的联系。
- 如果连接成功,请关闭连接。
一切都在debian docker容器上正常运行,在我的主机上openuse tumbleweed(所有x86_64和64bit),但在alpine linux容器(64bit x86_64)上,我在子进程中得到一个SEGFAULT:
上面的函数来自程序的依赖“libnice”。 它似乎是* agent == NULL,并且在调用者的作用域中无法使其为null。 我甚至插入了一个printf("Argument is %p", agent);
在函数调用之前,它打印出它的内存,我可以validation它不是null。 从反汇编中,它看起来像复制代理的内容(0x557a1d20)作为被调用者堆栈中的局部变量的行导致段错误。 即使在make clean
和重新编译之后,segfault也始终发生在此处。 激活记录失败? 堆栈腐败?
更新:我制作了一个更轻量级的容器并运行它,现在它在同一个priv_conn_keepalive_tick_unlocked
中的不同位置进行了段priv_conn_keepalive_tick_unlocked
。 似乎设置了参数(注意0x7ffff7f9ad08):
由于我认为我可能会达到libmusl的默认堆栈限制80k,我使用getrlimit(RLIMIT_STACK, &rl)
来获取堆栈大小,看起来它已经是8 MB而不是80k。 进一步增加此限制似乎没有任何区别,除非我分配超过8 MB,我的程序在Gdb 内部早期崩溃。 Gdb说它有一个未知的信号“??”; 在gdb之外,它在正常情况下崩溃,它通常在没有改变堆栈大小的情况下崩溃。
我不确定究竟是什么问题(堆栈损坏?)以及接下来要做什么来解决这个问题。
这是我的程序流程:
对于创建的每个对等体,使用fork()创建子进程 。 父子通信由ZeroMQ完成,我使用协议缓冲区将在子内部触发的任何回调(及其参数)转发到在父进程中运行的事件循环。
因此,对于上述程序,有2个子进程和1个父进程。
重现步骤:
- 源文件: https : //github.com/hamon-in/librtcdcpp/blob/alpine-test/examples/websocket_client/2in1.c
- 高山docker集装箱: https : //github.com/hamon-in/librtcdcpp/blob/alpine-test/Dockerfile.amd64
- 运行容器,二进制文件位于
/psl-librtcdcpp/examples/websocket_client/2in1
- 2in1将生成两个子进程,这两个进程都会崩溃。
在进一步调查中,崩溃是在一个指令写入与堆栈基指针稍微大的负偏移,所以它可能只是一个简单的堆栈溢出。
解决此问题的正确方法是减少过多的堆栈使用量或在pthread_create
时显式请求大堆栈,但我没有看到调用pthread_create
位置。 快速检查以validation这是问题是通过在程序的早期某处执行以下操作来覆盖新线程的默认堆栈大小:
pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 1<<20); // 1 MB pthread_setattr_default_np(&attr);
向您的CFLAGS添加-Werror=implicit-function-declaration
,您将立即得到原因。 关键线索是指针值0x557a1d20,这几乎肯定是将指针截断为32位的结果。 当您未能声明返回指针的函数并且编译器(通过可靠的向后默认值)假定它返回int而不是产生错误时,会发生这种情况,然后允许从int到指针的隐式转换,尽管C语言不允许它。