public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug analyzer/103892] New: -Wanalyzer-double-free false positive when compiling libpipeline
@ 2022-01-02 22:52 cjwatson at ubuntu dot com
  2022-01-14 23:22 ` [Bug analyzer/103892] " dmalcolm at gcc dot gnu.org
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: cjwatson at ubuntu dot com @ 2022-01-02 22:52 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103892

            Bug ID: 103892
           Summary: -Wanalyzer-double-free false positive when compiling
                    libpipeline
           Product: gcc
           Version: 11.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: cjwatson at ubuntu dot com
  Target Milestone: ---

Created attachment 52109
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=52109&action=edit
reduced version of lib/pipeline.c

Using gcc (Debian 11.2.0-13) 11.2.0 from Debian unstable, I tried -fanalyzer on
https://gitlab.com/cjwatson/libpipeline, and I ran into what looks like a false
positive from -Wanalyzer-double-free.  I've attached a test case that's reduced
as far as I could.  There's no double-free here, just fairly straightforward
freeing of elements of a tagged union, but it looks like the analyzer is
perhaps getting confused by the fact that the freeing is recursive?  (The
argstr_get_word and pipecmd_new_argstr functions appear entirely superfluous to
the problem, and I trimmed down their bodies as far as I could, but if I remove
anything else from them then the problem goes away.)

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 11.2.0-13'
--with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs
--enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr
--with-gcc-major-version-only --program-suffix=-11
--program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id
--libexecdir=/usr/lib --without-included-gettext --enable-threads=posix
--libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu
--enable-libstdcxx-debug --enable-libstdcxx-time=yes
--with-default-libstdcxx-abi=new --enable-gnu-unique-object
--disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib
--enable-libphobos-checking=release --with-target-system-zlib=auto
--enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet
--with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32
--enable-multilib --with-tune=generic
--enable-offload-targets=nvptx-none=/build/gcc-11-KdLYb3/gcc-11-11.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-11-KdLYb3/gcc-11-11.2.0/debian/tmp-gcn/usr
--without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu
--with-build-config=bootstrap-lto-lean --enable-link-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.2.0 (Debian 11.2.0-13)
$ gcc -save-temps -fanalyzer -Wall -Wno-analyzer-malloc-leak
-Wanalyzer-too-complex -g -O2 -Wall -c t.c -fPIC -DPIC -o t.o
t.c: In function ‘pipecmd_free’:
cc1: warning: terminating analysis for this program point: callstring: [(SN: 14
-> SN: 9 in pipecmd_free)] before (SN: 6 stmt: 0):  <L13>:EN: 67, EN: 77, EN:
87, EN: 97, EN: 107, EN: 117, EN: 127, EN: 137 [-Wanalyzer-too-complex]
t.c: At top level:
t.c:43:6: warning: analysis bailed out early (131 'after-snode' enodes; 491
enodes) [-Wanalyzer-too-complex]
   43 | void pipecmd_free (struct pipecmd *cmd)
      |      ^~~~~~~~~~~~
t.c: In function ‘pipecmd_free’:
t.c:56:25: warning: double-‘free’ of ‘*(struct pipecmd_process *)((char *)cmd +
8).argv’ [CWE-415] [-Wanalyzer-double-free]
   56 |                         free (cmdp->argv);
      |                         ^~~~~~~~~~~~~~~~~
  ‘pipecmd_free’: events 1-4
    |
    |   43 | void pipecmd_free (struct pipecmd *cmd)
    |      |      ^~~~~~~~~~~~
    |      |      |
    |      |      (1) entry to ‘pipecmd_free’
    |......
    |   47 |         if (!cmd)
    |      |            ~
    |      |            |
    |      |            (2) following ‘false’ branch (when ‘cmd’ is
non-NULL)...
    |......
    |   50 |         switch (cmd->tag) {
    |      |         ~~~~~~
    |      |         |
    |      |         (3) ...to here
    |      |         (4) following ‘case 1:’ branch...
    |
  ‘pipecmd_free’: event 5
    |
    |cc1:
    | (5): ...to here
    |
  ‘pipecmd_free’: events 6-8
    |
    |   64 |                         for (i = 0; i < cmds->ncommands; ++i)
    |      |                                     ~~^~~~~~~~~~~~~~~~~
    |      |                                       |
    |      |                                       (6) following ‘true’
branch...
    |   65 |                                 pipecmd_free (cmds->commands[i]);
    |      |                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                                 |
    |      |                                 (7) ...to here
    |      |                                 (8) calling ‘pipecmd_free’ from
‘pipecmd_free’
    |
    +--> ‘pipecmd_free’: events 9-12
           |
           |   43 | void pipecmd_free (struct pipecmd *cmd)
           |      |      ^~~~~~~~~~~~
           |      |      |
           |      |      (9) entry to ‘pipecmd_free’
           |......
           |   47 |         if (!cmd)
           |      |            ~
           |      |            |
           |      |            (10) following ‘false’ branch (when ‘cmd’ is
non-NULL)...
           |......
           |   50 |         switch (cmd->tag) {
           |      |         ~~~~~~
           |      |         |
           |      |         (11) ...to here
           |      |         (12) following ‘case 1:’ branch...
           |
         ‘pipecmd_free’: event 13
           |
           |cc1:
           | (13): ...to here
           |
         ‘pipecmd_free’: events 14-16
           |
           |   64 |                         for (i = 0; i < cmds->ncommands;
++i)
           |      |                                     ~~^~~~~~~~~~~~~~~~~
           |      |                                       |
           |      |                                       (14) following ‘true’
branch...
           |   65 |                                 pipecmd_free
(cmds->commands[i]);
           |      |                                
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                                 |
           |      |                                 (15) ...to here
           |      |                                 (16) calling ‘pipecmd_free’
from ‘pipecmd_free’
           |
           +--> ‘pipecmd_free’: events 17-18
                  |
                  |   43 | void pipecmd_free (struct pipecmd *cmd)
                  |      |      ^~~~~~~~~~~~
                  |      |      |
                  |      |      (17) entry to ‘pipecmd_free’
                  |......
                  |   47 |         if (!cmd)
                  |      |            ~
                  |      |            |
                  |      |            (18) following ‘true’ branch (when ‘cmd’
is NULL)...
                  |
                ‘pipecmd_free’: event 19
                  |
                  |cc1:
                  | (19): ...to here
                  |
           <------+
           |
         ‘pipecmd_free’: events 20-23
           |
           |   64 |                         for (i = 0; i < cmds->ncommands;
++i)
           |      |                                     ~~~~~~~~~~~~~~~~~~~
           |      |                                       |
           |      |                                       (21) following ‘true’
branch...
           |   65 |                                 pipecmd_free
(cmds->commands[i]);
           |      |                                
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                                 |
           |      |                                 (20) returning to
‘pipecmd_free’ from ‘pipecmd_free’
           |      |                                 (22) ...to here
           |      |                                 (23) calling ‘pipecmd_free’
from ‘pipecmd_free’
           |
           +--> ‘pipecmd_free’: events 24-25
                  |
                  |   43 | void pipecmd_free (struct pipecmd *cmd)
                  |      |      ^~~~~~~~~~~~
                  |      |      |
                  |      |      (24) entry to ‘pipecmd_free’
                  |......
                  |   56 |                         free (cmdp->argv);
                  |      |                         ~~~~~~~~~~~~~~~~~
                  |      |                         |
                  |      |                         (25) first ‘free’ here
                  |
           <------+
           |
         ‘pipecmd_free’: events 26-31
           |
           |   64 |                         for (i = 0; i < cmds->ncommands;
++i)
           |      |                                     ~~~~~~~~~~~~~~~~~~~
           |      |                                       |
           |      |                                       (27) following ‘true’
branch...
           |      |                                       (29) following ‘true’
branch...
           |   65 |                                 pipecmd_free
(cmds->commands[i]);
           |      |                                
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                                 |
           |      |                                 (26) returning to
‘pipecmd_free’ from ‘pipecmd_free’
           |      |                                 (28) ...to here
           |      |                                 (30) ...to here
           |      |                                 (31) calling ‘pipecmd_free’
from ‘pipecmd_free’
           |
           +--> ‘pipecmd_free’: events 32-33
                  |
                  |   43 | void pipecmd_free (struct pipecmd *cmd)
                  |      |      ^~~~~~~~~~~~
                  |      |      |
                  |      |      (32) entry to ‘pipecmd_free’
                  |......
                  |   56 |                         free (cmdp->argv);
                  |      |                         ~~~~~~~~~~~~~~~~~
                  |      |                         |
                  |      |                         (33) second ‘free’ here;
first ‘free’ was at (25)
                  |

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug analyzer/103892] -Wanalyzer-double-free false positive when compiling libpipeline
  2022-01-02 22:52 [Bug analyzer/103892] New: -Wanalyzer-double-free false positive when compiling libpipeline cjwatson at ubuntu dot com
@ 2022-01-14 23:22 ` dmalcolm at gcc dot gnu.org
  2022-04-08 18:03 ` dmalcolm at gcc dot gnu.org
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: dmalcolm at gcc dot gnu.org @ 2022-01-14 23:22 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103892

David Malcolm <dmalcolm at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
     Ever confirmed|0                           |1
   Last reconfirmed|                            |2022-01-14
             Status|UNCONFIRMED                 |ASSIGNED

--- Comment #1 from David Malcolm <dmalcolm at gcc dot gnu.org> ---
Thanks for filing this; it does indeed look like a false positive.

I can reproduce it with trunk; will investigate further.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug analyzer/103892] -Wanalyzer-double-free false positive when compiling libpipeline
  2022-01-02 22:52 [Bug analyzer/103892] New: -Wanalyzer-double-free false positive when compiling libpipeline cjwatson at ubuntu dot com
  2022-01-14 23:22 ` [Bug analyzer/103892] " dmalcolm at gcc dot gnu.org
