C语言入坑指南-缓冲区溢出
前言
缓冲区溢出通常指的是向缓冲区写入了超过缓冲区所能保存的最大数据量的数据。如果说之前所提到的一些问题可能只是影响部分功能的实现,那么缓冲区溢出将可能会造成程序运行终止,被不安全代码攻击等严重问题,因此我们不得不特别重视。
一个缓冲区溢出的例子
对于下面的程序:
#include <stdio.h>
#include <string.h>
int main(void)
{char buff[8] = {0};char *p = "0123456789";strcpy(buff,p);printf("%s\n",buff);return 0;
}
定义一个字符数组buff,数组长度为8,使用strcpy函数将p所指向的字符串常量拷贝到buff中。
运行程序,结果如下:
0123456789
*** stack smashing detected ***: ./buff terminated
已放弃 (核心已转储)
可以看到,由于p所指向的字符串长度大于buff的长度,拷贝时由于缓冲区溢出而破坏了栈中的内容而导致程序异常终止。
实际上,有时候缓冲区溢出导致程序马上运行出错是幸运的,因为我们至少能够知道这里出错了。而不幸的情况是,如果超出buff的部分存储在了栈帧不属于它自己的位置,即覆盖了栈帧上存储的其他信息,就有可能导致程序在其他位置出错,造成问题难以定位。
当然也有很幸运的时候,那就是超出buff的部分存储在了未被使用的栈空间上。但是我们绝对不可以对此抱有侥幸心理。
如何避免
对于前面所示的例子中,我们可以很明显地看到要拷贝的字符串长度大于buff的长度,我们可以选择将buff的长度增大。但是实际编程中,我们经常难以察觉是否会超过缓冲区大小。
比如,对于gets函数:
char buff[255];
gets(buff);
我们不会知道用户在控制台会输入多少字符,但是可以肯定的是,输入字符很有可能会超过255,甚至字符中包含了可以执行代码的字节编码(当然,编译器和操作系统有很多机制,例如栈随机化,栈破坏检测,限制可执行代码区域等来对抗缓冲区溢出攻击),这个时候,灾难就会发生了。
因此我们不应该使用像gets这样不安全的函数,而选择fgets这样的可替代函数。查看gets函数的手册发现,手册中甚至直言不讳地说道:Never use gets()。
同样的,库函数中还有一些函数也可能造成缓冲区溢出,我们应该尽量避免使用它们,而选择使用更加安全的版本。
作用 | 不推荐使用函数 | 推荐使用函数 |
---|---|---|
拷贝字符串 | strcpy | strncpy |
字符串比较 | strcmp | strncmp |
字符串连接 | strcat | strncat |
格式化字符串并存入缓冲区 | sprintf | snprintf |
读取字符串 | gets | fgets |
复制字符串 | strdup | strndup |
字符串比较忽略大小写 | strcasecmp | strncasecmp |
其中推荐使用的函数特点是,限定了操作内容的大小,从而避免了缓冲区溢出。当然,可能也会带来另外一个问题,就是截断。
我们修改一下前面的程序:
#include <stdio.h>
#include <string.h>
int main(void)
{char buff[8] = {0};char *p = "01234567890123";strncpy(buff,p,sizeof(buff));printf("%s\n",buff);return 0;
}
运行结果如下:
01234567
可以看到,虽然部分字符串没有被拷贝,但是避免了缓冲区溢出,程序不再异常终止。
总结
缓冲区溢出造成的危害非常大,可能导致程序运行终止或程序运行异常且难以定位问题。当然有时候,也能够正常运行,但我们不能够抱有侥幸心理。因此在实际编程中,尽量选择那些更加安全的函数来避免缓冲区溢出。而有些时候并不一定有更加安全的函数可替代,这种时候,我们需要自己特别关注。
思考
以下代码有什么问题:
char buff[10];
strcpy(buff,"0123456789");
推荐阅读:
C++之旅-string
推荐一款强大的在线编译器
如何理解 Linux shell中“2>&1”?
C语言入坑指南-数组之谜
关注公众号【编程珠玑】,第一时间获取更多原创技术文章
C语言入坑指南-缓冲区溢出相关推荐
- C语言入坑指南-数组之谜
前言 在C语言中,数组和指针似乎总是"暧昧不清",有时候很容易把它们混淆.本文就来理一理数组和指针之间到底有哪些异同. 数组回顾 在分析之前,我们不妨回顾一下数组的知识.数组是可以 ...
- uniapp调用c语言方法,uni-app 入坑指南-web开发
编辑推荐: 本文重点介绍了 uni-app 入坑指南,方便大家更好的了解 uni-app 本篇只讲述 uni-app,不与其他类似框架进行对比 本文来自于博客园,由火龙果软件Alice编辑推荐. 什么 ...
- python这个软件学会能做什么工作-学会Python真的有高收入?盯,请查收这份入坑指南...
学会Python真的有高收入?盯,请查收这份入坑指南 2018-10-10 20:51:00 567点赞 6312收藏 186评论 小编注:想获得更多专属福利吗?金币加成.尊享众测.专属勋章.达人福利 ...
- python web-python web入坑指南
原标题:python web入坑指南 Invest regularly in your knowledge portfolio. Make learning a habit. 自学python web ...
- Rust 入坑指南:鳞次栉比 | CSDN 博文精选
作者 | Jackyzhe 责编 | 屠敏 出品 | CSDN(ID:CSDNnews) 很久没有挖Rust的坑啦,今天来挖一些排列整齐的坑.没错,就是要介绍一些集合类型的数据类型."鳞次栉 ...
- 信息安全之路入坑指南
作者:腾讯安全平台部研发安全团队 riusksk 疫情下的高考已结束,又快到填志愿的时候了,又有不少知青要加入信息安全这个圈子.为了响应组织号召,撰写此文作为信安行业的入坑指南,希望能对刚入圈的同学有 ...
- Camunda BPM工作流引擎入坑指南(一)
Camunda BPM工作流引擎入坑指南 欢迎使用Camunda BPM工作流 入坑说明书 入坑准备工作 BPMN2.0基础 Camunda实战 Camunda BPM Activiti对比 功能快捷 ...
- Rust入坑指南:鳞次栉比
很久没有挖Rust的坑啦,今天来挖一些排列整齐的坑.没错,就是要介绍一些集合类型的数据类型."鳞次栉比"这个标题是不是显得很有文化? 在Rust入坑指南:常规套路一文中我们已经介绍 ...
- Rust入坑指南:核心概念
如果说前面的坑我们一直在用小铲子挖的话,那么今天的坑就是用挖掘机挖的. 今天要介绍的是Rust的一个核心概念:Ownership.全文将分为什么是Ownership以及Ownership的传递类型两部 ...
最新文章
- centos 配置bond_Linux CentOS 7 多网卡配置bond模式 bond1 bond5 bond6
- 有SELinux引起的Apache基于端口的虚拟主机启动失败
- python学习:time、unixtime、string的转换
- 构造方法与重载:定义一个网络用户类,信息有用户 ID、用户密码、 email 地址。在建立类的实例时把以上三个信息都作为构造函数的参数输入
- 解决No version of NDK matched the requested version问题
- js进阶 9-5 js如何确认form的提交和重置按钮
- 声明为数组定义为指针,声明为指针定义为数组
- Windows 下git 与 github 相关联
- Silverlight入门
- 用Python网络爬虫来抓取网易云音乐歌词
- Controller中使用swagger注解的正确姿势
- JVM 垃圾回收机制主要原理
- H5页面唤起指定app或跳转到应用市场
- 关于IE浏览器的一些思路
- java 背单词系统_基于JAVA模拟背单词系统(含源文件)
- 高瓴资本张磊:选择比努力重要,与谁同行比要去的远方重要
- Linux下QProcess不产生finished信号、waitforfinished阻塞超时【defunct进程】
- 计算机毕业设计ssm科技类产品众筹系统9x420系统+程序+源码+lw+远程部署
- 为什么现在真正的黑客越来越少了?
- sas mysql乱码_SAS 数据步 常见错误汇总之1-上
热门文章
- 组合,全排列以及子集超详细讲解
- java加快页面加载速度方法_关于页面加载速度优化的11种方法
- 删除链表中的重复出现的结点,留下只出现一次的结点
- 轻松入门Miniconda及注意事项
- 虚拟机VMware和Ubuntu的安装与配置教程(超详细,实验可行)
- Java案例 遍历字符串
- unity3d之如何控制人物移动、旋转和动画播放
- System.DllNotFoundException:“无法加载 DLL“XXX.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。”
- 高可用NAS集群技术
- 穿墙无忧,大型物联网专属 Zigbee PRO 2017正式推出