C编写的程序可能产生的主要缺陷

摘自:软件静态分析工具评析 王 凯,孔祥营

空指针引用、悬空指针、资源泄露、函数返回值、使用未初始化变量、无限循环、死亡代码、缓冲区溢出、野指针等。

1)空指针引用

空指针引用会导致程序崩溃。空指针引用的情况包括:
①忘记对指针为NULL 的情况进行判断;
②虽然对指针是否为NULL 进行了判断,但没能正确处理好。

2)缓冲区溢出

缓冲区溢出是最常见的安全漏洞,包括静态溢出和动态溢出。静态溢出主要指数组或指针的索引为常量情况下的越界,导致内存冲突,给黑客攻击提供了可乘之机,主要包括栈溢出、堆溢出、数据段溢出、BSS 溢出和共享内存溢出;动态溢出主要是数组或指针的索引在动态访问内存的时候越界,由于C 语言固有的不安全性,数组或指针的索引不会自动去做边界检查,因此缓冲区溢出的情况非常普遍,所以程序员在用C 语言编写代码时有必要检查索引是否在有效区
间内,但在复杂的函数调用和数据流传递中,这项工作变得异常复杂。

3)悬空指针

悬空指针是由于使用了已经释放的内存资源造成的。引用已释放的指针是非常危险的,因为指针的值不确定或者指针指向任意内存的位置。为了避免悬空指针,必须在最后的引用释放后再删除对象。

4)资源泄漏

资源泄漏是程序离开了指针的作用域后,仍没有释放指针占用的资源造成的。资源泄漏包括内存泄漏、文件句柄泄漏和网络套接字泄漏。
严重的内存泄漏能导致进程崩溃,即便是很小的内存泄漏,在系统长时间运行没有重启后,也会产生错误。文件句柄或者网络套接字的泄漏会导致程序崩溃、拒绝服务攻击或者打开其他文件或套接字失败。操作系统通常会限制进程的文件句柄和套接字个数。当达到限制的最大值时,进程要申请新的资源时,首先要关闭一些已打开的资源。如果进程中存在资源泄
漏,进程自己将没有办法回收这些资源,除非强行终止该进程。
多数情况下,这些泄漏通常发生在某个错误的路径,比如说,某个异常处理的分支。这种情况下,正确的做法应该是将程序跳转到该函数的出口,出口处应释放这些资源。

5)函数返回值

函数返回值错误主要包括函数遗漏返回值和函数返回值可能为空或为局部变量的地址或为负整数。函数返回值使用前,一定对其值进行判断。如果为空,对其非法引用将会导致程序崩溃;如果为负整数,在作为数组索引、循环标志变量、申请内存大小的参数等情况下要检查函数返回值的正确性,负整数的错误使用会导致如死循环、数组越界(内存冲突)、变量溢出等严重的问题;如果是局部变量的地址,在C 语言中,当被调用函数执行完毕,其所有的局部变量就
不再有效,因此将会引起内存冲突和不确定的行为;在返回类型为非void 的函数中,值没有被返回,比较常见的情况是,在不同的分支要返回不同的值,结果有一个分支漏了返回值。

6)使用未初始化变量

变量在使用前没有初始化。堆栈中的变量如果没有初始化,将没有固定的数值。使用了没有初始化的变量会导致不可预测的行为,或安全漏洞。

7)无限循环

程序中有不能终止的循环,会导致程序挂起或者崩溃。当然在多任务的程序中,故意设计的“死循环”除外。

8)不可达代码

由于条件判断总是TRUE 或FALSE,导致一个分支内的代码永远执行不到,这些永远都执行不到的代码称为不可达代码。不可达代码一般是由逻辑错误引起的。在情况严重时,这些逻辑错误可能导致重要的代码永远不能执行,造成严重的后果。

9)野指针

野指针不是NULL 指针,是指向“垃圾”内存的指针。产生野指针主要有两个方面的原因:
①指针变量未被初始化。任何指针刚创建时不会自动成为NNLL 指针,而是随机的,它会乱指一气。故指针创建时应当初始化,要么将指针设置为NULL,要么让它指向合法的内存。
②指针p 被free 或delete 后,没有设置为NULL。这样让人误以为p 是合法的指针,其实free 或delete仅把p 所指向的内存释放掉,但并没把指针p 本身释放(仍指向原来的地址)。通常用if(p!=NULL)进行防错处理,但是很遗憾,此if 语句根本起不到防错的作用,因为即使p 不是NULL,它也不指向合法的内存块。
另外不要将指针或引用指向栈内存,因为栈内存
在函数结束时会被释放。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章