安全堆栈(堆栈损坏)

堆栈损坏是令人烦恼的 bug。由于堆栈已损坏,调试器通常无法为你提供良好的堆栈跟踪,指出你的位置以及如何到达目的地。

这就是安全堆栈发挥作用的地方。它不使用单个堆栈用于你的线程,而是使用两个:安全堆栈和危险堆栈。安全堆栈的工作原理与之前完全相同,只是某些部件被移动到危险的堆栈中。

堆栈的哪些部分被移动?

每一个有可能破坏堆栈的部分都会被移出安全堆栈。一旦堆栈上的变量通过引用传递或者获取此变量的地址,编译器将决定在第二个堆栈而不是安全堆栈上分配它。

因此,对这些指针执行的任何操作,对内存进行的任何修改(基于那些指针/引用)都只能影响第二个堆栈中的内存。由于永远不会得到一个靠近安全堆栈的指针,堆栈不能破坏堆栈,调试器仍然可以读取堆栈上的所有函数以提供良好的跟踪。

实际使用的是什么?

安全堆栈不是为了给你更好的调试体验而发明的,但是,这对于讨厌的 bug 来说是一个很好的副作用。它的最初目的是作为代码指针完整性(CPI)项目的一部分 ,在该项目中,它们试图阻止覆盖返回地址以防止代码注入。换句话说,他们试图阻止执行黑客代码。

出于这个原因,该功能已在 Chrome 上激活,据报道其 CPU 开销<1%。

如何启用它?

现在,该选项仅在 clang 编译器中可用,其中可以将 -fsanitize=safe-stack 传递给编译器。一个建议是为了实现在 GCC 相同的特征。

结论

启用安全堆栈时,堆栈损坏可以变得更容易调试。由于性能开销较低,你甚至可以在构建配置中默认激活。