Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++ bug? (bool_val ? 0 : 1) returns neither 0 nor 1

Tags:

c++

gcc

I reproduce the problem by this simple demo:

// bool_test_func.cpp
#include <stdio.h>

void func(bool* b) {
  int a = (*b ? 0 : 1);
  printf("%d\n", a); // EXPECT ether 0 or 1 here
}

// bool_test.cpp
void func(bool* b);

int main() {
  int n = 128;
  func((bool*)&n);
  return 0;
}

-O0 compile and run:

g++ -g -O0 -Wall -o bool_test bool_test.cpp bool_test_func.cpp
mikewei@maclinux:~/testing/c++$ ./bool_test
0

-O1 compile and run (unexpected result):

g++ -g -O1 -Wall -o bool_test bool_test.cpp bool_test_func.cpp
mikewei@maclinux:~/testing/c++$ ./bool_test
129

When I check the -O2 ASM code, I think it is a g++ bug, g++'s optimzation code always think the bool value is ether 1 or 0:


    00000000004005e6 :
      4005e6:       48 83 ec 08             sub    $0x8,%rsp
      4005ea:       0f b6 37                movzbl (%rdi),%esi
      4005ed:       83 f6 01                xor    $0x1,%esi  #just XOR the bool val
      4005f0:       40 0f b6 f6             movzbl %sil,%esi
      4005f4:       bf 94 06 40 00          mov    $0x400694,%edi
      4005f9:       b8 00 00 00 00          mov    $0x0,%eax
      4005fe:       e8 9d fe ff ff          callq  4004a0 
      400603:       48 83 c4 08             add    $0x8,%rsp
      400607:       c3                      retq
      400608:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
      40060f:       00

 

gcc version 4.9.2 (Debian 4.9.2-10)

Is this g++ behavior by design? How can I disable this wrong optimaztion? Thanks~

like image 259
mikewei Avatar asked Jul 16 '15 13:07

mikewei


1 Answers

I think it is a g++ bug.

Have to respectfully disagree there.

How can I disable this wrong optimisation?

Even if that is possible, it's not actually wrong :-)

You are passing a non-bool pointer as a bool pointer (the underlying item is not of the bool type) and I'm pretty certain that this (known as type punning) invokes undefined behaviour.

Hence the code is free to do whatever it wants.

You can think of the prototype void func(bool* b) as a contract you agree to to only ever pass pointers to bool values. If you violate that contract, all bets are off. In this particular case, your code:

int a = (*b ? 0 : 1);

is telling it to convert false to 1 and true to 0. If you were to supply valid input (false/0 or true/1), the xor input, 1 would be exactly the right thing to do.

However, because you're giving it 128, the xor results in 129.

like image 182
paxdiablo Avatar answered Oct 27 '22 15:10

paxdiablo