6

I have a code snippet from here:

volatile int volatileInt;
int usualInt;

void function (unsigned x, unsigned y, unsigned z)
{
    volatileInt = 0;
    usualInt = (x % y) / z;
}

int main()
{
    function(rand(), rand(), rand());
}

which I compile with Visual C++ 10 with /O2 and get this disassembly:

00403940  push        ebx  
00403941  push        esi  
   276:     function(rand(), rand(), rand());
00403942  mov         esi,dword ptr [__imp__rand (4050C0h)]  
00403948  push        edi  
00403949  call        esi  
0040394B  mov         edi,eax  
0040394D  call        esi  
0040394F  mov         ebx,eax  
00403951  call        esi  
00403953  xor         edx,edx  
00403955  div         eax,ebx  <<<< possible UB
00403957  mov         dword ptr [volatileInt (4074D0h)],0  
00403961  mov         eax,edx  
00403963  xor         edx,edx  
00403965  div         eax,edi  <<<< possible UB
00403967  pop         edi  
00403968  pop         esi  
00403969  pop         ebx  
0040396A  mov         dword ptr [usualInt (4074CCh)],eax  
   277:     return 0;
0040396F  xor         eax,eax
00403971  ret  

Note that there're two operations - "mod" and "div" that could possibly yield UB if their second operand is zero at runtime. In the emitted code both are implemented with div opcodes that will trigger a structured exception and crash the program is the second operand is zero.

The first div is before the volatile int variable is modified, but the second one is after volatile int is modified.

So if x is zero the program crashes without modifying the volatile int but if x is nonzero and y is zero then the program modifies volatile int and then crashes.

So depending on whether x or y are zero the program will exhibit different observable behavior.

Is such interleaving of code with possible UB with code that affects observable behavior allowed?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • So you are asking that if in case of UB happening, your program state could be inconsistent? It is UB after all, anything could happen. – PlasmaHH Jul 18 '12 at 11:07
  • Basically the same issue but answered in a more general way: http://stackoverflow.com/questions/23153445/can-branches-with-undefined-behavior-be-assumed-unreachable-and-optimized-as-dea – usr Aug 20 '14 at 15:22

2 Answers2

7

Yes, this implementation is allowed. See 1.9/5:

A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible executions of the corresponding instance of the abstract machine with the same program and the same input. However, if any such execution contains an undefined operation, this International Standard places no requirement on the implementation executing that program with that input (not even with regard to operations preceding the first undefined operation).

sharptooth
  • 167,383
  • 100
  • 513
  • 979
hamstergene
  • 24,039
  • 5
  • 57
  • 72
  • Deleted my answer and upvoted your answer because you are citing the *relevant* part of the standard. – Werner Henze Jul 18 '12 at 11:19
  • There's some special stuff about finite infinite loops - IIRC, UB after an infinite loop can still occur. – MSalters Jul 19 '12 at 18:24
  • If a platform defines a volatile variable which, if written, (or for that matter, even if read) will instantly terminate the program, is the compiler allowed to move UB before the write (or read)? Many platforms have a number of such addresses defined. – supercat Apr 24 '15 at 03:33
  • @supercat The fundamental reason for the cited condition of the standard is to allow compilers to freely rearrange generated instructions as they please for optimization purposes, as long as observable behavior stays as required. – hamstergene Apr 24 '15 at 22:21
  • @hamstergene: To what extent must reads and writes of externally-exposed volatile variables be considered "observable behavior"? For many embedded systems, the performance of such reads and writes, in sequence, is the whole reason for code's existence. Also, if `getchar()` is called in a situation where any value it returns would invoke Undefined Behavior, but the user hits control-C and `getchar()` never returns, is Undefined Behavior still invoked? – supercat Apr 24 '15 at 22:31
  • @hamstergene: The intended purpose may have been to allow compilers to do things out-of-sequence, but aggressive compilers not only revoke time but causality as well by inferring that things must be true without regard for whether they actually are. I'm unaware of any evidence that most of the people approving the standard ever intended to allow that. If I tell someone who's driving somewhere "It should be safe to assume construction will be finished by the time you reach I23", that would justify the person being late to his destination, but it shouldn't authorize... – supercat Apr 24 '15 at 23:39
  • ...the person, upon finding that construction was still in progress, and might justify the person's driving down the road completely oblivious to construction barriers, but it wouldn't justify launching a crusade to destroy every single copy of "Manos: Hands of Fate". – supercat Apr 24 '15 at 23:40
5

I think clause 1.9:4 is relevant here:

Certain other operations are described in this International Standard as undefined (for example, the effect of attempting to modify a const object). [ Note: This International Standard imposes no requirements on the behavior of programs that contain undefined behavior. —end note ]

As I understand it, this means that if a program execution eventually results in undefined behaviour, then the entire observable behaviour of the program is undefined.

ecatmur
  • 152,476
  • 27
  • 293
  • 366