J
John Regehr
I'm trying to figure out what -- if any -- ammunition the C standard
gives me for identifying bugs in the translation of C code containing
volatile variables. For example consider this fragment:
volatile int g_1;
void self_assign (void)
{
g_1 = g_1;
}
One of gcc's embedded ports translates this into the following asm
when invoked with -Os:
self_assign:
ret
On the other hand, when optimizations are disabled the same compiler
produces object code that properly loads from g_1 and then stores the
loaded value back into g_1.
At an informal level, the optimized code is obviously wrong in the
sense that any embedded C programmer would expect this function to
load from g_1 and then store back to it.
What I am trying to figure out is, is this output buggy from the
language lawyer point of view? On one hand the standard tells us that
"any expression referring to such an object shall be evaluated
strictly according to the rules of the abstract machine." This
appears to clearly call for a load and then a store. On the other
hand the standard also says "What constitutes an access to an object
that has volatile-qualified type is implementation-defined." This
seems to admit an implementation that specifies that volatile-
qualified types are never accessed, regardless of what the source code
looks like. But is it legal for the compiler to access the object at
some optimization levels and not at others?
Any help appreciated.
gives me for identifying bugs in the translation of C code containing
volatile variables. For example consider this fragment:
volatile int g_1;
void self_assign (void)
{
g_1 = g_1;
}
One of gcc's embedded ports translates this into the following asm
when invoked with -Os:
self_assign:
ret
On the other hand, when optimizations are disabled the same compiler
produces object code that properly loads from g_1 and then stores the
loaded value back into g_1.
At an informal level, the optimized code is obviously wrong in the
sense that any embedded C programmer would expect this function to
load from g_1 and then store back to it.
What I am trying to figure out is, is this output buggy from the
language lawyer point of view? On one hand the standard tells us that
"any expression referring to such an object shall be evaluated
strictly according to the rules of the abstract machine." This
appears to clearly call for a load and then a store. On the other
hand the standard also says "What constitutes an access to an object
that has volatile-qualified type is implementation-defined." This
seems to admit an implementation that specifies that volatile-
qualified types are never accessed, regardless of what the source code
looks like. But is it legal for the compiler to access the object at
some optimization levels and not at others?
Any help appreciated.