前老东家的项目经理qq咨询我说遇到设备端里面的程序自动重启,观察调试日志有下面信息:
May 8 15:49:03 xx_server: ***read fd = 22 read error Bad file descriptor**
May 8 15:49:03 xx_server: handle_distribution_cmd_child:pollerr fd = -1277165504,errid=49
May 8 15:49:03 mpd: client: [341] closed
May 8 15:49:03 mpd: client: [342] closed
May 8 15:49:03 mpd: client: [340] closed
May 8 15:49:03 kernel: [ 1083.214089] usb 1-1: clear tt buffer port 1, a3 ep1 t81008d8a
May 8 15:49:04 watch_server: restart xx_server
项目经理介绍该现象无规律,三台机器出现了一台,而出现的这台机器下午继续实验又出现了一次,暂时没有发现其他规律。
分析过程:
根据描述和调试信息,初步推断是由于xx_server读取文件描述符出错导致程序异常退出后守护进程重新启动了xx_server,由于server的重新启动,导致以前外部建立的链路都中断被用户感知。
打印出来的fd是一个明显很异常的值,根据经验,出现这种情况一般有两个:1 指针越界访问 2 访问被释放没有归零的指针。
让工程师用gdb运行跟踪,出现异常后gdb出现下面信息:
因为所有错误都是和fd有关,重点查看操作该fd的代码,我把故障点代码贴出来,大家可以看下问题点:
该段代码是引用网络上的代码但是被工程师根据具体需要改动过(虽然我曾经是这个项目的总负责人,但是具体的代码也都是下面工程师写,我仅知道架构和代码大致运行流程)。经过分析里面fd操作,发现了问题点。
故障点我在这里标红:
代码逻辑没有考虑到这种异常情况:
it = pollfds.erase(it); 操作后如果刚好it等于end,前面的for循环还是会继续做it++,自增动作导致it已经越界,导致逻辑判断it != pollfds.end() 仍然成立进而进入对it的fd进行访问导致越界。
把以上分析告诉项目经理对代码进行修正后该问题排除,一个困扰老东家的问题远程搞定。