昨天帮导师做的一个程序出了内存泄露的bug(在VS上程序运行一切正常,等return返回后才出错)

而且是程序运行结束后才出现的错误,在退出前一切代码都顺利执行完了,只是return之后出错。

之后我在Linux下重新编译运行程序,提示的信息更详细:

free(): invalid next size (normal)

然后下面显示Backtrace和Memory map等一大串错误信息。

最终调试发现问题在于,读取数据格式不对,导致字符串转换后的int小于0,下标越界。我只检查了上限N,没检查下限0。

那么问题来了,为什么动态分配的内存能访问下标为负的地方呢?来写几个程序测试下。

#include <iostream>
using namespace std; int main() {
const int N = ;
int* p = new int[N];
p[-] = ;
p[-] = ;
for (int i = -; i < ; i++) {
cout << p[i] << " ";
}
cout << endl;
delete[] p;
return ;
}
0 0 3 1
*** Error in `./a.out': munmap_chunk(): invalid pointer: 0x0000000000ed6c20 ***

可以发现在n<0时,p[n]仍然可以访问,但是最终结束时会出错。

再看看下面这份代码

#include <iostream>
using namespace std; int main() {
const int N = ;
int* p = new int[N];
p[N] = ;
cout << p[N] << endl;
delete[] p;
return ;
}

运行结果是100,并且没任何问题。

也就是说,C/C++可以访问显式申请的内存之外的内存空间,它们可能是库函数隐式申请的,比如之所以上面一份代码正常运行,但是异常退出,下面一份代码正常运行、正常退出。原因是,new(会调用内置的allocator)动态申请一片内存时,会在返回的指针p之前记录下申请的内存大小,这样之后用delete释放new申请的内存时会隐式查找记录的内存大小,从而知道该释放多少内存。所以才可以用delete[]而不是delete[N]。

同理,使用malloc()时也会在返回的指针之前的某个地址记录申请内存大小,这样free()就会在释放内存时找到这个记录分配大小的地址,然后知道释放多少。

C/C++不会像java一样在编译层面检查下标是否越界,所以如果不在代码里手动检查,下标越界可能会导致库函数需要用到的内存地址被我们误修改,从而使库函数出错。

明白了这一点后,new和delete配对,new[]和delete[]配对,malloc()和free()配对的原因也理解了。每个内存分配器都有自己的申请和释放的策略,比如说记录申请的空间,我可以在一个字节的前几位记录,也可以在一个字节的后几位记录,如果申请和释放的规则不一致的话就会造成错误的后果。

回顾之前我的两篇类似的博客

再记录一次delete出错的经历

【free() invalid next size】谨慎地在C++的类中存储指针来方便访问其他节点

第一篇,用cvLoadImage申请内存,却用delete释放内存,两者记录申请内存大小的策略不同,因此释放出错。

第二篇,记录了vector之前的内部指针p,但是vector重新分配内存后内部指针变了,再访问p指向的位置就物是人非了。和我这次很像的是,之前那篇我自信满满地认为vector不会重新分配内存,即认为push_back的次数小于reserve预留的大小,这篇则是自信满满地认为下标肯定为非负数,因为之前的下标是用字符串转换而成的,比如"0a"对应的就是10,我认为肯定会不小于0,但是这些下标是从1开始的,所以我将字符串转换后的下标都减了1,这样的话错误的输入比如"00"在转换后就是-1,下标越界。

总结下来,C/C++下标越界确实是个麻烦,有时候像这种“自信满满”的预测会导致运行错误,所以最佳的实践方式是写出便于调试的代码。

1、尽可能使用STL容器,STL容器在下标越界时会在访问时就出错,不会让程序继续运行;

2、使用RAII来让申请和释放配对;

3、调试时若想获得更详细的信息,在所有需要用下标的位置都加上检查语句。

C/C++动态分配连续空间,下标越界导致的free():invalid next size问题的更多相关文章

  1. 内存写越界导致破环堆结构引起的崩溃问题定位经验[如报错malloc(): memory corruption或free(): invalid next size]

    前段时间开发的一个后端C模块上线后,线上出core,初始时,因为訪问压力不大,所以崩溃是上线3天左右出现的.当时用gdb跟进调用堆栈并检查源代码,发现出core位置的代码沒有啥问题.因为当时开发任务较 ...

  2. APNS导致消息丢失和发送效率原因

    http://blog.csdn.net/tlq1988/article/details/9612237 首先说明一下,本文只是介绍一些容易被开发者忽视,而导致性能低下问题.并不是介绍如何向苹果设备成 ...

  3. nmap扫描端口导致线上大量Java服务FullGC甚至OOM

    nmap扫描端口导致线上大量Java服务FullGC甚至OOM 最近公司遇到了一次诡异的线上FullGC保障,多个服务几乎所有的实例集中报FullGC,个别实例甚至出现了OOM,直接被docker杀掉 ...

  4. C++——模板、数组类

    1.函数模板:可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计. 声明方法:template<typename 标识符> 函数声明 求绝对值的模板 #in ...

  5. 【KMP算法】字符串匹配

    一.问题 给定两个字符串S(原串)和(模式串)T,找出T在S中出现的位置. 二.朴素算法 当S[i] != T[j]时,把T往后移一位,回溯S的位置并重新开始比较.    (1) 成功匹配的部分(AB ...

  6. C 语言 *** glibc detected *** free(): invalid next size (fast): 0x0000000000be1010 ***

    . . . . . LZ 今天在写一个 Socket 程序的时候使用 malloc(3) 在堆上动态分配了一个结构体的空间,在使用完之后用 free(3) 函数释放空间的时候报 invalid nex ...

  7. Inside of Jemalloc

    INSIDE OF JEMALLOCThe Algorithm and Implementation of Jemalloc author: vector03mail:   mmzsmm@163.co ...

  8. C与C++的区别

    C++与C的区别 1. 动态分配内存 1)C语言 a. malloc函数:在内存的动态存储区中分配一个长度为size的连续空间:       void *malloc(unsigned int siz ...

  9. 笔记整理--Linux多线程

    Unix高级环境编程系列笔记 (2013/11/17 14:26:38) Unix高级环境编程系列笔记 出处信息 通过这篇文字,您将能够解答如下问题: 如何来标识一个线程? 如何创建一个新线程? 如何 ...

随机推荐

  1. 074——VUE中vuex之模块化modules开发实例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. 基于Dlib、OpenCV开发人脸识别程序的开发建议

    前言 在去年十月的时候参加了一个小比赛,做了一个人脸识别程序并很意外地获得省里面的一等奖,视频演示链接在这里,有同学想要做这方面的毕业设计or课程设计,发一篇博客来分享一下当时的开发过程. 视频演示链 ...

  3. DevExpress v18.1新版亮点——ASP.NET篇(三)

    用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress ASP.NET v18.1 的新功能,快来下载试用新版本!点 ...

  4. 多种数据库之间的同步工具SymmetricDS

    代码:https://github.com/JumpMind/symmetric-ds 原理: 通过触发器模式同步时,是将数据库的变化记录到某个系统表中,然后在客户端建立缓冲,并定期将变化push到接 ...

  5. UI基础:target...action设计模式,手势识别器.UIimageview

    使用target..action和delegate设计模式可以实现解耦.使代码更加优化. 手势识别器: 手势识别器:是对触摸事件做了封装,无需自己去判断某个手势是否触发,手势识别器本身起到了识别作用, ...

  6. Texas Instruments matrix-gui-2.0 hacking -- generate.php

    <?php /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistrib ...

  7. Size类型如何调用和定义

    cv::Size sz = cv::Size(PROB_W, PROB_H);//Size(srcimage.cols, srcimage.rows) groundtoimage(xylimit, u ...

  8. bug20170125

    1s定时请求接口,接口不响应(接口挂掉),浏览器崩溃

  9. Android中对文件的读写进行操作

    1. 在文件的地方生成一个read.txt文件,并且写入一个read数据.IO流用完之后一定要记得关闭. 对于try和catch是对于错误的抓取. 2. 首先先new file来找到那个文件,然后在通 ...

  10. 在VM上安装centOS后的网络配置

    花了点时间,研究了下VM上的linux虚拟机的网络配置问题.1.环境主机:winXP SP2,家庭宽带,局域网连到路由器,ip地址为192.168.1.101. 虚拟机:centOS(redhat l ...