【Debug调试记录】结构体变量占位符未动态分配内存,引起的内存溢出
摘要:本文记录了一个C语言开发中因内存溢出导致Segmentation fault的调试过程。问题源于结构体中定义了一个不分配内存的占位符数组,但在x86系统中函数形参从右到左压栈的内存分配方式下,对cache变量的错误操作意外改变了相邻input变量的内存地址。通过gdb调试发现,静态定义的结构体变量无法为占位符提供足够空间,导致memcpy操作越界。最终解决方案是改用malloc动态分配结构体
记录一次在开发过程中,由于疏忽,导致的内存溢出的调试过程。涉及到:
- 结构体中定义了占位符
- x86 系统中该函数的形参为多个时,形参在堆栈空间上的内存分配。
- malloc 动态分配内存的重要性
- C语言中内存没边界检查,对开发者代码编写的要求较高
目录
0. 个人简介 && 授权须知

📋 个人简介
- 💖 作者简介:大家好,我是喜欢记录零碎知识点的菜鸟打工人。😎
- 📝 个人主页:欢迎访问我的博客主页🔥…
- https://blog.csdn.net/qq_39217004?spm=1010.2135.3001.5343
- 🎉 支持我:点赞👍+收藏⭐️+留言📝
- 📣 系列专栏:嵌入式Linux开发 🍁 🍁
- 💬格言:写文档啊不是写文章,重要的还是直白!🔥
转载文章,禁止声明原创;不允许直接二次转载,转载请根据原文链接联系作者
若无需改版,在文首清楚标注作者及来源/原文链接,并删除【原创声明】,即可直接转载。
但对于未注明转载来源/原文链接的文章,我将保留追述的权利。https://blog.csdn.net/qq_39217004?spm=1010.2135.3001.5343
作者:积跬步、至千里

1. 问题描述
- 调用自己定义的
Tensor接口,创建3个四维张量。其中create_tensor是 malloc 的,使用完毕之后需要手动释放。
Tensor *cache_tensor = create_tensor(4, cache_shape, TYPE_FLOAT16, "cache_tensor", LAYOUT_ROW_MAJOR, false);
Tensor *input_tensor = create_tensor(4, input_shape, TYPE_FLOAT16, "input_tensor", LAYOUT_ROW_MAJOR, false);
Tensor *input_vector_tensor = create_tensor(4, input_vector_shape, TYPE_INT32, "input_vector_tensor", LAYOUT_ROW_MAJOR, false);
- 调用自己的函数接口,更新张量的值
update_Tensor_device(cache_tensor, input_tensor, input_vector_tensor);
- 执行完毕后,释放张量
free_tensor(cache_tensor);
free_tensor(input_tensor);
free_tensor(input_vector_tensor);
- 报错,core dumped

2. 查找 Segmentation fault (core dumped) 的原因
gdb 运行可执行文件,找到报错的地方,通过 backtrace 查找

可以看到,在释放创建的张量时,报错了。
以上三个张量都是在 CPU 端通过 create_tensor 创建的,释放时报错,我们打印出张量数据的地址观察。
张量的地址为什么会被改变了呢?
在调用 input_tensor 变量的函数处,调用前和调用后分别打印 变量的地址,发现,该变量是在 my_test 函数中被改变了值。
3. 分析函数中内存溢出的位置
input_tensor 变量的地址被改变了,而 my_test 函数中,该参数恰好是 const 类型的,说明代码肯定是有问题,产生了内存被篡改的地方。
void my_test(Tensor *cache,const Tensor *input, Tensor *input_vec)
在 x86 中,函数的形参在栈空间上的分配为: :参数从右到左压栈
栈顶 → input_vec → input → cache ← 栈底
既然 input 是 const 类型,那么是否 cache 或者 input_vec 变量产生了溢出?
详细查看代码中,对cache 或者 input_vec 变量赋值的地方。
- 在函数执行的位置打断点

- 监控变量
watch input_tensor->data
继续执行,果然变量的地址被改变了
报错信息为:
Thread 1 "update_cache_te" hit Watchpoint 2: input_tensor->data
Old value = (void *) 0x40f8f0
New value = <unreadable>
__memmove_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:243
243 ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S: No such file or directory.
经查找资料,程序停在了 __memmove_avx_unaligned_erms —— 这是一个底层内存拷贝函数(如 memcpy 或 memmove 的实现)。
而我的代码中确实有用到 memcpy 接口

经过研究以上变量,发现我的结构体是这么定义的:

4. 结构体变量中的占位符惹的祸
代码中,结构体中定义了一个 int32_t input_vector_arry[0]; 作为占位符。
本身占位符是不分配内存空间的。
我定义了一个普通的 结构体变量,并将一个数组赋值到了结构体变量的占位符中,也恰好是我代码中 memcpy 接口的地方。
其实 cblk_matmul.runtimeArgs.input_vector_arry 这个地址是不可访问的。
由于赋值时意外给 cache 变量的额外的空间赋值,并且
cache input 和 input_vec 三个变量是函数形参,因此我错误的操作了cache 变量之外的地址空间,影响了 input 变量的地址。
造成了 input->data 被意外改变了地址,导致 cpu 无法访问
New value = <unreadable>
因为这个地址就是数组中的值了,比如 0x0b,cpu 当然无法访问。
5.修改错误
定义结构体变量时,由于有个占位符,因此必须使用动态分配内存的方式,把需要使用的占位符的空间提前算出来。如下所示:
在 memcpy 时,拷贝的数据一定不要越界
修改以上代码,再次测试,解决了 Segmentation fault (core dumped) 问题。
6.总结
函数形参的地址:
更多推荐

所有评论(0)