https://bugs.kde.org/show_bug.cgi?id=382041
Bug ID: 382041 Summary: False uninitialized on bit packing when the compiler chooses XOR to implement masking and shifting (x86_64) Product: valgrind Version: 3.14 SVN Platform: Other OS: other Status: UNCONFIRMED Severity: normal Priority: NOR Component: memcheck Assignee: jsew...@acm.org Reporter: broscutama...@gmail.com Target Milestone: --- Created attachment 106457 --> https://bugs.kde.org/attachment.cgi?id=106457&action=edit Full output While troubleshooting an image processing program, I've received a lot of warnings regarding uninitialized values after running a custom bit packing routine. Managed to narrow down and write a minimal example: #include <stdio.h> #include <stdlib.h> #include <stdint.h> void __attribute__((noinline)) set(uint16_t * x, uint16_t val, uint16_t mask) { *x = (*x & ~mask) | ((val << 4) & mask); } int main() { /* allocate 2 bytes of uninitialized memory */ uint16_t * buf = malloc(2); /* write 0x2340 in 2 steps, using 2 bit masks and a shift*/ /* this way, some compilers are "tempted" to use xor */ /* exact mask value doesn't matter - it's complemented */ set(buf, 0x1234, 0x003F); set(buf, 0x1234, ~0x003F); /* print the result => 0x2340 */ printf("%x\n", *buf); free(buf); return 0; } Compiled with e.g.: gcc bit.c -O2 Results: gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2) and gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4): ... ==22509== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ... ==22509== Use of uninitialised value of size 8 ==22509== at 0x4E81711: _itoa_word (_itoa.c:180) ==22509== by 0x4E85A78: vfprintf (vfprintf.c:1641) ==22509== by 0x4F4E955: __printf_chk (printf_chk.c:35) ==22509== by 0x400545: main (in /home/alex/vg/a.out) ... ==22509== ERROR SUMMARY: 20 errors from 10 contexts (suppressed: 0 from 0) objdump a.out -d -M intel | grep "<set>:" -A 8 0000000000400670 <set>: 400670: 0f b7 07 movzx eax,WORD PTR [rdi] 400673: c1 e6 04 shl esi,0x4 400676: 31 c6 xor esi,eax 400678: 21 d6 and esi,edx 40067a: 31 f0 xor eax,esi 40067c: 66 89 07 mov WORD PTR [rdi],ax 40067f: c3 ret gcc version 4.8.5 (Ubuntu 4.8.5-1ubuntu1) ==1105== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 0000000000400660 <set>: 400660: 89 d0 mov eax,edx 400662: c1 e6 04 shl esi,0x4 400665: f7 d0 not eax 400667: 66 23 07 and ax,WORD PTR [rdi] 40066a: 21 d6 and esi,edx 40066c: 09 f0 or eax,esi 40066e: 66 89 07 mov WORD PTR [rdi],ax 400671: c3 ret Ubuntu clang version 3.6.2-1 (tags/RELEASE_362/final) (based on LLVM 3.6.2) ==1302== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 0000000000400590 <set>: 400590: 89 d0 mov eax,edx 400592: f7 d0 not eax 400594: 66 23 07 and ax,WORD PTR [rdi] 400597: c1 e6 04 shl esi,0x4 40059a: 21 d6 and esi,edx 40059c: 09 c6 or esi,eax 40059e: 66 89 37 mov WORD PTR [rdi],si 4005a1: c3 ret My conclusion: the warning only appears when the compiler implements these bitfield-like operations with XOR. Another example, this time without shift. However, it only triggers the warning on gcc 5.2.1, not on 5.4.0. #include <stdio.h> #include <stdlib.h> #include <stdint.h> int main() { /* allocate 2 bytes of uninitialized memory */ uint16_t * buf = malloc(2); /* write 0x1234 in 2 steps, using 2 bit masks */ /* exact mask value doesn't matter */ const uint16_t mask1 = 0x3F; *buf = (*buf & ~mask1) | (0x1234 & mask1); /* complement the mask and write the other "half" of the number */ uint16_t mask2 = ~mask1; *buf = (*buf & ~mask2) | (0x1234 & mask2); /* print the result => 0x1234 */ printf("%x\n", *buf); free(buf); return 0; } gcc bit.c -O2 This is clean, as the compiler optimizes it out (because the masks are constant). 0000000000400470 <main>: 400470: 48 83 ec 08 sub rsp,0x8 400474: ba 34 12 00 00 mov edx,0x1234 400479: be 24 06 40 00 mov esi,0x400624 40047e: bf 01 00 00 00 mov edi,0x1 400483: 31 c0 xor eax,eax 400485: e8 d6 ff ff ff call 400460 <__printf_chk@plt> Remove one of the const's (say the second): ==25688== ERROR SUMMARY: 9 errors from 5 contexts (suppressed: 0 from 0) gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2) 0000000000400500 <main>: 400500: 53 push rbx 400501: bf 02 00 00 00 mov edi,0x2 400506: e8 d5 ff ff ff call 4004e0 <malloc@plt> 40050b: 48 89 c3 mov rbx,rax 40050e: 0f b7 00 movzx eax,WORD PTR [rax] 400511: be c4 06 40 00 mov esi,0x4006c4 400516: bf 01 00 00 00 mov edi,0x1 40051b: 83 e0 c0 and eax,0xffffffc0 40051e: 89 c2 mov edx,eax 400520: 80 f4 12 xor ah,0x12 400523: 83 ca 34 or edx,0x34 400526: 31 d0 xor eax,edx 400528: 0f b7 d0 movzx edx,ax 40052b: 31 c0 xor eax,eax 40052d: e8 be ff ff ff call 4004f0 <__printf_chk@plt> On gcc 5.4, removing "const" doesn't change the disassembly (therefore it doesn't trigger the warnings); the compiler apparently figures out the second mask is constant. Valgrind versions tested: valgrind-3.11.0 (prepackaged with Ubuntu) valgrind-3.13.0 (compiled from source) valgrind-3.14.0.SVN rev 16458 (compiled from source) Attached full output for both examples, using valgrind from SVN and gcc 5.2.1. Thanks for reading. -- You are receiving this mail because: You are watching all bug changes.