QNX系统STR触发时日志模块异常崩溃及栈回溯问题排查求助
QNX系统STR触发时程序偶现崩溃排查方案
问题背景
程序在QNX系统中仅触发STR(挂起并恢复)操作时偶现崩溃,核心异常表现为非递归实现的qnx_slog2::log_output()函数出现自调用栈,且存在无效this指针(如0x2)。日志参数由fmt库生成,不存在格式不匹配问题。
初始崩溃信息
栈回溯
(gdb) bt #0 0x0000003ae09b5cc0 in ?? () #1 0x0000001b5319cf64 in qnx_slog2::log_output (this=0x2, level=1, fmt=0x3ae09c9138 ,level=1) at /home/jhone/qnx_slog2.hpp:137 #2 0x0000001b5319cf64 in qnx_slog2::log_output (this=0x1b531e9048 <gnx slog2::get log()::slog2instance>, level=1, fmt=0x2ec2c7fbd0 "[st_slog2] 0MS-E oms_result_sender.cpp:174 operator()() soa ges dynamic rect width:0, height:0, x:0,y", level=1) at /home/jhone/qnx_slog2.hpp:137 #3 0x0000003aed61fcc in malloc_lock.constprop.4 () from //home/jhone/publish/lib/libc.so.5 #4 0x6c757365725f736d in ??() Backtrace stopped: previous frame identical to this frame (corrupt stack?)
对应log_output实现(qnx_slog2.hpp)
void log_output(short level, const char* fmt, ...) { if (true == log_block(level)) { return; } std::unique_lock<std::mutex> lock(lock_); va_list args; va_start(args, fmt); switch (log_type_) { case LOG_TYPE_QNX: if ((fmt != nullptr) && (match_level(level) > 0) && (*fmt != '\0')) { //line 137 vslog2f(nullptr, log_id_, match_level(level), fmt, args); } break; case LOG_TYPE_PRINTF: { memset(print_buffer_, 0, sizeof(print_buffer_)); vsnprintf(print_buffer_, sizeof(print_buffer_), fmt, args); log_print(level); break; } } va_end(args); }
优化后仍存在异常
改用线程安全的slog2c重实现log_output及相关宏后,崩溃概率从约1/(2×20)降至1/(33×18),但栈回溯仍存在重复调用异常:
#0 0x00000055f55b5afc in ?? () #1 0x0000004b6a42a9b8 in qnx_slog2::log_output (level=2, str=..., this=<optimized out>) at /mnt/nfs/qnx710/target/qnx7/usr/include/c++/v1/string:1520 #2 qnx_slog2::log_output (str=..., level=2, this=<optimized out>) at /home/jhone/qnx_slog2.hpp:103 #3 OMSResultSender::<lambda()>::operator()(void) const (__closure=<optimized out>) at /home/jhone/oms_result_sender.cpp:135 #4 0x0000004b6a42a9b8 in qnx_slog2::log_output (level=2, str=..., this=<optimized out>) at /mnt/nfs/qnx710/target/qnx7/usr/include/c++/v1/string:1520 #5 qnx_slog2::log_output (str=..., level=2, this=<optimized out>) at /home/jhone/qnx_slog2.hpp:103 #6 OMSResultSender::<lambda()>::operator()(void) const (__closure=<optimized out>) at /home/jhone/oms_result_sender.cpp:135 #7 0x0000000000000000 in ?? () Backtrace stopped: previous frame identical to this frame (corrupt stack?)
程序编译参数:-g -O3 -DNDEBUG -std=gnu++14
逐步排查方案
1. 校验STR过程中全局/静态对象的一致性
- 打印
qnx_slog2单例对象(slog2instance)在STR挂起前、恢复后的内存地址,确认是否存在系统恢复时内存映射偏移或对象被破坏的情况。 - 验证
lock_、log_id_等成员变量的初始化状态:QNX的STR机制可能不触发全局对象重初始化,需确认恢复后这些变量的有效性。
2. 排查线程锁的STR兼容性问题
- 替换
std::mutex为QNX原生pthread_mutex_t测试:检查C++标准库锁在STR挂起恢复后是否处于异常状态(如锁被持有时进程挂起,恢复后状态未同步)。 - 分析栈中
malloc_lock异常:检查print_buffer_等内存区域在STR前后的完整性,可添加校验和验证是否存在堆/栈内存破坏。
3. 排查编译器优化导致的代码异常
- 临时关闭优化:改用
-g -O0 -std=gnu++14编译,测试STR崩溃概率,确认是否是-O3优化导致的代码重排、变量生命周期异常(尤其是this指针、va_list的处理)。 - 显式控制锁逻辑:替换
std::unique_lock为手动lock/unlock调用,添加内存屏障(__sync_synchronize()),排查优化带来的锁释放逻辑异常。
4. 验证slog2 API的STR适配性
- 查阅QNX官方文档,确认
slog2f/vslog2f/slog2c在STR场景下的行为:部分系统API在恢复后可能需要重新初始化,需测试STR恢复后重新调用slog2_register的效果。 - 禁用日志输出测试:临时注释所有
log_output调用,确认STR操作是否仍崩溃,排除日志模块外的问题。
5. 定位栈破坏的根源
- 使用QNX
crashinfo工具分析崩溃转储:获取完整栈信息、寄存器状态,确认无效this指针是否由栈溢出或堆越界导致。 - 启用栈保护:添加
-fstack-protector-all编译选项,触发栈溢出时主动报错,快速定位内存破坏点。 - 内存监控:使用QNX兼容的
memwatch或valgrind在STR循环测试中监控内存操作,捕获越界写行为。
6. 排查线程与信号处理异常
- 检查STR相关信号处理:QNX在STR挂起/恢复时会发送特定信号,确认程序自定义信号处理函数中是否存在日志调用,避免递归或栈破坏。
- 验证线程恢复状态:打印线程ID及栈地址范围,对比STR前后的变化,确认是否存在线程栈被破坏的情况。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

