拷贝构造函数和拷贝赋值运算符安全漏洞分析(引用)
l 概述
在c++语言程序设计中,如果某个类的对象持有动态分配的内存资源,但是程序员却没有为该类定义拷贝构造函数和拷贝赋值运算符,则当对象拷贝构造(新对象尚未存在)和对象拷贝赋值(对象已经存在)时,编译器会为该类自动生成上述两个函数。但是自动生成的函数只具有按位拷贝复制语义功能,这样会给程序带来安全隐患,可能出现内存泄漏、重复释放内存等诸多问题。如果程序员定义了拷贝构造函数和拷贝赋值运算符中任何一个,就意味着程序员放弃了默认的按位拷贝复制语义。通常情况下的初始化复制和对象存在情况下的状态复制总是遵循相同的操作方式,因此如果程序员重新定义了其中任何—个函数,而未定义另外一个,就无法保证复制语义的一致性。如果程序员对拷贝构造函数和拷贝赋值运算符定义不恰当,就有可能出现对象复制语义错误等问题。
2 漏洞表现
漏洞的主要表现形式分为以下三类:
(1)拷贝构造函数和拷贝赋值运算符未被定义。
(2)拷贝构造函数和拷贝赋值运算符定义不配对。
(3)拷贝构造函数和拷贝赋值运算符定义不恰当。
3 典型漏洞实例分析与建议
在拷贝构造函数和拷贝赋值运算符安全漏洞的主要表现形式中, “拷贝构造函数和拷贝赋值运算符定义不恰当” 会引起对象复制语义错误等问题。本节为这一类漏洞表现形式设计并分析了一个漏洞实例——拷贝赋值运算符中内存释放和重分配操作不当。
3.1漏洞描述
当使用拷贝构造函数拷贝构造对象时,因为新对象还未存在,所以不用释放和重新分配内存资源。而当使用拷贝赋值运算符对对象执行拷贝赋值操作时,因为新对象已经构造完毕,所以该函数的定义中必须对被赋值对象执行释放和重新分配内存的操作。如果拷贝赋值运算符未准确地执行上述操作,就会导致内存泄漏和重复释放内存等错误。
3.2漏洞实例
实例1:未对被赋值对象执行释放和重新分配内存的操作,而是直接采用对其数据成员赋值的方式进行赋值操作。
实例2:对被赋值对象执行了释放内存操作,但是未对其重新分配内存
实例3:未对被赋值对象执行释放内存操作,但却对其重新分配了内存
3.3漏洞原因分析’
在实例1中,程序员在实现String类的拷贝赋值运算符时没有对被赋值对象执行释放和重新分配内存的操作,当main()函数执行到语句”s2=sl;”时,sl内部数据指针指向的字符串的长度超出了对象s2被分配的堆内存空间所能容纳酌范围,从而造成数据访问越界错误。在实例2中,程序员在实现String类的拷贝赋值运算符时虽然释放了被赋值对象占有的内存,但却没有为其按照赋值对象的数据大小重新分配内存,造成被赋值对象的内部数据指针不再指向合法的堆空间。当执行字符串复制操作时,程序出现了非法访问内存空间的错误。在实例3中,程序员在实现String类的拷贝赋值运算符时在没有释放被赋值对象占有的内存的情况下,为其重新分配了内存,造成被赋值对象原先持有的堆内存被丢弃,并且再也无法被释放,从而导致内存泄漏。
3.4安全编程建议
如果c++中某个类的对象持有非自动释放的资源(如堆内存空间、UNIX文件描述符)时,程序员应当为该类按照如下顺序实现拷贝赋值运算符:
(1)保存原先的资源。
(2)分配新的资源。
(3)执行句柄赋值操作。
(4)释放原先的资源。
拷贝构造函数和拷贝赋值运算符安全漏洞分析(引用)
最新推荐文章于 2022-12-09 16:43:38 发布