Safeguard
Application Security•

Why does memset not clear secrets in C and C++ code?

Compilers may delete a memset call on a buffer never read again, leaving keys in memory. Use memset_explicit or SecureZeroMemory and check the assembly.

Safeguard Security Team
4 min read

memset can fail to clear a secret because the compiler is allowed to remove a write that nothing reads afterwards. A password buffer wiped just before it goes out of scope is the classic case. Use a function the standard or platform guarantees will not be optimized away, and check the compiled output.

Why would a compiler remove the wipe?

The C standard lets an implementation skip evaluating an expression if it can deduce the value is not used. The CERT C recommendation on this quotes that wording from the standard. If a buffer is never read after the memset call, an optimizing compiler may treat the call as dead code and drop it.

Whether that happens depends on the compiler and the optimization level. That is what makes it nasty. Debug builds look fine, tests pass, and the release build keeps the key in memory.

What does the problem look like?

A constructed example, described in words: a function reads a passphrase into a local array, derives a key, then calls memset on the array as its last step before returning. Nothing reads the array again, so the optimizer has a reason to delete the call. After the function returns, the old stack bytes still hold the passphrase until something overwrites them.

Why care? Leftover secrets can reach core dumps, swap files, crash reports, or a later bug that reads uninitialized memory.

What are the safe options?

The CERT page walks through several, with caveats.

  • memset_explicit from C23. The page calls this the preferred solution.
  • memset_s from C11 Annex K. It is optional and poorly supported, so you may not have it.
  • SecureZeroMemory on Windows. Its documentation guarantees the call is not optimized out, while ZeroMemory can still be removed.
  • A custom memset_s that writes through a volatile pointer. The page treats it as the best fallback when neither standard function exists, though it can be slower and the page warns volatile accesses can still be optimized away in some cases.
  • Touching one byte through a volatile pointer after memset. The page says this is a partial fix that does not work everywhere, and that some GCC versions and the MIPSpro compiler clear only the first byte.
  • Disabling optimization around the call with a Visual Studio pragma. It is compiler specific, so check your compiler docs.

We did not find explicit_bzero in the page we read, so we make no claim about it here.

How do you know it worked?

The page recommends inspecting the assembly of an optimized release build to confirm the clearing is still there. Do it for the functions that handle keys, and put the check in a test or review checklist so it survives refactoring.

What else belongs in a C or C++ secrets policy?

Clearing memory is one layer. Keep secrets short lived, keep them in as few buffers as possible, and avoid copying them into std::string or other containers that may reallocate and leave stale copies behind. Never put secrets in source, in command line arguments, or in logs. The compile-time dependency list matters too: a vendored library with its own key handling is part of your exposure.

Safeguard can inventory the native libraries your C and C++ build pulls in and flag known issues, though it will not rewrite your wiping code for you.

What to do

  1. Find every place a key, token or password lands in a buffer. Search for memset next to key material.
  2. Replace those calls with memset_explicit where your toolchain supports C23, or SecureZeroMemory on Windows.
  3. Where neither exists, use a written, reviewed fallback and document why.
  4. Build in release mode and read the assembly for the sensitive functions.
  5. Add a unit or CI check that fails if the wipe disappears from the compiled output.
  6. Shorten the time secrets stay in memory, and avoid copies.
  7. Review crash dump and swap handling for hosts that process secrets.

Quick check

Is ZeroMemory on Windows enough?

No. According to the CERT page, ZeroMemory can still be optimized out. SecureZeroMemory is documented to prevent that.

Why do tests not catch a removed memset?

Behaviour depends on the compiler and optimization level, and the removed call changes nothing visible to the program itself. Only the memory contents or the assembly show it.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.