CAN信号处理传参异常:iface_id值不符问题排查求助
问题背景
为CAN接口帧缓冲实现自定义信号处理程序myHandler,处理流程中通过pthread_sigmask()在处理开始时阻塞目标信号、结束时解除阻塞,以避免信号重入。程序持续接收CAN帧运行一段不确定时长后,bufferMessageDirect()中的assert(0)触发导致程序终止。调试发现:信号处理栈帧中iface_id为有效值0,但传入bufferMessageDirect()的参数can_interface_id却变为-1,且已确认输入CAN帧无异常。
可能成因分析
信号处理栈帧变量被意外覆盖
信号处理函数的栈空间独立且有限,若myHandler中调用bufferMessageDirect()前存在栈溢出(比如局部变量过多、递归调用),或主程序栈与信号栈的内存区域发生重叠(部分系统配置下可能出现),会导致iface_id的存储被破坏。比如栈溢出后,后续写入的数据覆盖了iface_id的内存位置,使其从0变为-1,最终传入bufferMessageDirect()。pthread_sigmask()使用逻辑存在竞态
若在解除信号阻塞的操作与myHandler函数返回之间存在时间窗口,此时新的目标信号可能立即触发并抢占当前信号处理流程。新的信号处理会复用信号栈,可能覆盖当前处理流程中尚未完成传递的iface_id变量值。即使在处理开始时阻塞了信号,解除阻塞后的瞬间竞态仍可能导致参数被篡改。bufferMessageDirect()参数传递的寄存器/栈对齐问题
部分CPU架构下,函数参数会通过寄存器传递,若信号处理函数未正确保存和恢复调用者寄存器(比如编译器优化导致寄存器未被妥善保护),调用bufferMessageDirect()时寄存器中的参数值会被意外修改。另外,栈对齐错误也可能导致参数读取位置偏移,使原本的0被读成-1(比如栈地址未按要求对齐,读取时取到了相邻内存的无效值)。异步信号安全违规
若bufferMessageDirect()本身不是异步信号安全函数(比如内部使用了非原子操作的全局变量、调用了malloc/free等非信号安全函数),即使阻塞了目标信号,其他未阻塞的异步信号(如SIGSEGV、SIGALRM)仍可能打断bufferMessageDirect()的执行,导致其内部状态混乱,甚至反向修改传入的参数值。多线程环境下的信号处理冲突
pthread_sigmask()仅对当前线程生效,若程序为多线程架构,其他线程未阻塞目标信号,当信号触发时可能被其他线程捕获处理。此时不同线程的信号处理流程可能共享或干扰全局/共享变量,导致iface_id在传递到bufferMessageDirect()前被其他线程的操作修改为-1。
内容的提问来源于stack exchange,提问作者Walkingbeard

