记录一次C语言中free(p)失败
首先介绍一下自己的程序出错的原因,然后总结一下什么时候free会失败。
1.程序伪代码
// 已知payload已经指向一部分内存数据
char * payload;
int payload_len; //payload的长度 char * front_pkt="xxxxxxxxx"; // 申请内存
char * temp_ptr=(char *); malloc(payload_len+strlen(front_pkt)+1);// 多申请一位放\0
memset(temp_ptr,0,payload_len+strlen(front_pkt)+1); // 拷贝
strcat(temp_ptr,front_pkt);
strcat(temp_ptr,payload); // 错误原因就发生在这里
... // 释放
free(temp_ptr);//报错的地方
定位过程:
由于是和别的程序联调,首先定位出事free()函数时报的错。然后就开始从为指针申请内存的地方开始定位,最后发现,在strcat(temp_ptr,payload)之后,指针temp_ptr指向的数据竟然比我申请的内存要大,尾部有一部分杂数据。至此,发现是内存越界了。
为什么会越界呢?因为payload并不能保证是字符串,即不能保证是符号'\0'结尾的。在使用strcat追加拷贝字符串时是根据'\0'符号来判断拷贝结束的。所以非常有可能发生内存越界的行为。
修改方案:使用strncat()函数,指定拷贝的长度。
定位心得:
1.在使用C语言的字符串函数时,str开头的,一定要确保指针指向的内存是字符串,即'\0'结尾。
2.尽量使用带n的函数,指定内存、字符串拷贝等的长度,可以避免不必要的麻烦。
总结:什么时候free(p)会报错?
1.如果p不是NULL指针,对p连续操作两次就导致程序运行错误
2.内存越界,指针初始值被修改掉,和别的区块内存重叠,分配的这段内存的“门牌号”被改掉了,free就会失败。比如上边的例子。
引申:free的原理
free(p)释放p指向的内存时,并不需要提供要释放内存的大小,这是因为在p附近的某个位置存放有维护该内存区域的数据,这是由内存申请函数malloc等产生的。实际上在p之前有个结构体,记录了该块内存的信息。如果程序因为内存越界修改了结构体,则会导致free()函数报错返回,并不释放任何内存。
以上边的例子,strcat(temp_ptr,payload),向申请的内存中拷贝了过多的数据。
注:由于知识有限,本文所讲必定有缺陷之处,请谨慎参考,如有错误之处,请批评指正!
记录一次C语言中free(p)失败的更多相关文章
- Java 语言中 Enum 类型的使用介绍
Enum 类型的介绍 枚举类型(Enumerated Type) 很早就出现在编程语言中,它被用来将一组类似的值包含到一种类型当中.而这种枚举类型的名称则会被定义成独一无二的类型描述符,在这一点上和常 ...
- ZH奶酪:C语言中malloc()和free()函数解析
1.malloc()和free()的基本介绍 (1)函数原型及说明 void *malloc(long NumBytes) 该函数分配了NumBytes个字节,并返回了指向这块内存的指针.如果分配失败 ...
- C语言中setjmp与longjmp学习笔记
C语言中setjmp与longjmp学习笔记 一.基础介绍 头文件:#include<setjmp.h> 原型: int setjmp(jmp_buf envbuf) ,然而longjm ...
- C语言中 malloc函数用法
一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...
- Java语言中:float、double数据类型在内存中是如何存储的
引用参考 https://www.cnblogs.com/chenmingjun/p/8415464.html#4291528 https://blog.csdn.net/yansmile1/arti ...
- c语言中的malloc函数
少壮不努力,大一的时候c语言学得不扎实,最近学数据结构的时候看到c语言中malloc函数都不知道了,这里记录一下,避免以后再忘. malloc的全称是memory allocation,中文叫动态内存 ...
- C语言中 malloc
参考:https://blog.csdn.net/kokodudu/article/details/11760863 一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: ...
- C语言中,头文件和源文件的关系(转)
简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程: 1.预处理阶段 2.词法与语法分析阶段 3.编译阶段,首先编译成纯汇编语句, ...
- C 语言中 setjmp 和 longjmp
在 C 语言中,我们不能使用 goto 语句来跳转到另一个函数中的某个 label 处:但提供了两个函数——setjmp 和 longjmp来完成这种类型的分支跳转.后面我们会看到这两个函数在处理异常 ...
随机推荐
- 腾讯技术团队整理,为什么 Flutter 能最好地改变移动开发
导语 | Flutter 框架是当下非常热门的跨端解决方案,能够帮助开发者通过一套代码库高效构建多平台精美应用,支持移动.Web.桌面等多端开发.但仍然有很多产品.设计.甚至开发同学并不了解 Flut ...
- 网络图片下载,commons IO包
网络图片下载,commons IO包 导入commons-io包 commons-io包下载路径: http://www.apache.org/ 项目下新建lib包,将lib包添加为库 实现多线程下载 ...
- 【前端 · 面试 】HTTP 总结(十二)—— URL 和 URI
最近我在做前端面试题总结系列,感兴趣的朋友可以添加关注,欢迎指正.交流. 争取每个知识点能够多总结一些,至少要做到在面试时,针对每个知识点都可以侃起来,不至于哑火. 引言 不知道有多少人是和我一样分不 ...
- SpringBoot开发九-生成验证码
需求介绍-生成验证码 先生成随机字符串然后利用Kaptcha API生成验证图片 代码实现 先在pom.xml引入 <dependency> <groupId>com.gith ...
- sqli-labs lesson 46-53
写在前面: 关于 order by 例: select * from users order by 1 ; 将users表中的第1列按照从小到大依次排列 select * from users o ...
- sqli-labs lesson1-4
写在前面: 前四关基本都是基于GET的SQL注入 在Mysql中有一个系统数据库information_schema,存储着所有数据库的相关信息,一般利用这个数据库进行SQL注入. 因为大部分的注入需 ...
- SpringBoot集成websocket(Spring方式)
SpringWebSocketConfig配置 package com.meeno.chemical.socket.task.config; import com.meeno.chemical.soc ...
- COM笔记-包容与聚合
COM不支持实现继承的原因在于这种继承方式将使得一个对象的实现同另外一个对象的实现紧紧地关联起来.在这种情况下,当基类的实现被修改后,派生类将无法正常运行而必须被修改.这就是为什么一些用C++编写大型 ...
- Qt迭代器(Java类型和STL类型)详解
迭代器为访问容器类里的数据项提供了统一的方法,Qt 有两种迭代器类:Java 类型的迭代器和 STL 类型的迭代器. 两者比较,Java 类型的迭代器更易于使用,且提供一些高级功能,而 STL 类型的 ...
- C# 线程同步的多种方式
实际应用中多个线程往往需要共享数据,因此必须使用同步技术,确保一次只有一个线程访问和改变共享数据.同步又分为进程内部线程的同步以及进程之间线程的同步. 进程内部线程同步: 1. lock : 使用比较 ...