vector::at()越界抛std::out_of_range异常,operator[]越界导致未定义行为;越界读可能泄露数据,越界写会破坏内存;未触发SIGSEGV不等于安全,因越界可能落在可访问内存页内。
C++ 标准库 std::vector 对越界访问不做强制检查,但提供两种不同策略:operator[] 完全不检查,at() 会抛出 std::out_of_range 异常。
这导致同一段越界代码在不同写法下表现截然不同:

v[i](i ≥ v.size())→ 未定义行为(UB),可能读到垃圾值、崩溃,也可能“恰好”没出事 v.at(i)(i ≥ v.size())→ 立即抛异常,便于定位问题 实际开发中,operator[] 常用于性能敏感路径(如内层循环),但一旦索引逻辑有误,错误会隐藏得很深;而 at() 更适合调试期或用户输入驱动的索引场景。
越界访问不是“都一样危险”,读和写的后果差异极大:
v[i] 取值,i 超出范围):可能泄露栈上相邻变量、返回随机整数、触发段错误,但一般不破坏程序控制流 v[i] = x,i 超出范围):直接覆写内存,可能覆盖: vector 自身的元数据(如 size 或 capacity 字段,若内存布局紧凑且编译器未 padding) 尤其注意:即使 vector 数据在堆上分配,其内部指针(_M_start 等)仍在栈/对象内,越界写可能先破坏这些指针,再引发二次崩溃。
SIGSEGV 不是“越界就来”,而是“访问了操作系统标记为不可读/不可写的页”。关键点在于:
vector 的底层内存通常由 new 分配,连续一页或多页堆内存,相邻地址大概率可读可写 top chunk 后空隙) mprotect 设为 PROT_NONE) 换句话说:没崩溃 ≠ 没问题,反而更危险——你无法靠 crash 发现它。
真实攻击不依赖 vector,但原理相通:攻击者通过可控输入诱导越界写,篡改关键内存。例如:
vector ids ,又用未经校验的索引执行 ids[user_input] = new_val user_input(如 0x7fffffffffff),使指针计算后指向返回地址附近 vector 对象与函数返回地址在栈上紧邻(取决于编译器布局、优化等级),一次越界写就可劫持控制流 现代防护(ASLR、stack canary、W^X)大幅增加难度,但 vector 越界仍是内存破坏类漏洞的常见入口点——尤其在禁用异常、关闭 sanitizer 的生产构建中,它几乎不留痕迹。