• 一个arm平台工程段错误的排查


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

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

    起因

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

    排查及解决

    问题定位

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

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

    解决方法

    将最后组装的buffer数组容量改大即可。

    重现代码

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

    注:最后的output会越界。

    #include 
    #include 
    
    #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上是不存在的),没有条件很难测试到位。另一方面,审查代码也很难显式看出来。
    • 工程代码有大量的编译警告,但似乎没有人修正,从笔者经验看,修正警告也会带来隐患。
  • 相关阅读:
    如何解决pc端屏幕显示缩放比例125%,150%对页面布局的影响
    【Linux】时间同步
    YOLO V5、SAM、RESNET50模型在GPU环境下搭建过程
    计算机图像处理-均值滤波
    利用uni-app 开发的iOS app 发布到App Store全流程
    知识图谱:知识融合
    代码随想录二刷day29
    使用rna-seq定量软件salmon运行index步骤遇到的一个问题(计算集群slurm)
    竞赛选题 深度学习LSTM新冠数据预测
    BP算法学习心得(反向传播算法)
  • 原文地址:https://blog.csdn.net/subfate/article/details/131259223