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: [email protected]
Reporter: [email protected]
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.