Summary: | False positive on long double "uninitialised bytes" | ||
---|---|---|---|
Product: | [Developer tools] valgrind | Reporter: | Axel <axel.huebl> |
Component: | memcheck | Assignee: | Julian Seward <jseward> |
Status: | REPORTED --- | ||
Severity: | normal | CC: | daniel, tom |
Priority: | NOR | ||
Version: | 3.12 SVN | ||
Target Milestone: | --- | ||
Platform: | Other | ||
OS: | Linux | ||
URL: | https://github.com/ornladios/ADIOS/issues/184#issuecomment-411739144 | ||
Latest Commit: | Version Fixed In: |
Description
Axel
2018-08-09 12:39:03 UTC
Additional system information: Linux 4.9.0-5-amd64 x86_64 GNU/Linux gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516 sizeof(long double) == 16 When running with --track-origins=yes you can see where the uninitialised bytes originated from: ==7624== Uninitialised value was created by a stack allocation ==7624== at 0x10881A: main (test.c:11) which indicates a local variable in main is to blame. The problem is that the FPU stack is 80 bits wide even if sizeof(long double) returns 16. After the assignment only the first 10 bytes are initialised since floating point instructions has been used. Valgrind correctly reports the last 6 bytes as being uninitialised. If you do a memset followed by an assignment the warning will go away, like: memset(&ld1, 0, sizeof ld1); ld1 = 1.2345e+80; Just to clarify. The following example shows that long double ld1 = <value> does not work as you normally expect an assignment to work. #include <stdio.h> #include <string.h> void func1(void) { long double a; memset(&a, 0xFF, sizeof a); } void func2(void) { long double a = 0; char *p = (char *) &a; for (int i = 0; i < sizeof a; i++) printf("%d: 0x%02x\n", i, p[i] & 0xff); } int main(int argc, char *argv[]) { func1() func2(); return 0; } Thanks, that's understandable. But since it's ok for a long double to only store its values in 80 bits, what shall we do about it? Should that specific case be suppressed by valgrind? Address/memory sanitizers seem to handle our snippets gracefully: clang -g -fsanitize=address main.c && ./a.out clang -g -fsanitize=memory main.c && ./a.out gcc -g -fsanitize=address main.c && ./a.out (all ok) clang -g main.c && valgrind --track-origins=yes ./a.out (this report) It's not really something we can do anything about - although we know that the store is only 80 bits when a long double FP value is saved to memory we don't know that the compiler reported the size as 16 bytes with sizeof. In fact gcc will report different values for sizeof(long double) depending on what compiler options you use but none of that is known to us. The sanitizers have the advantage of working at compile time and knowing how much space the compiler has actually reserved, but there is no easy way to determine that from the compiled code. In principle I think -mlong-double-128 should fix this (at the expense of ABI compatibility...) but it doesn't seem to work for me for some reason. |