Optimising away memset() calls?

David Brown david@westcontrol.com
Fri Oct 10 07:47:00 GMT 2014


On 09/10/14 22:52, Ángel González wrote:
> On 09/10/14 12:18, Florian Weimer wrote:
>> On 10/08/2014 04:15 AM, Sandy Harris wrote:
>>> There are various solutions to this. Linux now has memzero_explicit(),
>>> Open SSH has bzero_explicit(), C11 has memset_s().
>>
>> Minor nit: The C11 standard still allows memset_s to be optimized away
>> if this does not cause an observable difference in behavior (in C
>> terms).  I know the intent is different, but this is impossible to
>> address within the standard, considering the direction in which the
>> language has developed over the last decades.
>>
> How so?
> 
> Copying the relevant description (n1570 draft):
>> 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.
> 
> For all the C compler knows, memset_s library function might be storing
> a pointer to s in a
> global variable, and checking its value on every libc call (including
> exit functions).
> The compiler would need to know that memset_s is special (either
> intrinsically or thorugh
> eg. function attributes). Either way, IMHO an advanced knowledge
> allowing to optimize it out
> would be a violation of K.3.7.4.1.
> The only misbehavior route I see would be the compiler using undefined
> behavior elsewhere
> for deciding that the whole path is unreachable.
> 

When a function is specified in the C standards, then the compiler
/does/ know all about it.  It knows that the memset_s library function
does not "store s in a global variable", because the C standard does not
allow it to do that (or at least, it does not allow such an action to be
visible to the program).  And the compiler is free to implement memset_s
in any way it wants, including inlining it or perhaps even removing it
as long as the behaviour is correct as seen by the C abstract machine.
This is complicated by the fact that the standards don't actually
specify what is meant by things like "memory accesses".

Adding to that, as has been noted by others, particular architectures
might need things like memory barriers, cache flushes, synchronisation
instructions, etc., in order for the writes to be visible across the
system.  The C compiler knows nothing about these things (it can provide
helpful intrinsic functions, but can't use them automatically), because
the C standards don't cover them.

So the only way to be absolutely sure that a memory area really is
cleared is to use an external function that the compiler does not know
about, and which also incorporates any required additional
machine-specific code.  Thus you need to use memzero_explicit(),
bzero_explicit(), or equivalent.



More information about the Gcc-help mailing list