天天看点

移植C/C++到嵌入式Linux下程序崩溃的问题

最近将自己开发的SIP协议栈移植到ARM芯片下的嵌入式Linux,遇到一个奇怪问题,这篇小文简要记录解决过程。

相同的代码在windows下、CentOS Linux下都正常,交叉编译到ARM芯片的64位Linux下总是崩溃,估计堆栈、内存被破坏,用Valgrind没办法定位到具体的出错位置。经过多次用最原始的printf()跟踪,发现和md5加密函数有关,筛查了代码死活也没发现错误。如此折腾了将近一周,神经高度紧张。

后来仔细分析相关的源代码,终于发现问题所在。

协议栈用到一个md5的函数库,这个库比较古老,Dos时代就存在。其中的头文件md5.h有问题:

#ifdef __alpha

typedef unsigned int uint32;

#else

typedef unsigned long uint32;

#endif

Dos时代(或windows NT 3.1时代),alpha芯片是32位的,因此定义一个32位无符号整数,用unsigned int,而intel的286之类的芯片int类型是16位的,所以32位无符号整数需定义为unsigned long。

到了现在的64位时代,这些就有问题了。

在windows下:int - 4字节32位,long - 4字节32位,long long - 8字节64位

在linux下:int - 4字节32位,long - 8字节64位,long long - 8字节64位

上述定义,非_alpha,32位无符号整数被定义为typedef unsigned long uint32,在windows下没问题,在linux下是有问题的,实际上成了64位。很多因此定义的缓冲区,在操作时就可能出错。

也许会问,同样Linux,为何CentOS下没问题呢?那是因为Intel和ARM芯片的内存布局不一样,ARM会立即暴露而已。

后来将上述定义统一改为(反正不可能16位时代了):

typedef unsigned int uint32;

重新编译后,程序就非常稳定了。

继续阅读