编译器是否在析构函数中优化memset?

Mar*_*ica 3 c++ optimization

给定一个结构:

struct CryptoKey {
    std::vector<unsigned char> key;
    ~CryptoKey() { memset(key.data(),0,key.size()); }
};
Run Code Online (Sandbox Code Playgroud)

编译器有权取消调用,memset因为这样可以节省时间,并且没有定义行为的程序可以区分.(假设key析构函数返回后该变量将不复存在.)

然而,像这样的代码在加密应用程序中很有用,因为秘密存储在内存中的时间越少,攻击者提取它的机会就越少.(memset它不提供安全性,但确实提供了"纵深防御".)

我的问题是,它真正的编译器实际上消除这样的memset电话(显然,与优化开启)?

and*_*vin 7

也许最好说好的编译器会尝试消除memset调用,开发人员不应该依赖编译器实现的差异来避免这种优化.这些编译器通常具有无法优化的安全替代方案.

memset的安全版本

C11引入了memset_s,其中一个特性是不会被优化出来的.

与memset不同,任何对memset_s函数的调用都应严格按照(5.1.2.3)中描述的抽象机的规则进行评估.也就是说,对memset_s函数的任何调用都应假定s和n指示的内存在将来可以访问,因此必须包含c所指示的值.

特定于Windows

在Windows上还有其他选择. SecureZeroMemory或使用#pragma optimize编译指示关闭优化.

常见的子表达式优化

密码安全存在一个更广泛的问题:出于优化原因,编译器有权复制缓冲区.归零可能不会删除所有副本,编译器可能已应用优化,将堆复制到堆栈以消除常见的子表达式.因此,除了避免优化归零之外,还应注意编译器不插入额外的副本.