Ubuntu编译的二进制在Alpine中调用duplocale()触发段错误的解决办法
问题:Ubuntu编译的二进制在Alpine中调用duplocale()触发段错误
问题重现
在Ubuntu 22.04上编译以下C代码:
#include <locale.h> #include <stdio.h> int main() { printf("1\n"); locale_t oldlocale = uselocale(NULL); printf("2\n"); locale_t duploc = duplocale(oldlocale); printf("3\n"); return 0; }
Ubuntu上运行正常:
$ gcc -g c.c && ./a.out 1 2 3
但将二进制复制到Alpine容器中运行时,调用duplocale()触发段错误:
# ./a.out 1 2 Segmentation fault (core dumped)
环境说明
已在Alpine容器中安装libc6-compat等兼容组件,且该代码在Alpine本地编译可正常运行,但实际场景无法采用本地编译方式。问题源于依赖的libjson-c调用duplocale()导致段错误,即使动态链接Alpine版本的json-c也无法解决。
调试信息
Alpine中的调试输出
process 340 is executing new program: /lib/ld-musl-x86_64.so.1 1 2 Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7f46aa7 in ?? () (gdb) bt #0 0x00007ffff7f46aa7 in ?? () #1 0x0000000000000001 in ?? () #2 0x00007ffff7f521cd in ?? () #3 0xffffffffffffffff in ?? () #4 0x00007ffff7fc1600 in __libc_start_init () at ldso/dynlink.c:1621 #5 0x00007ffff7f786d1 in libc_start_main_stage2 (main=0x7ffff7f52189, argc=-1, argv=0x7fffffffebb0) at src/env/__libc_start_main.c:95 #6 0x00007ffff7f520c5 in ?? () #7 0x00007fffffffebf8 in ?? () #8 0x00007ffff7f520a0 in ?? () #9 0x0000000000000001 in ?? () #10 0x00007fffffffee50 in ?? () #11 0x0000000000000000 in ?? ()
带回Ubuntu调试core文件的输出
Core was generated by `ld-linux-x86-64.so.2 --argv0 ./a.out --preload /lib/libgcompat.so.0 -- /dm/res'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x00007f1c76999aa7 in ?? () (gdb) bt #0 0x00007f1c76999aa7 in ?? () #1 0x0000000000000001 in ?? () #2 0x00007f1c769a51cd in ?? () #3 0xffffffffffffffff in ?? () #4 0x00007f1c76a0e600 in ?? () #5 0x00007ffc8621ad98 in ?? () #6 0x00007f1c769c56d1 in ?? () #7 0x0000000000000000 in ?? ()
注:二进制保留调试信息,未被剥离。
关键线索
json-c的CMakeLists.txt中提到:
# uClibc *intentionally* crashes in duplocale(), at least as of: # https://github.com/ffainelli/uClibc/blob/266bdc1/libc/misc/locale/locale.c#L1322 # So, if it looks like we're compiling for a system like that just disable # locale handling entirely.
可行解决办法
- 禁用json-c的locale支持:若能重新编译依赖的json-c,添加编译选项
-DENABLE_LOCALES=OFF,让json-c跳过locale相关逻辑,避免调用duplocale()。 - Hook替换duplocale函数:通过
LD_PRELOAD加载自定义共享库,替换duplocale的实现。示例代码:
编译为共享库:#define _GNU_SOURCE #include <locale.h> #include <dlfcn.h> locale_t duplocale(locale_t loc) { // 直接返回传入的locale,不执行复制操作(需注意线程安全) return loc; }gcc -shared -fPIC hook_duplocale.c -o libhook_duplocale.so,运行时加载:LD_PRELOAD=./libhook_duplocale.so ./your_binary - 静态链接glibc:在Ubuntu编译时添加
-static选项静态链接glibc,让二进制不依赖Alpine的musl libc,但会增大体积,且可能带来其他兼容性问题。 - 更换运行容器:若业务允许,直接使用Ubuntu容器运行,规避libc兼容问题。
内容的提问来源于stack exchange,提问作者hudac
相关产品推荐
相关产品推荐

