The definition of get_pointer
uses a statement in an expression, which is a GCC extension. The semantics of this are barely documented, and there is no reason to believe the storage duration of an object declared in a statement-expression persists beyond the evaluation of the statement.
Thus, in preparing the call to smemcpy
, the compiler may evaluate get_pointer
by creating the object tmp
, producing its address as the value of the statement-expression, and destroying the object tmp
. Then the now-invalid address of the no-longer-existing object is passed to smemcpy
, which copies invalid data because the space used for tmp
has been reused for another purpose.
The code may work when memcpy
is used because memcpy
is a special function known to GCC, and GCC optimizes it in various special ways.
A compound literal should work; the C standard specifies that a compound literal within the body of a function has automatic storage duration associated with the enclosing block. If we define get_pointer
as follows, the enclosing block includes the entire smemcpy
call:
#define get_pointer(value) (& (__typeof__(value)) { value })