作为一个程序员,对内存溢出问题肯定不陌生,它已经是软件开发历史上存在了近40年的大难题。在内存空间中,当要表示的数据超出了计算机为该数据分配的空 间范围时,就产生了溢出,而溢出的多余数据则可以作为指令在计算机中大摇大摆地运行。不幸的是,一不小心这就成了黑客们可利用的秘密后门,“红色代码”病 毒事件就是黑客利用内存溢出攻击企业网络的“经典案例”。甚至有人称,操作系统中超过50%的安全漏洞都是由内存溢出引起的。众所周知,C/C++语言虽 然是一种高级语言,但是其程序的目标代码却非常接近机器内核,它能够直接访问内存和寄存器,这种特性大大提升了C/C++语言代码的性能,同时也提高了内 存溢出问题出现的可能性。内存溢出问题可以说是C/C++语言所固有的缺陷,因为它们既不检查数组边界,也不检查类型可靠性。假设代码申请了X字节大小的 内存缓冲区,随后又向其中复制超过X字节的数据,那么多出来的字节会溢出原本的分配区。最重要的是,C/C++编译器开辟的内存缓冲区常常邻近重要的数据 结构。如果恶意攻击者用“别有用心”的东西刻意地覆盖原本安全可信的数据,那么后果就是此机器将会成为他们肆意攻击的“肉鸡”。下面将介绍常见的缓冲区溢 出,以及预防措施。

C语言中的字符串库没有采用相应的安全保护措施,所以在使用时要特别小心。例如,在执行strcpy、strcat等函数操作时没有检查缓冲区大小,就会很容易引起安全问题。

现在分析下面的代码片段:
const int MAX_DATA_LENGTH = 32;
void DataCopy (char *szSrcData)

  char szDestData[MAX_DATA_LENGTH]; 
  strcpy(szDestData,szSrcData); 
  // processing codes
  ... 
 }
似乎这段代码不存在什么问题,但是细心的读者还是会发其中的危险。如果数据源szSrcDatar的长度不超过规定的长度,那么这段代码确实没什么问题。
strcpy()不会在乎数据来源,也不会检查字符串长度,唯一能让它停下来的只有字符串结束符'\0'。不过,如果没有遇到这个结束符,它就会一个字节
一个字节地复制szSrcData的内容,在填满32字节的预设空间后,溢出的字符就会取代缓冲区后面的数据。如果这些溢出的数据恰好覆盖了后面
DataCopy函数的返回地址,在该函数调用完毕后,程序就会转入攻击者设定的“返回地址”中,乖乖地进入预先设定好的陷阱。为了避免落入这样的圈套,
给作恶者留下可乘之机,当C/C++代码处理来自用户的数据时,应该处处留意。如果一个函数的数据来源不可靠,又要用到内存缓冲区,那么必须提高警惕,必
须知道内存缓冲区的总长度,并检验内存缓冲区。
const int MAX_DATA_LENGTH = 32;
void DataCopy (char *szSrcData, DWORD nDataLen)

  char szDestData[MAX_DATA_LENGTH]; 
       if(nDataLen < MAX_DATA_LENGTH)
        strcpy(szDestData,szSrcData); 
       szDestData[nDataLen] = '\0'; // 0x42;
  // processing code
  ... 
 }
首先,要获得szSrcData的长度,保证数据长度不大于最大缓冲区长度MAX_DATA_LENGTH;其次,要保证参数传来的数据长度真实有效,方
法就是向内存缓冲区的末尾写入数据。因为,当缓冲区溢出时,一旦向其中写入常量值,代码就会出错,终止运行。与其落入阴谋家的陷阱,还不如及时终止程序运
行。虽然上述方法能够有效地降低内存溢出的危害,却不能从根本上避免对内存溢出的攻击。所以在调用 strcpy、strcat、gets
等经典函数时,你要从源代码开始就提高警惕,尽量追踪传入数据的流向,向代码中的每一个假设提出质疑,包括对那些所谓相对安全可靠的改良版N-
Versions(strncpy

strncat)也不可轻信。访问边界数据同样可能引起缓冲区溢出。在这种情况下的内存溢出不会像第一种那么危险,但同样令人讨厌。就如下面的代码片段:
const int DATA_LENGTH = 16;
Int data[16] = {1,9,8,4,0,9,1,7,1,9,8,7,0,3,0,9};
void PrintData()
{
for(int i=0; data[i]!=0&&i<DATA_LENGTH; i++)
{
cout<<data[i])<<endl;
}
}
这也是一个隐藏很深、难以发现的问题:当i==16的时候,在判断i<
DATA_LENGTH的同时需要判断data[16]。而data[16]已经访问到了非法区域,可能引起缓冲区溢出。正确的方式应该是不要将索引号i
与数据本身data[i]的判断放在一起,而是将判断条件分成两句:
const int DATA_LENGTH = 16;
int data[16] = {1,9,8,4,0,9,1,7,1,9,8,7,0,3,0,9};
void PrintData()
{
for(int i=0; i<DATA_LENGTH; i++)
{
if(data[i]!=0)
cout<<data[i])<<endl;
}
}

类似的问题还有可能发生在访问未初始化指针或失效指针时。未初始化的指针和失效后未置NULL的指针指向的是未知的内存空间,所以对这样的指针进行操作很有可能访问或改写未知的内存区域,也就可能引起缓冲区溢出的问题了。


