A custom memset() implementation to force bypass GCC/Clang optimization
The code was tested under the following compilers:
- ARMCC
- GCC
- GCC-ARM
- Clang (x86, arm64, armv7, armv7s)
int main() {
char buffer[4];
buffer[0] = 'A';
buffer[1] = 'B';
buffer[2] = 'C';
buffer[3] = 'D';
/*
* memset((unsigned char*)buffer, 0x00, sizeof(buffer));
*/
memset_explicit((unsigned char*)buffer, 0x00, sizeof(buffer));
return 0;
}
Typical memset with -O3 optimization produces the following assembly
for the code above, clearly shorting out the memset call. Here's how
the compiled assembly looks like after compiling it with GCC/Clang:
gdb$ Dump of assembler code for function main:
0x00001ff0 <+0>: push %ebp
0x00001ff1 <+1>: mov %esp,%ebp
0x00001ff3 <+3>: xor %eax,%eax
0x00001ff5 <+5>: pop %ebp
0x00001ff6 <+6>: ret
End of assembler dump.
As can be seen the memset call is "optimized" by GCC/Clang's
optimizer.
This can be problematic, even dangerous, if the memset was critically
needed to erase memory locations containting privacy sensitive data.
These are the situations where memset_explicit(..) becomes useful. The
same code snippet above compiled with -O3 produces the following
assembly with memset_explicit(..) forcing the deletion of the buffer
as the programmer have had intended.
gdb$ Dump of assembler code for function main:
0x00001fd0 <+0>: push %ebp
0x00001fd1 <+1>: mov %esp,%ebp
0x00001fd3 <+3>: sub $0x18,%esp
0x00001fd6 <+6>: movl $0x44434241,-0x4(%ebp)
0x00001fdd <+13>: lea -0x4(%ebp),%eax
0x00001fe0 <+16>: mov %eax,(%esp)
0x00001fe3 <+19>: movl $0x4,0x8(%esp)
0x00001feb <+27>: movl $0x0,0x4(%esp)
0x00001ff3 <+35>: call 0x1fb0 <memset_explicit>
0x00001ff8 <+40>: xor %eax,%eax
0x00001ffa <+42>: add $0x18,%esp
0x00001ffd <+45>: pop %ebp
0x00001ffe <+46>: ret
End of assembler dump.