More on in-memory zeroisation

Leichter, Jerry leichter_jerrold at emc.com
Tue Dec 11 17:07:05 EST 2007


| > However, that doesn't say anything about whether f is actually
| > invoked at run time.  That comes under the "acts as if" rule:  If
| > the compiler can prove that the state of the C (notional) virtual
| > machine is the same whether f is actually invoked or not, it can
| > elide the call.  Nothing says that memset() can't actually be
| > defined in the appropriate header, as a static (or, in C99, inline)
| > function.
| 
| The standard actually says "... it is permitted to take the address of
| a library function even if it is defined as a macro ...". The standard
| works for me as a source code author who needs an execution-aware
| memcpy function from time to time. Overworked GCC contributors should
| work to comply to the standard, not to address Peter, Thierry, and
| whoever's wildests dreams.
If the function is defined as I suggested - as a static or inline - you
can, indeed, takes its address.  (In the case of an inline, this forces
the compiler to materialize a copy somewhere that it might not otherwise
have produced, but not to actually *use* that copy, except when you take
the address.)  You are allowed to invoke the function using the address
you just took.  However, what in that tells you that the compiler -
knowing exactly what code will be invoked - can't elide the call?

By the way, you might wonder what happens if two different CU's take
the address of memset and we then compare them.  In this kind of
implementation, they will be unequal - but in fact nothing in the
Standard says they can't be!  A clever compiler could have all kinds
of reasons to produce multiple copies of the same function.  All you
can say is that if two function pointers are equal, they point to the
same function.  No converse form is provable within the Standard.

You might try something like:

	typedef (void *(*memset_ptr)(const void*,int,size_t));

	volatile memset_ptr p_memset = &(memset);

(I *think* I got that syntax right!)

Then you can invoke (*p_memset).  But if you do this in the same
compilation unit, a smart compiler that does value propagation could
determine that it knows where p_memset points, and that it knows what
the code there is, so it can go ahead and do its deeper analysis.

Using:

	volatile memset_ptr p_memset = &(memset);

in one compilation unit and then:

	extern volatile memset_ptr p_memset = &(memset);

will keep you safe from single-CU optimizations, but nothing in the
Standard says that's all there are.  Linker-based optimizations
could have the additional information that nowhere in the program
can p_memset be changed, and further that p_memset is allocated to
regular memory, and in principle the calls could be elided at that
point.  Mind you, I would be astounded if any compiler/linker system
actually attempted such an optimization ... but that doesn't make
it illegal within the language of the Standard.

| > Then the compiler can look at the implementation and "prove"
| > that a memset() to a dead variable can be elided....
| 
| It can't prove much in the case of (memset)()
In principle (I'll grant you, probably not in practice), it can
provie quite a bit - and certainly enough to justify eliding the
call.
							-- Jerry

---------------------------------------------------------------------
The Cryptography Mailing List
Unsubscribe by sending "unsubscribe cryptography" to majordomo at metzdowd.com



More information about the cryptography mailing list