前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C语言入坑指南-缓冲区溢出

C语言入坑指南-缓冲区溢出

作者头像
编程珠玑
发布2019-09-03 10:56:14
1.6K0
发布2019-09-03 10:56:14
举报
文章被收录于专栏:编程珠玑编程珠玑

前言

缓冲区溢出通常指的是向缓冲区写入了超过缓冲区所能保存的最大数据量的数据。如果说之前所提到的一些问题可能只是影响部分功能的实现,那么缓冲区溢出将可能会造成程序运行终止,被不安全代码攻击等严重问题,因此我们不得不特别重视。

一个缓冲区溢出的例子

对于下面的程序:

代码语言:javascript
复制
#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中。 运行程序,结果如下:

代码语言:javascript
复制
0123456789
*** stack smashing detected ***: ./buff terminated
已放弃 (核心已转储)

可以看到,由于p所指向的字符串长度大于buff的长度,拷贝时由于缓冲区溢出而破坏了栈中的内容而导致程序异常终止。

实际上,有时候缓冲区溢出导致程序马上运行出错是幸运的,因为我们至少能够知道这里出错了。而不幸的情况是,如果超出buff的部分存储在了栈帧不属于它自己的位置,即覆盖了栈帧上存储的其他信息,就有可能导致程序在其他位置出错,造成问题难以定位。

当然也有很幸运的时候,那就是超出buff的部分存储在了未被使用的栈空间上。但是我们绝对不可以对此抱有侥幸心理。

如何避免

对于前面所示的例子中,我们可以很明显地看到要拷贝的字符串长度大于buff的长度,我们可以选择将buff的长度增大。但是实际编程中,我们经常难以察觉是否会超过缓冲区大小。 比如,对于gets函数:

代码语言:javascript
复制
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

其中推荐使用的函数特点是,限定了操作内容的大小,从而避免了缓冲区溢出。当然,可能也会带来另外一个问题,就是截断。 我们修改一下前面的程序:

代码语言:javascript
复制
#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;
}

运行结果如下:

代码语言:javascript
复制
01234567

可以看到,虽然部分字符串没有被拷贝,但是避免了缓冲区溢出,程序不再异常终止。

总结

缓冲区溢出造成的危害非常大,可能导致程序运行终止或程序运行异常且难以定位问题。当然有时候,也能够正常运行,但我们不能够抱有侥幸心理。因此在实际编程中,尽量选择那些更加安全的函数来避免缓冲区溢出。而有些时候并不一定有更加安全的函数可替代,这种时候,我们需要自己特别关注。

思考

以下代码有什么问题:

代码语言:javascript
复制
char buff[10];
strcpy(buff,"0123456789");
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-11-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程珠玑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一个缓冲区溢出的例子
  • 如何避免
  • 总结
  • 思考
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档