@ 2022-04-08 18:03 ` dmalcolm at gcc dot gnu.org
  2022-04-09 22:14 ` cvs-commit at gcc dot gnu.org
  2022-04-09 22:26 ` dmalcolm at gcc dot gnu.org
  3 siblings, 0 replies; 5+ messages in thread
From: dmalcolm at gcc dot gnu.org @ 2022-04-08 18:03 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103892

--- Comment #2 from David Malcolm <dmalcolm at gcc dot gnu.org> ---
Still affects trunk

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug analyzer/103892] -Wanalyzer-double-free false positive when compiling libpipeline
  2022-01-02 22:52 [Bug analyzer/103892] New: -Wanalyzer-double-free false positive when compiling libpipeline cjwatson at ubuntu dot com
  2022-01-14 23:22 ` [Bug analyzer/103892] " dmalcolm at gcc dot gnu.org
  2022-04-08 18:03 ` dmalcolm at gcc dot gnu.org
@ 2022-04-09 22:14 ` cvs-commit at gcc dot gnu.org
  2022-04-09 22:26 ` dmalcolm at gcc dot gnu.org
  3 siblings, 0 replies; 5+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2022-04-09 22:14 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103892

--- Comment #3 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by David Malcolm <dmalcolm@gcc.gnu.org>:

https://gcc.gnu.org/g:3d41408c5d28105e7a3ea2eb2529431a70b96369

commit r12-8071-g3d41408c5d28105e7a3ea2eb2529431a70b96369
Author: David Malcolm <dmalcolm@redhat.com>
Date:   Sat Apr 9 18:12:57 2022 -0400

    analyzer: fix folding of regions involving unknown ptrs [PR103892]

    PR analyzer/103892 reports a false positive from -Wanalyzer-double-free.

    The root cause is the analyzer failing to properly handle "unknown"
    symbolic regions, and thus confusing two different expressions.

    Specifically, the analyzer eventually hits the complexity limit for
    symbolic values, and starts using an "unknown" svalue for a pointer.
    The analyzer uses
      symbolic_region(unknown_svalue([of ptr type]))
    i.e.
      (*UNKNOWN_PTR)
    in a few places to mean "we have an lvalue, but we're not going to
    attempt to track what it is anymore".

    "Unknown" should probably be renamed to "unknowable"; in theory, any
    operation on such an unknown svalue should be also an unknown svalue.

    The issue is that in various places where we create child regions, we
    were failing to check for the parent region being (*UNKNOWN_PTR), and so
    were erroneously creating regions based on (*UNKNOWN_PTR), such as
    *(UNKNOWN_PTR + OFFSET).  The state-machine handling was erroneously
    allowing e.g. INITIAL_VALUE (*(UNKNOWN_PTR + OFFSET)) to have state,
    and thus we could record that such a value had had "free" called on it,
    and thus eventually false report a double-free when a different
    expression incorrectly "simplified" to the same expression.

    This patch fixes things by checking when creating the various kinds of
    child region for (*UNKNOWN_PTR) as the parent region, and simply
    returning another (*UNKNOWN_PTR) for such child regions (using the
    appropriate type).

    Doing so fixes the false positive, and also fixes a state explosion on
    this testcase, as the states at the program points more rapidly reach
    a fixed point where everything is unknown.  I checked for other cases
    that no longer needed -Wno-analyzer-too-complex; the only other one
    seems to be gcc.dg/analyzer/pr96841.c, but that seems to already have
    become redundant at some point before this patch.

    gcc/analyzer/ChangeLog:
            PR analyzer/103892
            * region-model-manager.cc
            (region_model_manager::get_unknown_symbolic_region): New,
            extracted from...
            (region_model_manager::get_field_region): ...here.
            (region_model_manager::get_element_region): Use it here.
            (region_model_manager::get_offset_region): Likewise.
            (region_model_manager::get_sized_region): Likewise.
            (region_model_manager::get_cast_region): Likewise.
            (region_model_manager::get_bit_range): Likewise.
            * region-model.h
            (region_model_manager::get_unknown_symbolic_region): New decl.
            * region.cc (symbolic_region::symbolic_region): Handle sval_ptr
            having NULL type.
            (symbolic_region::dump_to_pp): Handle having NULL type.

    gcc/testsuite/ChangeLog:
            PR analyzer/103892
            * gcc.dg/analyzer/pr103892.c: New test.
            * gcc.dg/analyzer/pr96841.c: Drop redundant
            -Wno-analyzer-too-complex.

    Signed-off-by: David Malcolm <dmalcolm@redhat.com>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug analyzer/103892] -Wanalyzer-double-free false positive when compiling libpipeline
  2022-01-02 22:52 [Bug analyzer/103892] New: -Wanalyzer-double-free false positive when compiling libpipeline cjwatson at ubuntu dot com
                   ` (2 preceding siblings ...)
  2022-04-09 22:14 ` cvs-commit at gcc dot gnu.org
@ 2022-04-09 22:26 ` dmalcolm at gcc dot gnu.org
  3 siblings, 0 replies; 5+ messages in thread
From: dmalcolm at gcc dot gnu.org @ 2022-04-09 22:26 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103892

David Malcolm <dmalcolm at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |FIXED
             Status|ASSIGNED                    |RESOLVED

--- Comment #4 from David Malcolm <dmalcolm at gcc dot gnu.org> ---
Should be fixed by the above patch on trunk for GCC 12.  Backporting the fix to
GCC 11 is probably not feasible.

Marking as resolved.

Thanks again for filing this bug.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-04-09 22:26 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-02 22:52 [Bug analyzer/103892] New: -Wanalyzer-double-free false positive when compiling libpipeline cjwatson at ubuntu dot com
2022-01-14 23:22 ` [Bug analyzer/103892] " dmalcolm at gcc dot gnu.org
2022-04-08 18:03 ` dmalcolm at gcc dot gnu.org
2022-04-09 22:14 ` cvs-commit at gcc dot gnu.org
2022-04-09 22:26 ` dmalcolm at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).