结构体对齐导致结构体数组大小变化引发的指针越界操作问题.

来源:互联网 发布:mac word 登录 编辑:程序博客网 时间:2024/05/17 06:29

老大昨晚喊我过去帮他看看程序出现的奇怪问题, 挺晚才回去, 所以没来得及写, 今天反刍(恶......)了一下记录

下来. 哈哈.......被人需要果然是一种幸福. -_-||


这个 DSP 程序驱动部分几乎全是员工 Z(已离职) 编写的. Y 工呢, 根据这个基础增加实现了一部分 OS 功能, 如内

存管理,消息, 信号. 之后就没在继续了, 可能是升任管理层了. 我在刚来时, Y 工曾让我看了一段时间的代码. 我

得叫 OS 真的很扯, 因为已实现的功能在空转, 核心的进程管理功能没有实现. 程序执行方式还是传统的for(;;)

 & while(1).所以, 我把他们全精简掉. 事实证明是对的. 


本来可以一直搞这个 C6000 的. 奈何核心板硬件问题迟迟没有解决,目搁置. 我又被分配到了其他项目的单片机编

程填坑. 擦........扯远了.

-----------------------------------------扯蛋分割线---------------------------------------------------

谈正题:

老大 S 本来对这个 DSP 程序不甚了解, 所以在修改网络处理的相关代码时, 可能没有考虑到对其他代码的影响. 这

大概就是程序维护的大坑.


问题呢是如此...........

原本这个结构体是这样的:

typedef  struct {        u32   a;        u8    b;        u8    c;        u8    d;        u8    e;} VHF;VHF  VHF_Channel[15];// 15 * 8 = 120 Bytes


然后呢, 在结构体里增加了一个成员, 用于表示某个通道是否有效. 所以呢变成了这样:

typedef  struct {        u32   a;        u8    b;        u8    c;        u8    d;        u8    e;        u8    f;// 增加的成员} VHF;VHF  VHF_Channel[15];// 15 * (8 + 4) = 180 Bytes

然后编译链接, 双零; 运行, 死机!!! 


插调试器, 设断点, 单步, 发现在某个函数里的 for 循环 i 在从 0 到 15 的过程中,只增加到 13 然后 i 又回到

1 增加, 如此循环, 死在这了, 而且在变成 12 的时候, 更改了函数内其他 3 个变量的值, 这个是不符合逻辑的.

因为循环体内压根就没对这三个变量进行直接或间接的操作. 


开始的时候怀疑是栈溢出的问题, 查阅了手册, 根据编译后的 .map 文件(文后附内容)中得出的 RAM unused 大小修

了 .cmd 文件中 -statck 的大小, 增加一倍(4KB). 这肯定足够了. 烧写调试还是老错误. 其实原来栈空间就有

 4KB 了. 这个程序是足够的. 


不得已, 重新检查, 挨个单步执行查看, 函数内的局部变量值是否符合预期. 当单步执行到一个长度变量(结构体数

组的长度加上其他值)时, 发现了一个错误, 按照申请的 u32 buf[40] 也就是 160 字节. 而这个长度变量居然是

 205(正常值应该是 145), 远超过了缓冲区大小. 


源头发现是因为增加了结构体成员导致的大小变化. 因为编译器默认是按照 4Bytes 对齐原则(word-alignment)

(查看手册是个好习惯), 所以一个结构体就增加了 4 字节. 而 15 个结构体数组就增加了 60 字节. 远超缓冲区大

小了.


所以, 当 for 循环在操作 0-14 的结构体数组时, 指针已经越界操作. 导致的问题就是修改了不该指向的内存

域. 所以, 才会有不相干变量值的变化. 


其实如果结构体仅仅增加一个字节, 也就多了 15 个字节, 总共刚好侥幸到达 160. 侥幸是侥幸, 后果很严重. 

合理的做法还是使用编译器指令来强制结构体字节对齐.如 

struct  __attribute__ ((__packed__)) packed_struct {         char c1;         int i;         char c2; };

结束附上参考的编译器手册对应章节:



.map 文件内容(部分), 手册中有介绍:

******************************************************************************               TMS320C6x Linker PC v7.4.1                      ******************************************************************************>> Linked Tue Nov 12 10:47:24 2013OUTPUT FILE NAME:   <E:/os_app8023/project/../Debug/project.out>ENTRY POINT SYMBOL: "_c_int00"  address: 10012fc0MEMORY CONFIGURATION         name            origin    length      used     unused   attr    fill----------------------  --------  ---------  --------  --------  ----  --------  VECTOR_RAM            10000000   00000300  00000200  00000100  RWIX  TEXT_RAM              10000300   00015000  000131fc  00001e04  RWIX  RAM                   10015300   0000ad00  00008226  00002ada  RWIXSECTION ALLOCATION MAP output                                  attributes/section   page    origin      length       input sections--------  ----  ----------  ----------   ----------------.pinit     0    10000300    00000000     UNINITIALIZED..............以下 略


1 0