public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug analyzer/106436] New: -Wanalyzer-null-dereference false positive suggests data corruption in GCC
@ 2022-07-25 16:37 eggert at cs dot ucla.edu
  0 siblings, 0 replies; only message in thread
From: eggert at cs dot ucla.edu @ 2022-07-25 16:37 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 106436
           Summary: -Wanalyzer-null-dereference false positive suggests
                    data corruption in GCC
           Product: gcc
           Version: 12.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: eggert at cs dot ucla.edu
  Target Milestone: ---

Created attachment 53347
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53347&action=edit
Compile with -O2 -S -fanalyzer (GCC 12 x86-64) to reproduce the bug.

I found this problem when compiling Gnu Tar with GCC 12.1.1 20220507 (Red Hat
12.1.1-1) on x86-64. Compile the attached program t.i with:

gcc -O2 -S -fanalyzer t.i

The output is below. The first diagnostic is a false positive. Attempting to
silence it by inserting "if (!listed_loc) abort ();" before line 13975 causes
unrelated diagnostics to change, suggesting that there's some sort of confusion
in the internal data structure that GCC uses to represent the program.

        t.i: In function ‘optloc_eq’:
        t.i:12193:8: warning: dereference of NULL ‘a’ [CWE-476]
[-Wanalyzer-null-dereference]
        12193 |   if (a->source != b->source)
              |       ~^~~~~~~~
          ‘main’: events 1-4
            |
            |14348 | main (int argc, char **argv)
            |      | ^~~~
            |      | |
            |      | (1) entry to ‘main’
            |......
            |14373 |   if (stdopen ())
            |      |      ~
            |      |      |
            |      |      (2) following ‘false’ branch...
            |......
            |14383 |   allocated_archive_names = 10;
            |      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            |      |                           |
            |      |                           (3) ...to here
            |......
            |14400 |   decode_options (argc, argv);
            |      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
            |      |   |
            |      |   (4) calling ‘decode_options’ from ‘main’
            |
            +--> ‘decode_options’: events 5-7
                   |
                   |13764 | decode_options (int argc, char **argv)
                   |      | ^~~~~~~~~~~~~~
                   |      | |
                   |      | (5) entry to ‘decode_options’
                   |......
                   |13767 |   struct option_locus loc = { OPTS_COMMAND_LINE, 0,
0, 0 };
                   |      |                       ~~~
                   |      |                       |
                   |      |                       (6) ‘loc.prev’ is NULL
                   |......
                   |13890 |   parse_default_options (&args);
                   |      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                   |      |   |
                   |      |   (7) calling ‘parse_default_options’ from
‘decode_options’
                   |
                   +--> ‘parse_default_options’: events 8-10
                          |
                          |13721 | parse_default_options (struct tar_args
*args)
                          |      | ^~~~~~~~~~~~~~~~~~~~~
                          |      | |
                          |      | (8) entry to ‘parse_default_options’
                          |......
                          |13725 |   struct option_locus loc = { OPTS_ENVIRON,
"TAR_OPTIONS", 0, 0 };
                          |      |                       ~~~
                          |      |                       |
                          |      |                       (9) ‘loc.prev’ is NULL
                          |      |                       (10) ‘loc.prev’ is
NULL
                          |
                   <------+
                   |
                 ‘decode_options’: events 11-20
                   |
                   |12176 |   return option_class[id];
                   |      |          ~~~~~~~~~~~~~~~~
                   |      |                      |
                   |      |                      (17) ...to here
                   |      |                      (18) ‘0’ is NULL
                   |      |                      (19) ‘0’ is NULL
                   |......
                   |13890 |   parse_default_options (&args);
                   |      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                   |      |   |
                   |      |   (11) returning to ‘decode_options’ from
