#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
Bool can only be 0 or 1, any other value causes undefined behavior.
(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); }
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
Try -fsantitized=undefined to catch this error.
(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.
I should say the value that is stored in the bool variable can only be 0 or 1; anything else is undefined bahavior.
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;
(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.
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 :-/
(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)
(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