explicit_bzero
explicit_bzero
是一个为了解决 memset
在安全清除内存场景中可能被优化器移除的问题而设计的函数,广泛用于安全编程中,比如密码、密钥清除等。
Introduce
头文件
#include <string.h>
函数原型
void explicit_bzero(void *s, size_t n);
功能说明
将内存区域 s
开始的 n
个字节强制清零(写入 0
),确保不会被编译器优化掉。
为什么不能用 memset
?
当你写:
char key[32];
// ... 使用 key ...
memset(key, 0, sizeof(key));
有些编译器会发现 key
后面就不再使用,于是优化器会移除 memset 调用,导致密码/密钥未被真正擦除,造成信息泄露风险。
explicit_bzero
的实现避免了这一问题:
- 使用
volatile
指针或编译器 barrier; - 或直接调用外部函数(编译器无法内联);
- 保证操作不可优化,满足安全清除需求。
可用平台
平台 | 是否支持 explicit_bzero |
---|---|
✅ FreeBSD | 原生支持 |
✅ OpenBSD | 原生支持(首发平台) |
✅ glibc >= 2.25(2017) | 支持 |
✅ macOS 10.12+ | 可用 |
🚫 Windows | 不支持(用 SecureZeroMemory ) |
用法示例
#include <string.h>int main() {char secret[32] = "TopSecretPassword123!";// 使用 secret 做某些操作...// 清除 secret(防止泄露)explicit_bzero(secret, sizeof(secret));return 0;
}
📌 即使 secret
后续没有再用,这个清除也不会被优化掉!
与 bzero
区别?
函数 | 是否会被优化器移除 | 是否已废弃 | 推荐使用 |
---|---|---|---|
memset | ✅ 有风险 | 否 | ❌ 不用于清除敏感数据 |
bzero | ✅ 有风险 | ✅ 已废弃(非标准) | ❌ |
explicit_bzero | ❌ 安全 | 否 | ✅ ✅ ✅ |
Windows 等平台
Windows 没有 explicit_bzero
,可以用:
#include <windows.h>
SecureZeroMemory(ptr, size);
或者自己写:
void secure_memzero(void* p, size_t len) {volatile unsigned char* vp = (volatile unsigned char*)p;while (len--) {*vp++ = 0;}
}
跨平台、安全、可靠的 explicit_bzero
封装实现
- Linux(glibc >= 2.25)使用系统
explicit_bzero
- macOS 使用
explicit_bzero
或bzero
- Windows 使用
SecureZeroMemory
- 其他平台使用手动
volatile
写法
跨平台安全内存清除封装
#pragma once#include <cstddef> // for size_t#if defined(_WIN32)#include <windows.h>
#elif defined(__has_include)#if __has_include(<string.h>)#include <string.h>#endif
#endifnamespace secure {// 可移植 secure_memzero 封装
inline void memzero(void* ptr, size_t len) {if (!ptr || len == 0) return;#if defined(_WIN32)// Windows 安全 APISecureZeroMemory(ptr, len);#elif defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))// glibc 2.25+ 提供 explicit_bzeroexplicit_bzero(ptr, len);#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)// macOS / BSD 系统一般也有 explicit_bzeroexplicit_bzero(ptr, len);#else// 手动 volatile 写法,防止优化器移除volatile unsigned char* p = reinterpret_cast<volatile unsigned char*>(ptr);while (len--) {*p++ = 0;}
#endif
}} // namespace secure
使用方式
#include "secure_memzero.hpp"int main() {char password[32] = "MySecretPassword";// ... 使用 password ...// 安全清除secure::memzero(password, sizeof(password));return 0;
}
测试建议
- Release 模式下测试,确保
secure::memzero
不被优化掉。 - 检查编译器汇编输出(例如
objdump -d
)确保有写入指令。 - 如在密码模块中使用,建议配合内存保护机制(如
mlock
)以防 swap 泄露。
优点
特性 | 描述 |
---|---|
安全 | 防止编译器优化清零操作 |
跨平台 | 兼容 Linux/macOS/Windows/FreeBSD 等系统 |
无依赖 | 不依赖 C11 memset_s |
可内联 | 单头文件,适用于库内/项目中任意使用 |
总结
特性 | 说明 |
---|---|
安全 | 不会被编译器优化 |
用途 | 清除密码、私钥等敏感数据 |
可移植性 | glibc 2.25+、BSD、macOS 支持,Windows 需替代方案 |
推荐场景 | 密码学、加密库、认证信息清除等 |