常见的内存陷阱

19 篇文章 0 订阅

c/c++常见的内存陷阱

数据缓冲区分配不足及内存访问越界

分配不足是与c风格字符串相关的常见问题,大多数情况下,都是因为程序员没有额外分配尾部的’\0’终止符。当创建某个固定大小的空间时,也会发生字符串分配不足的情况。基本的内置c风格字符串函数不会针对固定大小操作,而是有多少写多少,如果超出字符串的末尾,就写入未分配的内存。例如:

char buff[8]{"hello"};
strcat(buff, "world");
printf("%s\n", buff);

上述代码编译的时候不会报错,但是执行的时候会:

helloworld
*** stack smashing detected ***: <unknown> terminated
已放弃 (核心已转储)

数据缓冲区分配不足通常会导致内存访问越界。例如上例,写入的数据超出分配的空间大小,导致在分配的空间外写数据,就很可能将内存中重要的部分被改写,导致程序崩溃。

在处理由于某种原因丢失’\0’终止符的c风格字符串时,也可能发生内存访问越界。例如,将某个字符串str的字符全部替换成字符’a’,但是由于某种原因该字符串丢失了终止符,导致替换的字符a超出了字符串str的大小,则会继续在字符串后面写字符a,改写了字符串边界外的内存。

void func(char *str)
{
    int i = 0;
    while (str[i] != '\0') {
        str[i] = 'a';
        i++;
    }
}

对于内存越界问题经常会被一些黑客利用,改写部分内存来攻击用户。

所以应该避免使用旧的c风格字符串和数组,它们没有提供任何保护;而要改用像c++中string、vector这样安全的结构,它们能自动管理内存。

内存泄漏

在大型项目中,常常会出现分配了内存,而没有释放,从而导致了内存泄漏。过多的泄漏会拖垮整个系统。然而依靠单纯阅读代码排查这些泄漏点非常困难,所以一般都借助工具来完成这项工作。比如在Windows下可以使用Microsoft Visual C++的调试库对内存泄漏进行检测,在linux下使用Valgrind中定位,它可以精准的定位到泄漏的行数。当然除了上述两个工具,还有很多免费或者付费的工具。

双重释放和无效指针

当释放某指针指向的内存后,那么该内存就可以重新被其它部分使用了。所以会造成已经被释放了对象在释放后立即或者短时间内再次使用,这个对象可能完好无损的被使用。造成程序错误,崩溃等。

在同一个指针上执行了两次的释放操作,程序可能会释放重新分配给另外一个对象的内存。当然如果双重释放在较短的时间内发生,程序可能会产生未定义的行为,因为关联的内存可能不会那么快的被重用。重复释放内存可能导致应用程序崩溃,拒绝服务攻击等,是C/C++常见漏洞之一。

在我使用的编译器(gcc version 11.1.0)上是会对双重释放报错的(free(): double free detected in tcache 2)但是有些编译器是不会报错的,所以当程序发生无效指针(悬空指针)、双重释放的问题依靠程序员来排查是非常困难的,而且往往上述事情发生了,并不会马上导致程序崩溃,而是在未来的某时候发生错误,那么排查问题将变得非常痛苦。所以程序员最好的办法一定在释放指针后,将指针置空,这样就不会出现上述的问题了。当然也有很多内存检测工具可以检测上述问题。

对于c/c++程序员来说内存管理方面常常会带来很多bug。在c++11中引入了智能指针来帮助程序员管理分配的内存,当智能指针所托管的内存空间离开作用域或者被重置时,会自动释放所占有的资源。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值