1

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

 1 year ago
source link: https://blog.csdn.net/subfate/article/details/131259223
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

李迟 于 2023-06-17 13:16:22 发布 2462

某 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 <string>

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;
}
newCodeMoreWhite.png

经测试,只有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

在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
段错误(吐核)

在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
总线错误

最近断续地接触国产化适配,有点小心得。

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

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

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK