[llvm-dev] broken C code only when optimized "-O2"
Adrian Moreno via llvm-dev
llvm-dev at lists.llvm.org
Tue Dec 21 10:22:56 PST 2021
Thanks Sterling
On 12/21/21 18:31, Sterling Augustine wrote:
> The thing to do with problems like this is to run with clang's sanitizers, which
> diagnose undefined behavior, memory errors, and other such issues that often
> show up only under optimization. A cursory look at all the casting in this
> example makes me think there is undefined behavior, but there very well could be
> another type of failure.
Interestingly, when I enable UndefinedBehaviorSanitizer, my problem disappears
(and sanitizer does not report anything). In fact, the issue is quite elisuve,
adding a function call, a compiler barrier or not inlining a single function
changes the behavior of the program.
MemorySanitizer does print an error that I'm investigating:
==762381==WARNING: MemorySanitizer: use-of-uninitialized-value
[Detaching after fork from child process 764910]
#0 0x4b1871 in hmap_next__
/home/amorenoz/code/ovs/out/include/openvswitch/hmap.h:379:13
#1 0x4af81f in hmap_first
/home/amorenoz/code/ovs/out/include/openvswitch/hmap.h:391:12
#2 0x4adf3a in main /home/amorenoz/dev/bugs/2014942/example.c:82:5
#3 0x7ffff77c055f in __libc_start_call_main (/lib64/libc.so.6+0x2d55f)
#4 0x7ffff77c060b in __libc_start_main at GLIBC_2.2.5 (/lib64/libc.so.6+0x2d60b)
#5 0x42c244 in _start (/home/amorenoz/devel/bugs/2014942/example_+0x42c244)
Uninitialized value was stored to memory at
#0 0x4b17d8 in hmap_next__
/home/amorenoz/code/ovs/out/include/openvswitch/hmap.h:378:27
#1 0x4af81f in hmap_first
/home/amorenoz/code/ovs/out/include/openvswitch/hmap.h:391:12
#2 0x4adf3a in main /home/amorenoz/dev/bugs/2014942/example.c:82:5
#3 0x7ffff77c055f in __libc_start_call_main (/lib64/libc.so.6+0x2d55f)
Uninitialized value was created by a heap allocation
#0 0x45c942 in malloc (/home/amorenoz/devel/bugs/2014942/example_+0x45c942)
#1 0x4b4c9d in xmalloc__ /home/amorenoz/code/ovs/lib/util.c:137:15
#2 0x4b4c9d in xmalloc /home/amorenoz/code/ovs/lib/util.c:172:12
>
> https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
> <https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html>
> https://clang.llvm.org/docs/AddressSanitizer.html
> <https://clang.llvm.org/docs/AddressSanitizer.html>
> https://clang.llvm.org/docs/MemorySanitizer.html
> <https://clang.llvm.org/docs/MemorySanitizer.html>
>
>
> On Tue, Dec 21, 2021 at 9:30 AM Adrian Moreno via llvm-dev
> <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote:
>
> Hello,
>
> I need some help understanding what might be wrong with a piece of code from
> the
> openvswitch project. By ${subject} I'm not suggesting there's a problem in
> clang, gcc also shows the same behavior so it's likely our code is broken. I am
> kindly asking for help to understand/troubleshoot the problem.
>
> Summary: It seems that certain interaction between two main openvswitch data
> structures, when optimized ("-O2 -flto=auto") is broken.
> The two data structures are:
>
> hmap:
> https://github.com/openvswitch/ovs/blob/master/include/openvswitch/hmap.h
> <https://github.com/openvswitch/ovs/blob/master/include/openvswitch/hmap.h>
> list:
> https://github.com/openvswitch/ovs/blob/master/include/openvswitch/list.h
> <https://github.com/openvswitch/ovs/blob/master/include/openvswitch/list.h>
>
> I've reproduced the problem outside of openvswitch daemon using a short C
> program (attached)
>
> Code snippet:
>
> struct bond {
> struct hmap members;
> };
>
> struct member {
> struct hmap_node hmap_node;
> int order;
> struct ovs_list elem;
> };
>
> int main() {
> int ret = 0;
> struct member *member, *member1, *member2;
> struct bond *bond;
> struct ovs_list start = {0};
>
> bond = malloc(sizeof *bond);
> memset(bond, 0, sizeof (struct bond));
> hmap_init(&bond->members);
>
> member1 = malloc(sizeof *member1);
> member2 = malloc(sizeof *member2);
> memset(member1, 0, sizeof (struct member));
> memset(member2, 0, sizeof (struct member));
>
> member1->order = 3;
> member2->order = 2;
>
> hmap_insert(&bond->members, &member1->hmap_node,
> (uint32_t)(uintptr_t)member1);
> hmap_insert(&bond->members, &member2->hmap_node,
> (uint32_t)(uintptr_t)member2);
>
> ovs_list_init(&start);
> HMAP_FOR_EACH (member, hmap_node, &bond->members) {
> /*
> * Insert member in start (sorted)
> * */
> struct member *pos;
> LIST_FOR_EACH (pos, elem, &start) {
> if (member->order > pos->order) {
> break;
> }
> }
> // TESTED: If I add this printf, the problem disappears
> //printf("Inserting member: %p\n", member);
> ovs_list_insert(&pos->elem, &member->elem);
> }
>
> /* I've inserted two members into the 'start' list.
> * first and last have to be either member1 or member2
> * */
> if ((first != member1 && first != member2) || (last != member1 && last !=
> member2)) {
> printf("list is broken!\n");
> }
>
> }
>
>
> What I know for now:
> * -fno-strict-aliasing does not fix it
> * Only happens with "-O2 -flto=auto"
> * If I define 'ovs_list *start' and change the code to use the pointer directly
> and not '&start' the problem disappears. It seems that the LIST_FOR_EACH macros
> prefer an lvalue rather than "&" but I don't get why.
> * I'm not able to reproduce without using hmap _and_ ovs_list.
> * If I add a compiler barrier (or a call to an external function) after the
> loop, the problem disappears (e.g printf), the problem disappears.
> * If I add -fsanitize=undefined the problem disappears!
>
> I'd really appreciate any hint or idea to try to understand this problem.
>
> Thanks in advanced.
>
> --
> Adrián Moreno_______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
> <https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev>
>
--
Adrián Moreno
More information about the llvm-dev
mailing list