2

The following code seems to be correctly executed when compiled with GCC 4.4.7 and LLVM 6.1. Yet i don't think it correctly compiles with gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4).

The following is what I have reduced the problem to:

#include <stdio.h>
#include <stdlib.h>

#define GENERAL 1
#define BRACKETS 2
#define QUOTES 3

//This method contains the issue.
void foo(char *qb, char* into) {
  //The starting state is important for the bug.
  int state = QUOTES;
  int save_state = BRACKETS;

  //This here needs to reference qb in some way, previously I 
  //had this as just qb however I will set it to qb[0]. Note that this
  //is a contrived  example, I already know that setting it to one
  //makes this pass which makes me suspect this is a compiler 
  //issue.
  while (qb[0]) {
    printf("State is %d\n", state);
    switch (state) {
    case BRACKETS:
      printf("Yay this was correctly executed\n");
      exit(0);
      break;
    case GENERAL:
        printf("Oh no how did you get here?\n");
        printf("State is %d\n", state);
        exit(1);
      break;
    case QUOTES:
        state = save_state;
        printf("State went to %d btw BRACKETS is %d\n", state, BRACKETS);
        save_state = GENERAL; //Remove this line and it will work even
when optimised.
        printf("After save state, state went to %d btw BRACKETS is
%d\n", state, BRACKETS);
      break;
    default: ;
    }
    printf("State %d btw GENERAL %d\n", state, GENERAL);
  }
  printf("If you see this then something is really wrong.\n");
  exit(4);
}

int main() {
    //These don't seem to matter don't concern yourself with them.
    char *b = "123";
    char out[4];
    foo(b, out);
    return 1;
}

If I compile this with: gcc -O0 -g -Wall -Werror sillyswitch.c -o sillyswitch

It will print

Yay this was correctly executed

which is what I expect it to print

However if I compile this with: gcc -O -g -Wall -Werror sillyswitch.c -o sillyswitch

It will print

Oh no how did you get here?

Which is not what I expect to see.

I don't under why it does not work as expected when optimisation is turned on. Is the code wrong in that the branch of the switch statement taken on the second loop is arbitrary? As it is C did I shoot myself in the foot somehow?

Failed full output:

State is 3
State went to 2 btw BRACKETS is 2
After save state, state went to 2 btw BRACKETS is 2
State 2 btw GENERAL 1
State is 2
Oh no how did you get here?
State is 1

Success full output:

State is 3
State went to 2 btw BRACKETS is 2
After save state, state went to 2 btw BRACKETS is 2
State 2 btw GENERAL 1
State is 2
Yay this was correctly executed
Luke
  • 884
  • 8
  • 21
  • 3
    what's the full output that you get in each case? – bruceg Dec 06 '16 at 03:20
  • This works: http://ideone.com/mSEmGH But the unmodified code didn't. Both work in Visual Studio 2015. *shrug* – Retired Ninja Dec 06 '16 at 03:30
  • Thanks for commenting, chux added a comment as to why the pointer is needed. Retired Ninja yeah I am not sure why setting it to 1 makes it pass. I will upload the fill output – Luke Dec 06 '16 at 06:46
  • Well, this seems weird. I'd probably look at the generated asm next. – melpomene Dec 06 '16 at 06:53
  • @melpomene yes original comment should have been ... Why `while(pointer)`? That would not typically generate a compiler warning. Yet it was certainly not what OP wanted. The `case` not being indented under `switch`, provoked my incorrect comment details. Removing mis-leading comments. – chux - Reinstate Monica Dec 06 '16 at 20:56
  • 2
    AFAICS, what you've found is a bug in GCC 5.4.x optimizer. There's not much point in reporting it to GCC; they're not really doing anything with GCC 5.x any more. I can't reproduce the problem in GCC 6.2.0; that may or may not help you. If you can get hold of GCC 6.x and the problem reproduces, then you should report the issue. Otherwise, use the new, fixed compiler and go on your way. – Jonathan Leffler Dec 07 '16 at 03:13

0 Answers0