专栏首页PHP饭米粒10 个内存引发的大坑,你能躲开几个?(3)

10 个内存引发的大坑,你能躲开几个?(3)

对程序员来说内存相关的 bug 排查难度几乎和多线程问题并驾齐驱,当程序出现运行异常时可能距离真正有 bug 的那行代码已经很远了,这就导致问题定位排查非常困难,这篇文章将总结涉及内存的一些经典 bug ,快来看看你知道几个,或者你的程序中现在有几个。。。

指针大小与指针所指向对象的大小不同
int **create(int n) {int i;int **M = (int **)malloc(n * sizeof(int));
for (i = 0; i < n; i++)  M[i] = (int *)malloc(m * sizeof(int));   return M;}

这段代码的本意是要创建一个n*n二维数组,但其错误出现在了第3行,应该是 sizeof(int *) 而不是sizeof(int),实际上这行代码创建了一个包含有 n 个 int 的数组,而不是包含 n 个 int 指针的数组。

但有趣的是,这行代码在int和int*大小相同的系统上可以正常运行,但是对于int指针比int要大的系统来说,上述代码同样会覆盖掉数组M之后的一部分内存,这里和上一个例子类似,如果这部分内存是 malloc 用来保存内存分配信息用的,那么也许当释放这段内存时才会出现运行时异常,此时可能已经距离出现问题的那行代码很远了,这类 bug 同样难以排查。

栈缓冲器溢出
void buffer_overflow() {char buf[32];
gets(buf);return;}

上面这段代码总是假定用户的输入不过超过 32 字节,一旦超过后,那么将立刻破坏栈帧中相邻的数据,破坏函数栈帧最好的结果是程序立刻crash,否则和前面的例子一样,也许程序运行很长一段时间后才出现错误,或者程序根本就不会有运行时异常但是会给出错误的计算结果。

实际上在上面几个例子中也会有“溢出”,不过是在堆区上的溢出,但栈缓冲器溢出更容易导致问题,因为栈帧中保存有函数返回地址等重要信息,一类经典的黑客攻击技术就是利用栈缓冲区溢出,其原理也非常简单。

原来,每个函数运行时在栈区都会存在一段栈帧,栈帧中保存有函数返回地址,在正常情况下,一个函数运行完成后会根据栈帧中保存的返回地址跳转到上一个函数,假设函数A调用函数B,那么当函数B运行完成后就会返回函数A,这个过程如图所示:

你可以在《函数运行时在内存中是什么样子》这篇文章中找到关于函数运行时栈帧的详细讲解。

但如果代码中存在栈缓冲区溢出问题,那么在黑客的精心设计下,溢出的部分会“恰好”覆盖掉栈帧中的返回地址,将其修改为一个特定的地址,这个特定的地址中保存有黑客留下的恶意代码,如图所示:

这样当该进程运行起来后实际上是在执行黑客的恶意代码,这就是利用缓冲区溢出进行攻击的一个经典案例。

操作指针所指对象而非指针本身
void delete_one(int** arr, int* size) {  free(arr[*size - 1]);  *size--;}

arr 是一个指针数组,这段代码的本意是要删除掉数组中最后一个元素,同时将数组的大小减一。

但上述代码的问题在于*和--有相同的优先级,该代码实际上会将 size 指针减1而不是把 size 指向的值减1。

如果你足够幸运的话那么上述程序运行到*size--时立刻 crash,这样你就有机会快速发现问题。但更有可能的是上述代码会看上去一切正常的继续运行并返回一个错误的执行结果,这样的bug排查起来会让你终生难忘,因此当不确定优先级时不要吝啬括号,加上它。

总结

内存是计算机系统中至关重要的一个组成部分,C/C++这类偏底层的语言在带来高性能的同事也带来内存相关的无尽问题,而这类问题通常难以排查,不过知彼知己,当你理解了常见的内存相关问题后将极大减少出现此类问题的概率。

希望这个小系列文章对大家理解内存与指针有所帮助。

本文分享自微信公众号 - PHP饭米粒(phpfamily)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-02-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 10 个内存引发的大坑,你能躲开几个?(2)

    对程序员来说内存相关的 bug 排查难度几乎和多线程问题并驾齐驱,当程序出现运行异常时可能距离真正有 bug 的那行代码已经很远了,这就导致问题定位排查非常困难...

    桶哥
  • 10 个内存引发的大坑,你能躲开几个?(1)

    对程序员来说内存相关的 bug 排查难度几乎和多线程问题并驾齐驱,当程序出现运行异常时可能距离真正有 bug 的那行代码已经很远了,这就导致问题定位排查非常困难...

    桶哥
  • 开工大吉:几个让你月薪3万+的excel神技能

    来源:运营圈信息流广告 职场中经常会用到哪些函数? IF函数、SUMIF函数、VLOOKUP函数、SUMPRODUCT函数...... 小编总结了8个在工作中常...

    CDA数据分析师
  • 你可能不知道大数据开发的10个技巧

    “当你不创造东西时,你只会根据自己的感觉而不是能力去看待问题。” – WhyTheLuckyStiff

    风火数据
  • Android爬坑之旅:软键盘挡住输入框问题的终极解决方案

    开发做得久了,总免不了会遇到各种坑。 而在Android开发的路上,『软键盘挡住了输入框』这个坑,可谓是一个旷日持久的巨坑——来来来,我们慢慢看。

    用户2802329
  • 吹弹牛皮之Unity 性能分析-锁定内存泄漏

    承载千万家庭的高考莘莘学子刚刚为10年的寒窗苦拉上帷幕。鼓励我们的学子多多选择计算机专业。这里有拉格朗日函数的求解,有傅里叶级数的转换。奥秘万千,从笛卡尔坐标系...

    用户7698595
  • 案例实战:每日上亿请求量的电商系统,JVM年轻代垃圾回收参数如何优化?

    按照惯例,我们接下来会用案例驱动来带着大家分析到底该如何在特定场景下,预估系统的内存使用模型。

    乔戈里
  • 高仿微信双击消息弹出可自由复制

    Enmmm,前几天突然才晓得微信还有一个双击消息弹出且提供自由复制的这么一个小功能,惊呆了,我滴天~!

    HLQ_Struggle
  • 天使投资人王利杰解读智能硬件创业趋势

    镁客网

扫码关注云+社区

领取腾讯云代金券