记录生活:一个arm平台工程段错误的排查
  aAUWpv2LLzAQ 2023年11月02日 55 0

某 arm 工控机在试点测试时发现,一旦有数据到,工控机界面会就卡住,测试人员此问题必现,经查日志为段错误,多次在相同代码位置出错。除去周末,经过一天多时间,解决了问题,虽然没有很难的技术问题,但过程还是值得记录的。

由于本文没有技术含量,请谨慎按需阅读。

起因 上周五早上,测试人员(很不幸,我还无资格称之为同事)正在去试点路上,打电话给我,说要更新软件版本,于是我拉取代码树上最新的release分支。基于手上没有 arm 的编译环境,于是打包发给他,让他在测试机上编译并测试。后来才知道,那是目前唯一一台集编译和测试于一体的一体机。编译好后,指导如何更新,近中午时反馈出现段错误,因为有其它事,到下午时才找日志看。由于那个工程我没有参与,所以找相应开发人员看,经查,问题定位到一个初始化语句std::string foobar = "";,四只眼睛分析半天没结论。经商量,把试点的机器搬回来,在实验室重现,再跟踪调试。

排查及解决 问题定位 咨询测试人员,反馈说在实验室相同场景测试时没有遇到问题。由于实验室均为x86机器,也没错误,只能加打印调试。

先是在出错那一行代码前面加上一些语句,测试,发现出错的行号变化了,依然指向那个string语句。再仔细观察代码,发现这个string类型变量在函数后面赋值给另一个数组(char buff[]),于是怀疑数组容量不够,将组装后的string变量长度打印,发现超过了数组长度。将长度加大,测试,一切正常。使用工程封装的log函数打印,发现URL地址的中文输出有乱码,但用printf输出正常。URL的转义是通过调用curl库函数curl_easy_escape实现的,中文字符会带了百分号%,怀疑是封装log函数问题,限于时间,没有再研究。不过可能是个隐患,日后再议。

解决方法 将最后组装的buffer数组容量改大即可。

重现代码 下面模拟实际工程的函数布局,舍去无关的代码,以突显问题。

注:最后的output会越界。

#include <stdlib.h> #include <stdio.h>

#include

int main() { const char* url = "http://172.168.168.188:18080/api/new/v2/queryAVeryloongApiforveryloongremoteipserver?"; char foo1[256]={0};

int a = 100;
int b = 1;
int c = a+b+1+1+b+3+a;

std::string strData = "";

for (int i=0; i < 3; i++)
{
    strData.append("&");
    strData.append("10000");
    strData.append("=");
    strData.append("103");
}
char output[96]={0};

sprintf(output, "%s?%s", url, strData.c_str());
printf("url=%s\n", output);

return 0;

}

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 经测试,只有x86上正常,其它2个平台段错误。从业多年的直觉认为,x86上应该是看上去正常,实际不正常(肯定是越界了),但一直如此使用,百思不得其解。

在x86工控机上的测试结果:

$ file a.out a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=3e7c0c704230b08e49f529a6924397e0dfd358ba, not stripped

$ ./a.out url=http://172.168.168.188:18080/api/new/v2/queryAVeryloongApiforveryloongremoteipserver??&10000=103&10000=103&10000=103 1 2 3 4 5 在arm工控机上的测试结果:

$ file a.out a.out: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.7.0, not stripped

$ ./a.out url=http://172.168.168.188:18080/api/new/v2/queryAVeryloongApiforveryloongremoteipserver??&10000=103&10000=103&10000=103 段错误(吐核) 1 2 3 4 5 6 在loongarch工控机上的测试结果:

$ file a.out a.out: ELF 64-bit LSB executable, LoongArch-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld.so.1, for GNU/Linux 4.15.0, BuildID[sha1]=7d61ce6d3a50850e045dcdaab48585f88bbca4f7, not stripped

$ ./a.out url=http://172.168.168.188:18080/api/new/v2/queryAVeryloongApiforveryloongremoteipserver??&10000=103&10000=103&10000=103 总线错误 1 2 3 4 5 6 小结 最近断续地接触国产化适配,有点小心得。

与很多人认为的只要改个宏定义,交叉编译一下就行不同,我对适配的事不敢太乐观。上面往往认为三两天就能做完,但实操起来就很麻烦。相同的代码,在不同的架构(x86和arm、mips)上表现不一定相同。

目前较大的问题有下面几个:

很多工程代码已经有数年历史,有些函数已无可考,有的代码用了当时的第三方版本,如果贸然更新,或使用新操作系统新编译器,则可能导致编译不通过。 宏定义修改的确简单,但工程代码里,对于系统位数和系统架构两个不同概念没有区分,所以要十分小心。比如,指针长度,在32位和64位系统中,值就不同。 代码存在隐藏的bug,如段错误。一方面,不同架构平台对个别段错误类型的处理方式不同(如本文所遇到的问题,在x86上是不存在的),没有条件很难测试到位。另一方面,审查代码也很难显式看出来。 工程代码有大量的编译警告,但似乎没有人修正,从笔者经验看,修正警告也会带来隐患。 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  4WdcduV19eWs   2023年11月02日   65   0   0 ios#includeios#include
  4WdcduV19eWs   2023年11月02日   62   0   0 ios#includeios#include
  4WdcduV19eWs   2023年11月02日   67   0   0 ios#includeios#include
  4WdcduV19eWs   2023年11月02日   54   0   0 ios#includeios#include
  4WdcduV19eWs   2023年11月02日   44   0   0 ios#includeios#include
  ZydNzX6XOBO2   2023年11月02日   114   0   0 出队C++ci#include
  4WdcduV19eWs   2023年11月02日   68   0   0 ios#includeios#include
  4WdcduV19eWs   2023年11月02日   90   0   0 ios#includeios#include
  ZydNzX6XOBO2   2023年11月02日   52   0   0 i++C语言#include
  4WdcduV19eWs   2023年11月02日   51   0   0 ios#includeios#include
  4WdcduV19eWs   2023年11月02日   80   0   0 #includelinuxlinux#include
aAUWpv2LLzAQ