Bug 67433 - ?: expression returns unexpected value when condition is a bool variable which memory is not true/false
Summary: ?: expression returns unexpected value when condition is a bool variable whic...
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-09-02 07:44 UTC by xuejuncao
Modified: 2015-09-02 10:59 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description xuejuncao 2015-09-02 07:44:47 UTC

    
Comment 1 xuejuncao 2015-09-02 07:53:48 UTC
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

int main()
{
    union u {
        bool b;
        char c;
    } u;
    memset((void *)&u, -1, sizeof(u));
    bool b = (u.b ? 1 : 0);
    int i = (u.b ? 1 : 0);
    int j = (u.b ? 1 : 2);
    printf("b = %d, i = %d, j = %d\n", b, i, j);
    return 0;
}

without optimisation, the output is:
b = 1, i = 255, j = 1

with -O2, is:
b = 255, i = 255, j = 1
Comment 2 Andrew Pinski 2015-09-02 07:58:53 UTC
Bool can only be 0 or 1, any other value causes undefined behavior.
Comment 3 xuejuncao 2015-09-02 08:11:24 UTC
(In reply to Andrew Pinski from comment #2)
> Bool can only be 0 or 1, any other value causes undefined behavior.

but it seems like a trap, the below code will not work fine, and will make program abort.
(expect to write "1/0" that only takes 1 byte, but write 2 bytes when value is negative)

https://github.com/google/protobuf/blob/master/src/google/protobuf/wire_format_lite_inl.h

inline void WireFormatLite::WriteBoolNoTag(bool value,
                                           io::CodedOutputStream* output) {
  output->WriteVarint32(value ? 1 : 0);
}
Comment 4 xuejuncao 2015-09-02 08:20:25 UTC
btw, the same code works fine on Mac:

$gcc --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.5.0
Thread model: posix
Comment 5 Andrew Pinski 2015-09-02 08:21:16 UTC
Try -fsantitized=undefined to catch this error.
Comment 6 Andrew Pinski 2015-09-02 08:22:49 UTC
(In reply to xuejuncao from comment #4)
> btw, the same code works fine on Mac:
> 
> $gcc --version
> Configured with: --prefix=/Library/Developer/CommandLineTools/usr
> --with-gxx-include-dir=/usr/include/c++/4.2.1
> Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
> Target: x86_64-apple-darwin14.5.0
> Thread model: posix

So this is undefined behavior.
Comment 7 Andrew Pinski 2015-09-02 08:33:21 UTC
I should say the value that is stored in the bool variable can only be 0 or 1; anything else is undefined bahavior.
Comment 8 xuejuncao 2015-09-02 09:04:27 UTC
thanks, i get the below result with -fsanitize=undefined 

boolmagic.c:12:16: runtime error: load of value 255, which is not a valid value for type '_Bool'
boolmagic.c:13:15: runtime error: load of value 255, which is not a valid value for type '_Bool'
boolmagic.c:14:15: runtime error: load of value 255, which is not a valid value for type '_Bool'
b = 1, i = 1, j = 1

but, can i say the "-fsanitize=undefined" will _corrects_ the undefined behaviour?

or replace the code by if/else, which works fine (lucky?)

    int i; // = (u.b ? 1 : 0);
    if (u.b) i = 1; else i = 0;
Comment 9 Markus Trippelsdorf 2015-09-02 09:17:09 UTC
(In reply to xuejuncao from comment #8)
> thanks, i get the below result with -fsanitize=undefined 
> 
> boolmagic.c:12:16: runtime error: load of value 255, which is not a valid
> value for type '_Bool'
> boolmagic.c:13:15: runtime error: load of value 255, which is not a valid
> value for type '_Bool'
> boolmagic.c:14:15: runtime error: load of value 255, which is not a valid
> value for type '_Bool'
> b = 1, i = 1, j = 1
> 
> but, can i say the "-fsanitize=undefined" will _corrects_ the undefined
> behaviour?
> 
> or replace the code by if/else, which works fine (lucky?)
> 
>     int i; // = (u.b ? 1 : 0);
>     if (u.b) i = 1; else i = 0;

No, you're still invoking undefined behavior. -fsanitize=undefined will not
fix this at all; it just points out the issues.

You need to get rid of the underlying problem, but this is not the place
to discuss this further.
Comment 10 xuejuncao 2015-09-02 10:15:44 UTC
when bool value read from unpacked stream or file, wen can not ensure it's 1 or 0;
so maybe the best solution is compile with "-D_Bool=char" for now :-/
Comment 11 Richard Biener 2015-09-02 10:20:17 UTC
(In reply to xuejuncao from comment #10)
> when bool value read from unpacked stream or file, wen can not ensure it's 1
> or 0;
> so maybe the best solution is compile with "-D_Bool=char" for now :-/

You can always do the read with 'char' and then convert to _Bool.

You can also "fix" your testcase (I think, didn't try) by using

union u {
  bool b : 1;
  char c;
} u;

(in case unions allow bitfield members)
Comment 12 xuejuncao 2015-09-02 10:59:24 UTC
(In reply to Richard Biener from comment #11)
> (In reply to xuejuncao from comment #10)
> > when bool value read from unpacked stream or file, wen can not ensure it's 1
> > or 0;
> > so maybe the best solution is compile with "-D_Bool=char" for now :-/
> 
> You can always do the read with 'char' and then convert to _Bool.
> 
> You can also "fix" your testcase (I think, didn't try) by using
> 
> union u {
>   bool b : 1;
>   char c;
> } u;
> 
> (in case unions allow bitfield members)

yes, it works, but likes a trick:-)

bit operation to bool is also undefined
int i = (u.b & 1 ? 1 : 0); // works without -O2, useless with -O2