aarch64平台C++调用libmongoose C共享库值传参段错误咨询
aarch64架构下C++调用C共享库值传参触发段错误排查
故障背景
- 运行环境:aarch64(arm64)架构
- 业务构成:基于C++11开发的应用,依赖C语言实现的共享库
libmongoose - C++侧调用代码如下:
void some_class::some_function_in_CPP_application() { // 局部mg_connect_opts对象 struct mg_connect_opts opts; // 给opts成员赋值 opts.error_string = &err_str; opts.user_data = this; // 按值传递opts参数 struct mg_connection *nc = mg_connect_ws_opt(mgr, ev_handler, opts, uri, nullptr, nullptr); }
- C共享库侧
mg_connect_ws_opt函数签名如下:
struct mg_connection *mg_connect_ws_opt( struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_connect_opts opts, const char *url, const char *protocol, const char *extra_headers);
异常现象
按照函数签名定义,opts为值传递参数,理论上参数拷贝过程不会触发内存访问问题,但分析core dump调用栈时出现异常:
- C++代码侧,调用
mg_connect_ws_opt前,gdb打印opts对象内容完全正常:
(gdb) print opts $5 = { user_data = 0x7fe8e70f40, flags = 0, error_string = 0x5569ba17b8 <err_str>, iface = 0x0, nameserver = 0x0, ssl_cert = 0x0, ssl_key = 0x0, ssl_ca_cert = 0x0, ssl_cipher_suites = 0x556965e850 "PSKADJSAFSAK", ssl_server_name = 0x0, ssl_psk_identity = 0x55a07451a0 "21321521321321312312321", ssl_psk_key = 0x55a0742e20 "43124321rsafsa32131zcxbsa" }
- 切换到调用栈下一帧(C库内
mg_connect_ws_opt函数帧)时,opts参数无法访问:
(gdb) frame 4 #4 0x0000007fb59fdfd4 in mg_connect_ws_opt (mgr=<optimized out>, ev_handler=<optimized out>, opts=<error reading variable: Cannot access memory at address 0xffffffffffffffff>, url=<optimized out>, protocol=0x0, extra_headers=0x0) (gdb) print opts Cannot access memory at address 0xffffffffffffffff
问题解答与排查思路
核心结论
该故障不是C/C++调用约定差异直接导致,给调用方函数加extern "C"无法解决问题。
aarch64遵循AAPCS64调用规范:当值传递的结构体尺寸超过通用寄存器承载上限时,调用方会在自身栈帧上分配结构体副本,将副本指针传递给被调用函数。你看到的0xffffffffffffffff非法地址,本质是被调用方读取opts成员时,拿到了错误偏移位置的垃圾值,根因90%以上是C++侧和C共享库侧看到的struct mg_connect_opts内存布局不一致。extern "C"仅作用于函数符号的名称修饰规则,不影响结构体的内存布局,你当前已经能正常进入mg_connect_ws_opt函数帧,说明符号解析完全正常,不需要给调用方加该修饰。
排查优先级
- 优先核对两边使用的头文件一致性
检查C++代码包含的mongoose.h,和编译libmongoose时使用的mongoose.h是否为完全相同的版本,重点核对:struct mg_connect_opts的成员顺序、成员数量是否一致- 结构体中是否存在条件编译包裹的成员(比如
#ifdef MG_ENABLE_SSL控制的SSL相关字段),两边编译时的宏定义是否匹配
你打印的opts中存在ssl_cipher_suites、ssl_psk_identity等SSL相关字段,非常大概率是编译C++代码时开启了SSL相关宏,但编译libmongoose时关闭了对应宏,或者反过来,导致两边结构体中SSL字段的偏移完全错位,值传递时拷贝的内存长度不匹配,被调用方读成员时直接访问非法地址。
- 直接校验结构体尺寸
分别在C++调用侧、C库函数内打印sizeof(struct mg_connect_opts)的值,如果两个值不相等,可直接坐实头文件/宏定义不匹配的问题。 - 排查结构体对齐规则
如果确认头文件、宏定义完全一致,检查C++代码中是否存在#pragma pack等修改结构体默认对齐的指令,或者编译时加了自定义对齐参数,导致两边结构体对齐规则不一致、成员偏移错位。
临时验证方案
如果暂时无法重新编译libmongoose,可以临时将mg_connect_ws_opt的opts参数改为指针传递,修改后如果参数访问恢复正常,即可确认是值传递时两边结构体大小不一致导致的拷贝长度错误。
内容的提问来源于stack exchange,提问作者w0wy
相关产品推荐
相关产品推荐

