最近工作中遇到一个问题,前前后后共定位了4天+,当最后定位到根因的时候,才发现“最后出问题的地方往往是那些你认为最不会出问题的地方”这句话是警示名言,要牢记之。
问题场景:有一大片内存,从起始地址开始以128KB大小切块(低地址的64KB内存设置为只读,高地址的64KB内存主要用于任务栈),大概有205000个;现在写个函数从低地址开始把每个栈的低地址写入数组。
代码大概如下:
unsigned int stack_size = 65536;
void* statck_init(void* stack_start_addr,int num) {
unsigned int i;
void** stack_array;
if (!stack_start_addr) {
printf ("stack is NULL.\n");
return NULL;
}
stack_array = (void**)malloc(sizeof(void*)*20500);
if (!stack_array) {
printf("mallco stack array failed.\n");
return NULL;
}
for(i=0;i<205000;i++) {
stack_array[i] = stack_start_addr + stack_size*2*i;
}
return (void*)statck_array;
}
在运行业务过程中大概率出现同一片栈的内存被同时被两个任务运行,开始以为栈分配和释放流程中没有做好互斥,所以对栈使用的场景的代码进行详细代码检视和加调试信息,但是问题还是没有定位出来。
在定位问题期间,也有怀疑到上述代码可能有问题,但是代码如此简单,不会出问题,也拉多人检视。
但是最终多人同时分析代码时,突然发现:
stack_array[i] = stack_start_addr + stack_size*2*i;
代码中存在问题:stack_size*2*i可能溢出;
unsigned int的最大值是4294967295
当i为100000时:stack_size*2*i的值是13107200000,此时对unsigned int的数据类型来说已经溢出,所以stack_array中存在多个同一个地址,所以从数组中取的地址存在重复。
思考
1.检视代码时多关注边界问题,数组溢出,地址溢出,数据类型溢出等。
2.最不可能出现问题的代码往往就是问题的根因。
3.检视代码不能因为简单而跳过。
本文通过一个实际案例,展示了如何排查和解决由于地址计算错误导致的栈内存重复分配问题,强调了即使简单的代码也可能隐藏着难以察觉的问题。

7437

被折叠的 条评论
为什么被折叠?



