https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94596
Bug ID: 94596 Summary: possible false positive when analyze OVS macro Product: gcc Version: 10.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: analyzer Assignee: dmalcolm at gcc dot gnu.org Reporter: u9012063 at gmail dot com Target Milestone: --- Hi, Below is my system info: $ uname -a Linux osboxes 5.5.0-rc1+ #112 SMP Fri Feb 21 10:28:49 PST 2020 x86_64 x86_64 x86_64 GNU/L $ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/10.0.1/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ./configure Thread model: posix Supported LTO compression algorithms: zlib gcc version 10.0.1 20200405 (experimental) (GCC) $ git clone https://github.com/openvswitch/ovs.git $ cd ovs $ ./boot.sh; ./configure; make CFLAGS+=-fanalyzer A use-after-free warning is shown, but I think it's a false positive. libtool: compile: gcc -DHAVE_CONFIG_H -I. -I ./include -I ./include -I ./lib -I ./lib -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wswitch-bool -Wlogical-not-parentheses -Wsizeof-array-argument -Wbool-compare -Wshift-negative-value -Wduplicated-cond -Wshadow -Wmultistatement-macros -Wcast-align=strict -fanalyzer -MT lib/conntrack.lo -MD -MP -MF lib/.deps/conntrack.Tpo -c lib/conntrack.c -o lib/conntrack.o In file included from lib/conntrack.h:25, from lib/conntrack.c:26: ./include/openvswitch/hmap.h: In function ‘hmap_remove’: ./include/openvswitch/hmap.h:292:52: warning: use after ‘free’ of ‘node’ []8;;https://cwe.mitre.org/data/definitions/416.htmlCWE-416]8;;] []8;;https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wanalyzer-use-after-free-Wanalyzer-use-after-free]8;;] 292 | struct hmap_node **bucket = &hmap->buckets[node->hash & hmap->mask]; | ~~~~^~~~~~ ‘conntrack_destroy’: event 1 | |lib/conntrack.c:486:1: | 486 | conntrack_destroy(struct conntrack *ct) | | ^~~~~~~~~~~~~~~~~ | | | | | (1) entry to ‘conntrack_destroy’ | ‘conntrack_destroy’: event 2 | |lib/cmap.h:222:5: | 222 | ((CURSOR)->node \ | | ^ | | | | | (2) following ‘false’ branch... lib/cmap.h:253:10: note: in expansion of macro ‘CMAP_CURSOR_FOR_EACH__’ | 253 | CMAP_CURSOR_FOR_EACH__(NODE, &CURSOR_NAME, MEMBER); \ | | ^~~~~~~~~~~~~~~~~~~~~~ lib/cmap.h:257:11: note: in expansion of macro ‘CMAP_FOR_EACH__’ | 257 | CMAP_FOR_EACH__(NODE, MEMBER, CMAP, \ | | ^~~~~~~~~~~~~~~ lib/conntrack.c:494:5: note: in expansion of macro ‘CMAP_FOR_EACH’ | 494 | CMAP_FOR_EACH (conn, cm_node, &ct->conns) { | | ^~~~~~~~~~~~~ | ‘conntrack_destroy’: event 3 | |lib/cmap.h:222:5: | 222 | ((CURSOR)->node \ | | ^ | | | | | (3) ...to here lib/cmap.h:253:10: note: in expansion of macro ‘CMAP_CURSOR_FOR_EACH__’ | 253 | CMAP_CURSOR_FOR_EACH__(NODE, &CURSOR_NAME, MEMBER); \ | | ^~~~~~~~~~~~~~~~~~~~~~ lib/cmap.h:257:11: note: in expansion of macro ‘CMAP_FOR_EACH__’ | 257 | CMAP_FOR_EACH__(NODE, MEMBER, CMAP, \ | | ^~~~~~~~~~~~~~~ lib/conntrack.c:494:5: note: in expansion of macro ‘CMAP_FOR_EACH’ | 494 | CMAP_FOR_EACH (conn, cm_node, &ct->conns) { | | ^~~~~~~~~~~~~ | ‘conntrack_destroy’: event 4 | |lib/cmap.h:252:5: | 252 | for (struct cmap_cursor CURSOR_NAME = cmap_cursor_start(CMAP); \ | | ^~~ | | | | | (4) following ‘false’ branch... lib/cmap.h:257:11: note: in expansion of macro ‘CMAP_FOR_EACH__’ | 257 | CMAP_FOR_EACH__(NODE, MEMBER, CMAP, \ | | ^~~~~~~~~~~~~~~ lib/conntrack.c:494:5: note: in expansion of macro ‘CMAP_FOR_EACH’ | 494 | CMAP_FOR_EACH (conn, cm_node, &ct->conns) { | | ^~~~~~~~~~~~~ | ‘conntrack_destroy’: event 5 | | 497 | cmap_destroy(&ct->conns); | | ^~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | ‘conntrack_destroy’: event 6 | |./include/openvswitch/hmap.h:218:31: | 218 | INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \ ./include/openvswitch/util.h:131:17: note: in definition of macro ‘OBJECT_CONTAINING’ | 131 | ((char *) (POINTER) - OBJECT_OFFSETOF(OBJECT, MEMBER))) | | ^~~~~~~ ./include/openvswitch/util.h:146:23: note: in expansion of macro ‘ASSIGN_CONTAINER’ | 146 | ((OBJECT) = NULL, ASSIGN_CONTAINER(OBJECT, POINTER, MEMBER)) | | ^~~~~~~~~~~~~~~~ ./include/openvswitch/hmap.h:218:10: note: in expansion of macro ‘INIT_CONTAINER’ | 218 | INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \ | | ^~~~~~~~~~~~~~ lib/conntrack.c:500:5: note: in expansion of macro ‘HMAP_FOR_EACH_POP’ | 500 | HMAP_FOR_EACH_POP (zl, node, &ct->zone_limits) { | | ^~~~~~~~~~~~~~~~~ | +--> ‘hmap_pop_helper__’: events 7-12 | |./include/openvswitch/hmap.h:202:1: | 202 | hmap_pop_helper__(struct hmap *hmap, size_t *bucket) { | | ^~~~~~~~~~~~~~~~~ | | | | | (7) entry to ‘hmap_pop_helper__’ | 203 | | 204 | for (; *bucket <= hmap->mask; (*bucket)++) { | | ~~~ | | | | | (8) following ‘true’ branch... | 205 | struct hmap_node *node = hmap->buckets[*bucket]; | | ~~~~~~~~~~~~~ | | | | | (9) ...to here | 206 | | 207 | if (node) { | | ~ | | | | | (10) following ‘true’ branch (when ‘node’ is non-NULL)... | 208 | hmap_remove(hmap, node); | | ~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (11) ...to here | | (12) calling ‘hmap_remove’ from ‘hmap_pop_helper__’ | +--> ‘hmap_remove’: events 13-15 | | 290 | hmap_remove(struct hmap *hmap, struct hmap_node *node) | | ^~~~~~~~~~~ | | | | | (13) entry to ‘hmap_remove’ |...... | 293 | while (*bucket != node) { | | ~ | | | | | (14) following ‘false’ branch... |...... | 296 | *bucket = node->next; | | ~~~~~~~~~~ | | | | | (15) ...to here | <------+ | ‘hmap_pop_helper__’: event 16 | | 208 | hmap_remove(hmap, node); | | ^~~~~~~~~~~~~~~~~~~~~~~ | | | | | (16) returning to ‘hmap_pop_helper__’ from ‘hmap_remove’ | <------+ | ‘conntrack_destroy’: event 17 | | 218 | INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \ ./include/openvswitch/util.h:131:17: note: in definition of macro ‘OBJECT_CONTAINING’ | 131 | ((char *) (POINTER) - OBJECT_OFFSETOF(OBJECT, MEMBER))) | | ^~~~~~~ ./include/openvswitch/util.h:146:23: note: in expansion of macro ‘ASSIGN_CONTAINER’ | 146 | ((OBJECT) = NULL, ASSIGN_CONTAINER(OBJECT, POINTER, MEMBER)) | | ^~~~~~~~~~~~~~~~ ./include/openvswitch/hmap.h:218:10: note: in expansion of macro ‘INIT_CONTAINER’ | 218 | INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \ | | ^~~~~~~~~~~~~~ lib/conntrack.c:500:5: note: in expansion of macro ‘HMAP_FOR_EACH_POP’ | 500 | HMAP_FOR_EACH_POP (zl, node, &ct->zone_limits) { | | ^~~~~~~~~~~~~~~~~ | ‘conntrack_destroy’: event 18 | |./include/openvswitch/hmap.h:220:10: | 219 | (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) \ | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 220 | || ((NODE = NULL), false);) | | ^~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (18) following ‘true’ branch (when ‘zl’ is non-NULL)... lib/conntrack.c:500:5: note: in expansion of macro ‘HMAP_FOR_EACH_POP’ | 500 | HMAP_FOR_EACH_POP (zl, node, &ct->zone_limits) { | | ^~~~~~~~~~~~~~~~~ | ‘conntrack_destroy’: event 19 | |./include/openvswitch/hmap.h:220:10: | 219 | (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) \ | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 220 | || ((NODE = NULL), false);) | | ^~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (19) ...to here lib/conntrack.c:500:5: note: in expansion of macro ‘HMAP_FOR_EACH_POP’ | 500 | HMAP_FOR_EACH_POP (zl, node, &ct->zone_limits) { | | ^~~~~~~~~~~~~~~~~ | ‘conntrack_destroy’: event 20 | |./include/openvswitch/hmap.h:217:5: | 217 | for (size_t bucket__ = 0; \ | | ^~~ | | | | | (20) following ‘true’ branch... lib/conntrack.c:500:5: note: in expansion of macro ‘HMAP_FOR_EACH_POP’ | 500 | HMAP_FOR_EACH_POP (zl, node, &ct->zone_limits) { | | ^~~~~~~~~~~~~~~~~ | ‘conntrack_destroy’: event 21 | | 501 | free(zl); | | ^~~~~~~~ | | | | | (21) ...to here | ‘conntrack_destroy’: event 22 | |./include/openvswitch/hmap.h:218:31: | 218 | INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \ ./include/openvswitch/util.h:131:17: note: in definition of macro ‘OBJECT_CONTAINING’ | 131 | ((char *) (POINTER) - OBJECT_OFFSETOF(OBJECT, MEMBER))) | | ^~~~~~~ ./include/openvswitch/util.h:146:23: note: in expansion of macro ‘ASSIGN_CONTAINER’ | 146 | ((OBJECT) = NULL, ASSIGN_CONTAINER(OBJECT, POINTER, MEMBER)) | | ^~~~~~~~~~~~~~~~ ./include/openvswitch/hmap.h:218:10: note: in expansion of macro ‘INIT_CONTAINER’ | 218 | INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \ | | ^~~~~~~~~~~~~~ lib/conntrack.c:500:5: note: in expansion of macro ‘HMAP_FOR_EACH_POP’ | 500 | HMAP_FOR_EACH_POP (zl, node, &ct->zone_limits) { | | ^~~~~~~~~~~~~~~~~ | +--> ‘hmap_pop_helper__’: events 23-29 | |./include/openvswitch/hmap.h:202:1: | 202 | hmap_pop_helper__(struct hmap *hmap, size_t *bucket) { | | ^~~~~~~~~~~~~~~~~ | | | | | (23) entry to ‘hmap_pop_helper__’ | 203 | | 204 | for (; *bucket <= hmap->mask; (*bucket)++) { | | ~~~ | | | | | (24) following ‘true’ branch... | 205 | struct hmap_node *node = hmap->buckets[*bucket]; | | ~~~~~~~~~~~~~ | | | | | (25) ...to here | | (26) freed here | 206 | | 207 | if (node) { | | ~ | | | | | (27) following ‘true’ branch (when ‘node’ is non-NULL)... | 208 | hmap_remove(hmap, node); | | ~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (28) ...to here | | (29) calling ‘hmap_remove’ from ‘hmap_pop_helper__’ | +--> ‘hmap_remove’: events 30-31 | | 290 | hmap_remove(struct hmap *hmap, struct hmap_node *node) | | ^~~~~~~~~~~ | | | | | (30) entry to ‘hmap_remove’ | 291 | { | 292 | struct hmap_node **bucket = &hmap->buckets[node->hash & hmap->mask]; | | ~~~~~~~~~~ | | | | | (31) use after ‘free’ of ‘node’; freed at (26) |