https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108045
Bug ID: 108045 Summary: analyzer: false positive memory leak Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: analyzer Assignee: dmalcolm at gcc dot gnu.org Reporter: jamie.bainbridge at gmail dot com Target Milestone: --- Created attachment 54060 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=54060&action=edit minimal reproducer The analyzer detects a memory leak here, but I don't think there is one. It seems not to have understood that I've kept the reference to "new_scr" (and its child allocation) in the global "ctx->scr" when I swap the pointers on line 80/81 with: struct screen_s *old_scr = ctx->scr; ctx->scr = new_scr; I found that if I omit the body of resize_screen() and place its instructions directly in main(), then the analyzer doesn't report anything is wrong. It seems the extra layer of indirection with the resize_screen() function trips it up. This problem happens with GCC 11.3.0, 12.1.0, and 13.0-20221209 nightly from Compiler Explorer. Full output from CE nightly below, using these options: -v -save-temps -g3 -Og -std=c99 -Wall -Wextra -Wpedantic -fanalyzer Using built-in specs. COLLECT_GCC=/opt/compiler-explorer/gcc-snapshot/bin/gcc Target: x86_64-linux-gnu Configured with: ../gcc-trunk-20221209/configure --prefix=/opt/compiler-explorer/gcc-build/staging --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --disable-bootstrap --enable-multiarch --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --enable-clocale=gnu --enable-languages=c,c++,fortran,ada,objc,obj-c++,d --enable-ld=yes --enable-gold=yes --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-linker-build-id --enable-lto --enable-plugins --enable-threads=posix --with-pkgversion=Compiler-Explorer-Build-gcc-e6110da479951b759a12c5618f5304187b650326-binutils-2.38 --enable-libstdcxx-backtrace=yes Thread model: posix Supported LTO compression algorithms: zlib gcc version 13.0.0 20221209 (experimental) (Compiler-Explorer-Build-gcc-e6110da479951b759a12c5618f5304187b650326-binutils-2.38) COLLECT_GCC_OPTIONS='-fdiagnostics-color=always' '-g' '-o' '/app/output.s' '-masm=intel' '-S' '-v' '-save-temps' '-g3' '-Og' '-std=c99' '-Wall' '-Wextra' '-Wpedantic' '-fanalyzer' '-mtune=generic' '-march=x86-64' '-dumpdir' '/app/' /opt/compiler-explorer/gcc-trunk-20221209/bin/../libexec/gcc/x86_64-linux-gnu/13.0.0/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu -iprefix /opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/ -dD <source> -masm=intel -mtune=generic -march=x86-64 -std=c99 -Wall -Wextra -Wpedantic -fdiagnostics-color=always -fanalyzer -g -g3 -fworking-directory -Og -fpch-preprocess -o /app/output.i ignoring nonexistent directory "/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/../../../../x86_64-linux-gnu/include" ignoring duplicate directory "/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/13.0.0/include" ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring duplicate directory "/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/13.0.0/include-fixed/x86_64-linux-gnu" ignoring duplicate directory "/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/13.0.0/include-fixed" ignoring nonexistent directory "/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/13.0.0/../../../../x86_64-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/include /opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/include-fixed/x86_64-linux-gnu /opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/include-fixed /usr/local/include /opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/../../include /usr/include/x86_64-linux-gnu /usr/include End of search list. COLLECT_GCC_OPTIONS='-fdiagnostics-color=always' '-g' '-o' '/app/output.s' '-masm=intel' '-S' '-v' '-save-temps' '-g3' '-Og' '-std=c99' '-Wall' '-Wextra' '-Wpedantic' '-fanalyzer' '-mtune=generic' '-march=x86-64' '-dumpdir' '/app/' /opt/compiler-explorer/gcc-trunk-20221209/bin/../libexec/gcc/x86_64-linux-gnu/13.0.0/cc1 -fpreprocessed /app/output.i -quiet -dumpdir /app/ -dumpbase output.c -dumpbase-ext .c -masm=intel -mtune=generic -march=x86-64 -g -g3 -Og -Wall -Wextra -Wpedantic -std=c99 -version -fdiagnostics-color=always -fanalyzer -o /app/output.s GNU C99 (Compiler-Explorer-Build-gcc-e6110da479951b759a12c5618f5304187b650326-binutils-2.38) version 13.0.0 20221209 (experimental) (x86_64-linux-gnu) compiled by GNU C version 9.4.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 GNU C99 (Compiler-Explorer-Build-gcc-e6110da479951b759a12c5618f5304187b650326-binutils-2.38) version 13.0.0 20221209 (experimental) (x86_64-linux-gnu) compiled by GNU C version 9.4.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 Compiler executable checksum: 18c5716274d15bcd60b31c3cdaf8ef4d <source>: In function 'screen_destroy': <source>:67:9: warning: leak of '<unknown>' [CWE-401] [-Wanalyzer-malloc-leak] 67 | free(scr); | ^~~~~~~~~ 'resize_screen': event 1 | | 70 | void resize_screen(size_t cols, size_t rows) | | ^~~~~~~~~~~~~ | | | | | (1) entry to 'resize_screen' | 'resize_screen': event 2 | |<source>:74:19: | 74 | new_scr = screen_create(cols, rows); | | ^~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (2) calling 'screen_create' from 'resize_screen' | +--> 'screen_create': event 3 | |<source>:27:18: | 27 | struct screen_s *screen_create(size_t cols, size_t rows) | | ^~~~~~~~~~~~~ | | | | | (3) entry to 'screen_create' | 'screen_create': event 4 | |<source>:32:12: | 32 | if (!result) | | ^ | | | | | (4) following 'false' branch (when 'result' is non-NULL)... | 'screen_create': events 5-8 | |<source>:35:9: | 35 | result->cols = cols; | | ^~~~~~ | | | | | (5) ...to here |...... | 39 | result->data = calloc(rows, sizeof(result->data) + sizeof(*result->data) * cols); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (6) allocated here | 40 | if (!result->data) { | | ~ | | | | | (7) assuming 'calloc(rows, (cols + 1) * 8)' is non-NULL | | (8) following 'false' branch... | 'screen_create': events 9-10 | |<source>:46:9: | 46 | char *ptr = (char *)(result->data + rows); | | ^~~~ | | | | | (9) ...to here |...... | 49 | for (size_t row = 0; row < rows; row++) | | ~~~~~~~~~~ | | | | | (10) following 'false' branch (when 'row >= rows')... | 'screen_create': event 11 | |cc1: | (11): ...to here | <------+ | 'resize_screen': events 12-15 | |<source>:74:19: | 74 | new_scr = screen_create(cols, rows); | | ^~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (12) returning to 'resize_screen' from 'screen_create' | 75 | if (!new_scr) { | | ~ | | | | | (13) following 'false' branch (when 'new_scr' is non-NULL)... |...... | 80 | struct screen_s *old_scr = ctx->scr; | | ~~~~~~ | | | | | (14) ...to here |...... | 86 | screen_destroy(old_scr); | | ~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (15) calling 'screen_destroy' from 'resize_screen' | +--> 'screen_destroy': events 16-18 | |<source>:56:6: | 56 | void screen_destroy(struct screen_s *scr) | | ^~~~~~~~~~~~~~ | | | | | (16) entry to 'screen_destroy' | 57 | { | 58 | if (!scr) | | ~ | | | | | (17) following 'false' branch (when 'scr' is non-NULL)... |...... | 61 | free(scr->data); | | ~~~~ | | | | | (18) ...to here | 'screen_destroy': event 19 | |<source>:67:9: | 67 | free(scr); | | ^~~~~~~~~ | | | | | (19) '<unknown>' leaks here; was allocated at (6) | COMPILER_PATH=/opt/compiler-explorer/gcc-trunk-20221209/bin/../libexec/gcc/x86_64-linux-gnu/13.0.0/:/opt/compiler-explorer/gcc-trunk-20221209/bin/../libexec/gcc/x86_64-linux-gnu/:/opt/compiler-explorer/gcc-trunk-20221209/bin/../libexec/gcc/:/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/../../../../x86_64-linux-gnu/bin/ LIBRARY_PATH=/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/:/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/:/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/:/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib64/:/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/../../../../x86_64-linux-gnu/lib/:/opt/compiler-explorer/gcc-trunk-20221209/bin/../lib/gcc/x86_64-linux-gnu/13.0.0/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-fdiagnostics-color=always' '-g' '-o' '/app/output.s' '-masm=intel' '-S' '-v' '-save-temps' '-g3' '-Og' '-std=c99' '-Wall' '-Wextra' '-Wpedantic' '-fanalyzer' '-mtune=generic' '-march=x86-64' '-dumpdir' '/app/output.' Compiler returned: 0