‘parse_default_options’
                   |13891 | 
                   |13892 |   if (argp_parse (&argp, argc, argv, 0x08, &idx,
&args))
                   |      |      ~
                   |      |      |
                   |      |      (12) following ‘false’ branch...
                   |13893 |     exit (2);
                   |13894 |   if (args.o_option)
                   |      |       ~~~~~~~~~~~~~
                   |      |           |
                   |      |           (13) ...to here
                   |......
                   |13970 |   if (listed_incremental_option
                   |      |      ~~~~~~~~~~~~~~~~~~~~~~~~~~
                   |      |      |
                   |      |      (14) following ‘true’ branch...
                   |13971 |       && (0 <= (newer_mtime_option).tv_nsec))
                   |      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                   |      |       |                            |
                   |      |       |                            (15) ...to here
                   |      |       (16) following ‘true’ branch...
                   |......
                   |13975 |       if (optloc_eq (listed_loc, newer_loc))
                   |      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                   |      |           |
                   |      |           (20) calling ‘optloc_eq’ from
‘decode_options’
                   |
                   +--> ‘optloc_eq’: events 21-22
                          |
                          |12191 | optloc_eq (struct option_locus *a, struct
option_locus *b)
                          |      | ^~~~~~~~~
                          |      | |
                          |      | (21) entry to ‘optloc_eq’
                          |12192 | {
                          |12193 |   if (a->source != b->source)
                          |      |       ~~~~~~~~~
                          |      |        |
                          |      |        (22) dereference of NULL ‘a’
                          |
        t.i: In function ‘get_date_or_file’:
        t.i:12354:23: warning: leak of ‘p’ [CWE-401] [-Wanalyzer-malloc-leak]
        12354 |    args->textual_date = p;
              |    ~~~~~~~~~~~~~~~~~~~^~~
          ‘parse_opt’: events 1-4
            |
            |12682 | parse_opt (int key, char *arg, struct argp_state *state)
            |      | ^~~~~~~~~
            |      | |
            |      | (1) entry to ‘parse_opt’
            |......
            |12686 |   switch (key)
            |      |   ~~~~~~
            |      |   |
            |      |   (2) following ‘case 152:’ branch...
            |......
            |12946 |     case MTIME_OPTION:
            |      |     ~~~~
            |      |     |
            |      |     (3) ...to here
            |12947 |       get_date_or_file (args, "--mtime", arg,
&mtime_option);
            |      |      
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            |      |       |
            |      |       (4) calling ‘get_date_or_file’ from ‘parse_opt’
            |
            +--> ‘get_date_or_file’: events 5-13
                   |
                   |12303 | get_date_or_file (struct tar_args *args, const char
*rpl_option,
                   |      | ^~~~~~~~~~~~~~~~
                   |      | |
                   |      | (5) entry to ‘get_date_or_file’
                   |......
                   |12307 |      ((void) (
                   |      |      ~~~~~~~~~
                   |12308 |      str
                   |      |      ~~~
                   |12309 |      ), 0)
                   |      |      ~~~~~
                   |12310 |                                   != 0
                   |      |                                   ~~~~
                   |12311 |       ||
                   |      |       ~~
                   |      |       |
                   |      |       (6) following ‘false’ branch...
                   |12312 |         ((
                   |      |         ~~
                   |12313 |         *str
                   |      |         ~~~~
                   |12314 |         ) == '/')
                   |      |         ~~~~~~~~~
                   |12315 | 
                   |      |  
                   |12316 |      || *str == '.')
                   |      |      ~~~~~~~~~~~~~~
                   |      |      |
                   |      |      (7) ...to here
                   |      |      (8) following ‘false’ branch...
                   |......
                   |12332 |       if (! parse_datetime (ts, str,
                   |      |          ~  ~~~~~~~~~~~~~~~~~~~~~~~~
                   |      |          |  |
                   |      |          |  (9) ...to here
                   |      |          (10) following ‘true’ branch...
                   |12333 |                                     ((void *)0)
                   |      |                                     ~~~~~~~~~~~
                   |12334 |                                         ))
                   |      |                                         ~
                   |......
                   |12349 |    struct textual_date *p = xmalloc (sizeof (*p));
                   |      |                             ~~~~~~~~~~~~~~~~~~~~~
                   |      |                             |
                   |      |                             (11) ...to here
                   |      |                             (12) allocated here
                   |......
                   |12354 |    args->textual_date = p;
                   |      |    ~~~~~~~~~~~~~~~~~~~~~~
                   |      |                       |
                   |      |                       (13) ‘p’ leaks here; was
allocated at (12)
                   |
        t.i: In function ‘decode_options’:
        t.i:13862:35: warning: leak of ‘xstrdup(&buffer)’ [CWE-401]
[-Wanalyzer-malloc-leak]
        13862 |    opt = find_argp_option (&argp, *letter);
              |                                   ^~~~~~~
          ‘decode_options’: events 1-7
            |
            |13764 | decode_options (int argc, char **argv)
            |      | ^~~~~~~~~~~~~~
            |      | |
            |      | (1) entry to ‘decode_options’
            |......
            |13831 |   if (argc > 1 && argv[1][0] != '-')
            |      |      ~
            |      |      |
            |      |      (2) following ‘true’ branch...
            |......
            |13842 |       buffer[0] = '-';
            |      |       ~~~~~~~~~~~~~~~
            |      |                 |
            |      |                 (3) ...to here
            |......
            |13856 |       for (letter = *in++; *letter; letter++)
            |      |                            ~
            |      |                            |
            |      |                            (4) following ‘true’ branch...
            |......
            |13860 |    buffer[1] = *letter;
            |      |    ~~~~~~~~~~~~~~~~~~~
            |      |              |
            |      |              (5) ...to here
            |13861 |    *out++ = xstrdup (buffer);
            |      |             ~~~~~~~~~~~~~~~~
            |      |             |
            |      |             (6) allocated here
            |13862 |    opt = find_argp_option (&argp, *letter);
            |      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            |      |          |
            |      |          (7) calling ‘find_argp_option’ from
‘decode_options’
            |
            +--> ‘find_argp_option’: events 8-10
                   |
                   |13655 | find_argp_option (struct argp *ap, int key)
                   |      | ^~~~~~~~~~~~~~~~
                   |      | |
                   |      | (8) entry to ‘find_argp_option’
                   |......
                   |13663 |   if (!p && ap->children)
                   |      |      ~
                   |      |      |
                   |      |      (9) following ‘false’ branch (when ‘p’ is
non-NULL)...
                   |......
                   |13672 |   return p;
                   |      |          ~
                   |      |          |
                   |      |          (10) ...to here
                   |
            <------+
            |
          ‘decode_options’: events 11-17
            |
            |13856 |       for (letter = *in++; *letter; letter++)
            |      |                            ~
            |      |                            |
            |      |                            (14) following ‘true’ branch...
            |......
            |13860 |    buffer[1] = *letter;
            |      |    ~~~~~~~~~~~~~~~~~~~
            |      |              |
            |      |              (15) ...to here
            |13861 |    *out++ = xstrdup (buffer);
            |      |             ~~~~~~~~~~~~~~~~
            |      |             |
            |      |             (16) allocated here
            |13862 |    opt = find_argp_option (&argp, *letter);
            |      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            |      |          |                        |
            |      |          |                        (17) ‘xstrdup(&buffer)’
leaks here; was allocated at (16)
            |      |          (11) returning to ‘decode_options’ from
‘find_argp_option’
            |13863 |    if (opt && opt->arg)
            |      |       ~       ~~~~~~~~
            |      |       |          |
            |      |       |          (13) ...to here
            |      |       (12) following ‘true’ branch (when ‘opt’ is
non-NULL)...
            |

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-07-25 16:37 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-25 16:37 [Bug analyzer/106436] New: -Wanalyzer-null-dereference false positive suggests data corruption in GCC eggert at cs dot ucla.edu

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).