// Reproducer of https://bugzilla.redhat.com/show_bug.cgi?id=2014942 // How to build: // Build & install openvswitch // git clone https://github.com/openvswitch/ovs // cd ovs // ./boot.sh && ./configure && make && sudo make install // Build this program as: // export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig // gcc `pkg-config --libs libopenvswitch --static` $CFLAGS -lssl -lcrypto -lcap-ng -o example example.c /usr/local/lib/libopenvswitch.a // // Test: // export CFLAGS="-O0 -g" // The program runs successfully // // export CFLAGS="-O2 -flto=auto -g" // The program fails // #include #include #include #include #include #include #include #include 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; // TESTED: If i create the struct in the heap: // struct ovs_list *startp; // startp = malloc(sizeof *startp); // // TEST 1: If I use start as a struct ovs_list and &start in the rest of the // code, the problem still happens // TEST 2: If I use start as a struct ovs_list* and change the rest of // the code to use start directly (not &start), the problem disappears // struct ovs_list start = *startp; // TESTED: Same as before but stack allocation // If I use a pointer to a stack-allocated ovs_list and change the resto of // the code to use start directly (not &start), the problem disappears //struct ovs_list sstart; //struct ovs_list start = &start; 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); printf("start: %p\n", &start); 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); } // TESTED: If, instead of using an hmap to iterate through bond->members, I add them // one by one, the problem disappears: //insert_ordered(&start, member1); //insert_ordered(&start, member2); struct member *first = CONTAINER_OF(ovs_list_front(&start), struct member, elem); struct member *last = CONTAINER_OF(ovs_list_back(&start), struct member, elem); printf("first: %p \nlast: %p\n", first, last); /* 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"); printf("Start: %p. start->next: %p, start->next->next: %p, start->prev: %p\n", &start, start.next, start.next->next, start.prev); ret = 1; goto out; } out: // cleanup free(member1); free(member2); hmap_destroy(&bond->members); free(bond); return ret; }