请记住:因为内存溢出潜在的危害很大,所以必须注意和面对这个问题,特别是在
网络相关的应用程序中。在调用C语言字符串经典函数(如strcpy、strcat、gets
等)时,要从源代码开始就提高警惕,尽量追踪传入数据的流向,向代码中的每一个假设提出质疑。在访问数据时,注意对于边界数据要特殊情况特殊处理,还要对
杜绝使用未初始化指针和失效后未置NULL的“野指针”。

 
原文:http://blog.csdn.net/baliguan163/article/details/11476535

改善C++ 程序的150个建议学习之建议7:时刻提防内存溢出的更多相关文章

  1. 改善c++程序的150个建议(读后总结)-------0-9

    0. 不要让main 函数返回 void 入口函数main()返回类型应该为 int, 即程序结束时return 0 表示程序正常返回,函数结束时 return -1 值表示程序异常返回, 如果不显式 ...

  2. 编写高质量代码_改善C++程序的150个建议 读书笔记

    这几天看了下这本书<编写高质量代码_改善C++程序的150个建议>,觉的蛮有收获的,再次记录下自己以前不清晰的知识点,以供学习. 编写符合标准的main函数 C语言标准规定了main函数的 ...

  3. Java基础学习总结(30)——Java 内存溢出问题总结

    Java中OutOfMemoryError(内存溢出)的三种情况及解决办法 相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各 ...

  4. JMeter学习(二十八)内存溢出解决方法(转载)

    转载自 http://www.cnblogs.com/yangxia-test 使用jmeter进行压力测试时遇到一段时间后报内存溢出outfmenmory错误,导致jmeter卡死了,先尝试在jme ...

  5. 改善c++程序的150个建议(读后总结)-------19-26

    19. 明白在c++中如何使用c c++可以兼容c的绝大部分代码,但是还是有一部分不能兼容. c语言的编译器在调用函数时会把函数翻译成 : "_函数名",例如: int nasa( ...

  6. 改善c++程序的150个建议(读后总结)-------12-18

    12.优先使用前置操作符 #include <iostream> using namespace std; class A { private: int num; public: A op ...

  7. 改善c++程序的150个建议(读后总结)-------10-11

    10. 优化结构体中元素的布局 结构体变量所占空间大小并不是其所含类型所占字节数之和,其所占内存字节数涉及到字节对齐. 字节对齐 :变量在内存中储存都是以字节数为单位,每一个字节都有自己的地址,逻辑上 ...

  8. 改善c++程序的150个建议(读后总结)-------27-35

    27. 区分内存分配的方式 c++中内存分为5个不同的区 ①栈区 栈是一种特殊的数据结构,其存取数据特点为(先进后出,后进先出).栈区中主要用于存储一些函数的入口地址,函数调用时的实参值以及局部变量. ...

  9. 编写高质量代码改善python程序91个建议学习01

    编写高质量代码改善python程序91个建议学习 第一章 建议1:理解pythonic的相关概念 狭隘的理解:它是高级动态的脚本编程语言,拥有很多强大的库,是解释从上往下执行的 特点: 美胜丑,显胜隐 ...

随机推荐

  1. 用ESP8266+android,制作自己的WIFI小车(ESP8266篇)

    整体思路ESP8266作为TCP服务器,,手机作为TCP客户端,自己使用Lua直接做到了芯片里面,省了单片机,,节约成本,其实本来就是个单片机(感觉Lua开发8266真的很好,甩AT指令好几条街,,而 ...

  2. 怎样让oracle实验本在不做实验时性能提升——win7下举例

    怎样让oracle实验本在不做实验时性能提升--win7下举例 型号:ThinkPad E431 系统:WIN7 实验使用的笔记本不使用数据库时.建议将oracle关闭,使其释放占用的资源. orac ...

  3. 20155318 《网络攻防》 Exp8 Web基础

    20155318 <网络攻防> Exp8 Web基础 基础问题 什么是表单? HTML表单用于收集用户输入,用元素定义,包含不同类型的input元素.复选框.单选按钮.提交按钮等等.一个表 ...

  4. Luogu P1726 上白泽慧音

    这显然是一道求强连通分量(SCC)的题目. 只要你正常,都知道应该写Tarjan. 然后(假装会写Tarjan),其实我当然不会.但是求SCC还有另一个算法.复杂度和Tarjan一样,只不过常数大了点 ...

  5. [Oracle]查看数据是否被移入 DataBuffer 的方法

    查看数据是否被移入 DataBuffer 的方法: 例如:表名为 tabxxx, 用户为U2: SQL> grant dba to u2 identified by u2;SQL> con ...

  6. PostgreSQL内部结构与源代码研究索引页

    磨砺技术珠矶,践行数据之道,追求卓越价值 luckyjackgao@gmail.com 返回顶级页:PostgreSQL索引页 本页记录所有本人所写的PostgreSQL的内部结构和源代码研究相关文摘 ...

  7. python 实现分治法的几个例子

    分治法所能解决的问题一般具有以下几个特征: 1) 该问题的规模缩小到一定的程度就可以容易地解决 2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质. 3) 利用该问题分解出的子 ...

  8. Ubuntu 守护进程

    项目中用的Qt开发的GUI程序,需要随机自启动. 最初尝试过使用SuperVisor,但是会出现下面的错误. qt.qpa.screen: QXcbConnection: Could not conn ...

  9. 【第三课】Centos 7.x系统安装和网络配置以及远程密钥登录

    目录 一.安装CentOS 7.3 二.配置网络 1.使用dhclient命令自动获取ip地址 2.使用ip addr或ifconfig命令查看网卡信息 3.使用route命令查看路由信息 4.通过修 ...

  10. VS相关

    快速显示函数名称 ctrl+alt+T 显示函数参数说明 ctrl+shift+space,光标放在函数里面 link 1123错误,vs2010的问题. 点击工程-属性-ManifestTool-I ...