language lawyer - C "observable behavior" in the context of UB "undefined behavior" -
(question prompted comments under answer are there race conditions in producer-consumer implementation? being asked here strictly c language perspective, without concurrency or multi-threading involved.)
consider minimal code:
#define bufsiz 10 char buf[bufsiz]; void f(int *pn) { buf[*pn]++; *pn = (*pn + 1) % bufsiz; } int main() { int n = 0; f(&n); return n; }
question: c "as-if" rules allow compiler rewrite code follows?
void f(int *pn) { int n = *pn; *pn = (*pn + 1) % bufsiz; buf[n]++; }
on 1 hand, above not change observable behavior of program written.
on other hand, f
called invalid index, possibly translation unit:
int g() { int n = -1001; f(&n); }
in latter case, both variants of code invoke ub when accessing out-of-bounds array element. however, original code leave *pn
@ value being passed f
(= -1001) while rewritten code step ub-land after modifying *pn
(to 0
).
would such difference count "observable" or, actual question, there in c standard allow or preclude type of code rewrite/optimization?
if part of program has undefined behaviour, behaviour of entire program undefined. in other words, behaviour of program undefined "before" construct behaviour undefined. (this necessary allow compiler perform optimizations depend on behaviour being defined.)
given neither variable declared volatile, believe possible order of memory updates reordered indicated, since observable behaviour guaranteed according execution model in absence of undefined behaviour.
"observable behaviour" (in standard c) defined in §5.1.2.3 as:
- accesses volatile objects evaluated strictly according rules of abstract machine.
- at program termination, data written files shall identical result execution of program according abstract semantics have produced.
- the input , output dynamics of interactive devices shall take place specified in 7.21.3. intent of these requirements unbuffered or line-buffered output appear possible, ensure prompting messages appear prior program waiting input.
this list not include potential response undefined behaviour (such trap or signal), though in vernacular terms segfault observable. particular example in question not involve of these 3 points. (the ub prevent program terminating, voids second point in observable behaviour.) in particular case of code in question, reordering not alter observable behaviour , performed.
my statement implementation's response undefined behaviour not limited execution strictly following component engenders undefined behaviour created lot more controversy in comments thread expected, since well-known feature of modern c. may worth reviewing john regehr's useful essay on undefined behaviour, quote: (in third part)
more specifically, when program dies due performing illegal operation such dividing 0 or dereferencing null pointer, considered side effecting? answer “no.” … since crash-inducing operations not side effecting, compiler can reorder them respect other operations,
as possibly more interesting example (taken comments thread), if program produces several lines of output, , deliberately executes explicit divide-by-zero, 1 might expect compiling , running program produce output before responding in whatever undefined way responds divide-by-zero. however, compiler detected divide-by-zero , prove control flow of program guaranteed execution entitled produce error message at translation time , refuse produce executable image.
alternatively, if not prove control flow reached divide-by-zero, entitled assume divide-by-zero not happen, , therefore remove code unequivocally leading divide-by-zero (including calls output function) dead code.
both of above fit list of example responses undefined behaviour in §3.4.3: "from ignoring situation unpredictable results, … terminating translation or execution (with issuance of diagnostic message)."
Comments
Post a Comment