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

Reply via email to