#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了。