#pragma pack(1) 引发的血案

2019-08-05  本文已影响0人  乐十七

问题

static VCUStateEvt smlPoolSto[20];
上述变量中的 smlPoolSto[0]的值被第三方修改,反复查找没有找到变量本身被修改的地方,也没有找到有指针直接指向这个变量。

解决过程

本着程序员不相信玄学的精神,打断点调试,找到问题的边界

       LightEvt *test;
       test = Q_NEW(LightEvt, wake_up_SIG);
       QF_PUBLISH(&test->super, "tt");

上面的代码运行20遍就会出现。
当然这个这个断点是不会手动按21次了,设置断点触发条件。


捕获.PNG

在触发的临界点在使能变量断点


捕获1.PNG

只监控变量的写入位置,手动检测到了这里跳出的时候,变量的值发生了变化

 if (p_obj != (OS_PEND_OBJ *)0) {
        p_tcb->DbgNamePtr =  p_obj->NamePtr;                /* Task pending on this object ... save name in TCB       */
        p_pend_list       = &p_obj->PendList;               /* Find name of HP task pending on this object ...        */
        p_pend_data       =  p_pend_list->HeadPtr;
        p_tcb1            =  p_pend_data->TCBPtr;
        p_obj->DbgNamePtr = p_tcb1->NamePtr;                /* ... Save in object                                     */
    } else {
        switch (p_tcb->PendOn) {
            case OS_TASK_PEND_ON_TASK_Q:
                 p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)"Task Q");
                 break;

            case OS_TASK_PEND_ON_TASK_SEM:
                 p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)"Task Sem");
                 break;

            default:
                 p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)" ");
                 break;
        }
    }

这段代码和 smlPoolSto[0] 没有任何联系,在进一步打断点,发现是下面的复制语句让变量值改变、
···C
p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)"Task Q");
···

显然指针和我们开头描述的变量地址是一样的。
通过查找map文件,最终发现了问题所在

.bss                zero     0x2001c708     0xb4  App_BLEProtocol.o [1]
  .bss                zero     0x2001c7bc     0xa0  qp_bsp.o [1]

pcb指向的结构体和 smlPoolSto在相邻的RAM区域,而且PCB的结构体实际指针大小应该是0xB8
难道是编译器算错了,我试着在pcb的前后加变量偏移pcb的位置等操作,发现不论怎样地址是多少,pcb的大小都是0xb4.
于是pcb旁边定义变量计算大小。
uint32_t len = sizeof(pcb);
输出结果竟让是179,竟然是奇数对齐,这时才发现这个问题可能是字节对其的原因。

结果

果不其然在其对应的头文件中发现了

#pragma pack(1) 

一个孤独的 #pragma pack(1)
辛亏这个头文件没有大范围应用,不然真不知道会发生什么。
最终解决方案很简单,

#pragma pack(1) 


#pragma pack() 

给它找个对象就OK了。

上一篇下一篇

猜你喜欢

热点阅读