Is there a Mac OS X equivalent of RtlSecureZeroMemory
/ SecureZeroMemory
, a function which zeroes a block of memory, but the call will not be optimized away by the compiler?
Write your own function:
void secure_zero(void *s, size_t n)
{
volatile char *p = s;
while (n--) *p++ = 0;
}
EDIT: to the question in the comments, why not memset
? The memset
function call could be optimized away by the compiler if the array object is no futher accessed.
Note that C11 adds the (optional) function memset_s
and the Standard guarantees the function call cannot be optimized away:
(C11, K.3.7.4.1p4) "[...] Unlike memset, any call to the memset_s function shall be evaluated strictly according to the rules of the abstract machine as described in (5.1.2.3). That is, any call to the memset_s function shall assume that the memory indicated by s and n may be accessible in the future and thus must contain the values indicated by c."
Is there a Mac OS X equivalent of RtlSecureZeroMemory / SecureZeroMemory, a function which zeroes a block of memory, but the call will not be optimized away by the compiler?
In more recent version of the C runtime, you have memset_s
. Its guaranteed not to be optimized away.
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
errno_t memset_s(void * restrict s, rsize_t smax, int c, rsize_t n)
OS X also includes the bzero
function. But the bzero(3)
man pages don't state its not subject to removal by the optimizer.
Avoid the tricks with the volatile
qualifier because its not portable. It works as expected on Windows, but the GCC folks interpret volatile
to mean memory backed by hardware for I/O. So you're not supposed to use volatile
to tame the optimizer.
Here's an inline assembly implementation you can use. Oddly, __volatile__
on ASM statements and blocks are OK. It works fine on OS X (that's where it was originally written).
// g++ -Og -g3 -m64 wipe.cpp -o wipe.exe
// g++ -Og -g3 -m32 wipe.cpp -o wipe.exe
// g++ -Os -g2 -S -m64 wipe.cpp -o wipe.exe.S
// g++ -Os -g2 -S -m32 wipe.cpp -o wipe.exe.S
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
string s("Hello world");
cout << "S: " << s << endl;
char* ptr = &s[0];
size_t size = s.length();
if(ptr && size)
{
/* Needed because we can't just say to GCC, */
/* "give me a register that you choose". */
void* dummy;
__asm__ __volatile__
(
"%=:\n\t" /* generate a unique label for TOP */
#if (__WORDSIZE == 64)
"subq $1, %2\n\t" /* 0-based index */
#elif (__WORDSIZE == 32)
"subl $1, %2\n\t" /* 0-based index */
#elif (__WORDSIZE == 16)
"subw $1, %2\n\t" /* 0-based index */
#else
# error Unknown machine word size
#endif
"lea (%1, %2), %0\n\t" /* calcualte ptr[idx] */
"movb $0, (%0)\n\t" /* 0 -> ptr[size - 1] .. ptr[0] */
"jnz %=b\n\t" /* Back to TOP if non-zero */
: "=&r" (dummy)
: "r" (ptr), "r" (size)
: "0", "1", "2", "cc"
);
}
#if 0
cout.setf(ios::hex, ios::basefield);
cout.fill('0');
for(size_t i = 0; i < s.length(); i++)
cout << "0x" << setw(2) << ((int)s[i] & 0xff) << " ";
cout << endl;
#endif
cout << "S: " << s << endl;
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With