关于 C++ 迭代器失效特性的研究
一、前言 在C++中,迭代器(Iterator)是一种用于遍历容器中元素的对象(如数组、向量、列表等)。它提供了一种统一的访问容器元素的方式,无论容器的类型和实现细节如何,比如list,vector,map等虽然实现不同,但最终都可以通过迭代器来访问和操作容器中的元素。 迭代器的工作方式类似于指针,它可以指向容器中的特定位置,并允许你在容器中前进或后退。通过使用迭代器,你可以遍历容器中的所有元素,执行读取、修改或删除操作。 二、迭代器的几种常见使用方式 Range-Base-For形式 for(auto& it : its_){ [...] } 直接迭代器形式 auto it = its_.begin() it.next() 循环形式 for(it = its_.begin();it!= its_.end();it++){ [...] } 三、序列式容器 3.1 Vector失效 首先先来介绍一下Vector的结构,Vector 是C++标准程序库中的一个类,可视为会自动扩展容量的数组,以循序(Sequential)的方式维护变量集合。 失效原因:容器发生内存重分配后,或者有删除或者插入操作 失效前提:有删除或者插入操作。 失效情况: 容器内存经过push_back 后重新分配,迭代器的指针还是指向原来的内存,导致迭代器、引用、指针都失效。如果是插入且没有重新分配,只会使后面的元素失效。 如下例,定义了一个Vector,并对其进行循环迭代。 std::vector<int> vec_; vec_.push_back(1); vec_.push_back(2); for(auto & it : vec_){ vec_.push_back(3); std::cout<<it<<std::endl; } 在运行完两个push_back进行元素的添加后,此时Vector的内存: std::vector<int> vec_; vec_.push_back(1); vec_.push_back(2); --------------------- vec_: 0x7fffffffdcc0: 0x0000602000000030[start] 0x0000602000000038[finish] 0x7fffffffdcd0: 0x0000602000000038[end] 0x00007ffff7f953f8 ---------------------- 然后在进行迭代时,对其进行元素添加,超过其容量导致空间重分配。[*]的位置就是Vector的首地址,可以清楚看见此时的地址已经为重新分配后的地址了,原地址已经被释放。然后在运行输出语句后导致UAF。 for(auto & it : vec_){ vec_.push_back(3); ---------------------------- 0x7fffffffdcc0: 0x0000602000000050[*] 0x000060200000005c 0x7fffffffdcd0: 0x0000602000000060 0x00007ffff7f953f8 //原先的内存被释放,重新申请新空间。此时迭代器it 引用的地址 //pwndbg> p &it //$9 = (int *) 0x602000000030 ---------------------------- std::cout<<it<<std::endl; ---------------------------- ==2386378==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000030 at pc 0x5555556329fe bp 0x7fffffffdc90 sp 0x7fffffffdc88 READ of size 4 at 0x602000000030 thread T0 ----------------------------- } 容器内元素erase后,在其后面的元素都会往前移,导致其后面的元素都失效。(不可利用)...