public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug analyzer/106428] New: -Wanalyzer-file-leak false positive with if ((ptr = fopen(...)) == NULL) ...
@ 2022-07-24 20:40 eggert at cs dot ucla.edu
0 siblings, 0 replies; only message in thread
From: eggert at cs dot ucla.edu @ 2022-07-24 20:40 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106428
Bug ID: 106428
Summary: -Wanalyzer-file-leak false positive with if ((ptr =
fopen(...)) == NULL) ...
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 53342
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53342&action=edit
Compile with '-O2 -S -fanalyzer' to demonstrate the bug
This is GCC 12.1.1 20220507 (Red Hat 12.1.1-1) on x86-64. Compile the attached
program t.i with 'gcc -fanalyzer -O2 -S t.i'. It outputs a false alarm as shown
at the end of this comment. If I replace lines 12046-12049:
if ((ent->v.file.fp = fopen (ent->v.file.name, "r")) ==
((void *)0)
)
open_fatal (ent->v.file.name);
with the following (which is equivalent, since ent->v.file.fp is NULL before
the code is executed):
FILE *fp = fopen (ent->v.file.name, "r");
if (!fp)
open_fatal (ent->v.file.name);
ent->v.file.fp = fp;
then the first diagnostic, which is a false positive, goes away.
Here is the diagnostic output, the first of which is the false positive.
t.i: In function ‘read_next_name’:
t.i:12046:7: warning: leak of FILE ‘fopen(*ent.v.file.name, "r")’
[CWE-775] [-Wanalyzer-file-leak]
12046 | if ((ent->v.file.fp = fopen (ent->v.file.name, "r")) ==
| ^
‘name_scan’: events 1-2
|
|13033 | name_scan (const char *file_name)
| | ^~~~~~~~~
| | |
| | (1) entry to ‘name_scan’
|......
|13039 | struct name *cursor = namelist_match (file_name,
length);
| |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) calling ‘namelist_match’
from ‘name_scan’
|
+--> ‘namelist_match’: events 3-5
|
|12316 | namelist_match (char const *file_name, size_t
length)
| | ^~~~~~~~~~~~~~
| | |
| | (3) entry to ‘namelist_match’
|......
|12320 | for (p = namelist; p; p = p->next)
| | ~
| | |
| | (4) following ‘true’ branch
(when ‘p’ is non-NULL)...
|12321 | {
|12322 | if (p->name[0]
| | ~~~~~~~
| | |
| | (5) ...to here
|
<------+
|
‘name_scan’: events 6-11
|
|13039 | struct name *cursor = namelist_match (file_name,
length);
| |
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (6) returning to ‘name_scan’
from ‘namelist_match’
|13040 | if (cursor)
| | ~
| | |
| | (7) following ‘false’ branch (when ‘cursor’ is
NULL)...
|......
|13048 | if (same_order_option && namelist &&
namelist->found_count)
| | ~~~~~~~~~~~~~~~~~~
| | ||
| | |(8) ...to here
| | (9) following ‘true’ branch...
|13049 | {
|13050 | name_gather ();
| | ~~~~~~~~~~~~~~
| | |
| | (10) ...to here
| | (11) calling ‘name_gather’ from ‘name_scan’
|
+--> ‘name_gather’: events 12-13
|
|12170 | name_gather (void)
| | ^~~~~~~~~~~
| | |
| | (12) entry to ‘name_gather’
|......
|12179 | if (same_order_option)
| | ~
| | |
| | (13) following ‘true’ branch...
|
‘name_gather’: event 14
|
|cc1:
| (14): ...to here
|
‘name_gather’: event 15
|
|12183 | while ((ep = name_next_elt (0)) && ep->type
== NELT_CHDIR)
| | ^~~~~~~~~~~~~~~~~
| | |
| | (15) calling ‘name_next_elt’
from ‘name_gather’
|
+--> ‘name_next_elt’: events 16-19
|
|12110 | name_next_elt (int change_dirs)
| | ^~~~~~~~~~~~~
| | |
| | (16) entry to ‘name_next_elt’
|......
|12115 | while ((ep = name_head) !=
| | ~~~~~~~~~~~~~~~~~~~
| | |
| | (17) following
‘true’ branch (when ‘ep’ is non-NULL)...
|12116 | ((void *)0)
| | ~~~~~~~~~~~
|......
|12119 | switch (ep->type)
| | ~~~~~~~~
| | |
| | (18) ...to here
|......
|12122 | name_list_advance ();
| | ~~~~~~~~~~~~~~~~~~~~
| | |
| | (19) calling ‘name_list_advance’ from
‘name_next_elt’
|
+--> ‘name_list_advance’: events 20-24
|
|11759 | name_list_advance (void)
| | ^~~~~~~~~~~~~~~~~
| | |
| | (20) entry to ‘name_list_advance’
|......
|11767 | if (elt->type == NELT_OPTION ||
elt->type == NELT_CHDIR)
| | ~
| | |
| | (21) following ‘false’ branch...
|......
|11775 | if (elt->type != NELT_NOOP)
| | ~
| | |
| | (22) ...to here
| | (23) following ‘false’
branch...
|11776 | unconsumed_option_free ();
|11777 | free (elt);
| | ~~~~~~~~~~
| | |
| | (24) ...to here
|
<------+
|
‘name_next_elt’: events 25-28
|
|12115 | while ((ep = name_head) !=
| | ~~~~~~~~~~~~~~~~~~~
| | |
| | (26) following
‘true’ branch (when ‘ep’ is non-NULL)...
|12116 | ((void *)0)
| | ~~~~~~~~~~~
|......
|12119 | switch (ep->type)
| | ~~~~~~~~
| | |
| | (27) ...to here
|......
|12122 | name_list_advance ();
| | ^~~~~~~~~~~~~~~~~~~~
| | |
| | (25) returning to ‘name_next_elt’ from
‘name_list_advance’
|......
|12126 | if (read_next_name (ep, &entry) == 0)
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (28) calling ‘read_next_name’ from
‘name_next_elt’
|
+--> ‘read_next_name’: events 29-34
|
|12028 | read_next_name (struct name_elt *ent,
struct name_elt *ret)
| | ^~~~~~~~~~~~~~
| | |
| | (29) entry to ‘read_next_name’
|12029 | {
|12030 | if (!ent->v.file.fp)
| | ~
| | |
| | (30) following ‘true’ branch...
|12031 | {
|12032 | if (!strcmp (ent->v.file.name,
"-"))
| | ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (31) ...to here
| | (32) following ‘false’
branch (when the strings are non-equal)...
|......
|12041 | if (add_file_id
(ent->v.file.name))
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (33) ...to here
| | (34) calling ‘add_file_id’
from ‘read_next_name’
|
+--> ‘add_file_id’: events 35-37
|
|11891 | add_file_id (const char
*filename)
| | ^~~~~~~~~~~
| | |
| | (35) entry to ‘add_file_id’
|......
|11897 | if (stat (filename, &st))
| | ~
| | |
| | (36) following ‘false’
branch...
|11898 | stat_fatal (filename);
|11899 | reading_from =
file_list_name ();
| |
~~~~~~~~~~~~~~~~~
| | |
| | (37) ...to
here
|
<------+
|
‘read_next_name’: events 38-42
|
|12041 | if (add_file_id
(ent->v.file.name))
| | ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | ||
| | |(38) returning to
‘read_next_name’ from ‘add_file_id’
| | (39) following ‘false’
branch...
|......
|12046 | if ((ent->v.file.fp = fopen
(ent->v.file.name, "r")) ==
| | ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (40) ...to
here
| | | (41) opened
here
| | (42) ‘fopen(*ent.v.file.name,
"r")’ leaks here; was opened at (41)
|
t.i:12046:7: warning: leak of ‘fopen(*ent.v.file.name, "r")’ [CWE-401]
[-Wanalyzer-malloc-leak]
12046 | if ((ent->v.file.fp = fopen (ent->v.file.name, "r")) ==
| ^
‘name_scan’: events 1-2
|
|13033 | name_scan (const char *file_name)
| | ^~~~~~~~~
| | |
| | (1) entry to ‘name_scan’
|......
|13039 | struct name *cursor = namelist_match (file_name,
length);
| |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) calling ‘namelist_match’
from ‘name_scan’
|
+--> ‘namelist_match’: events 3-5
|
|12316 | namelist_match (char const *file_name, size_t
length)
| | ^~~~~~~~~~~~~~
| | |
| | (3) entry to ‘namelist_match’
|......
|12320 | for (p = namelist; p; p = p->next)
| | ~
| | |
| | (4) following ‘true’ branch
(when ‘p’ is non-NULL)...
|12321 | {
|12322 | if (p->name[0]
| | ~~~~~~~
| | |
| | (5) ...to here
|
<------+
|
‘name_scan’: events 6-11
|
|13039 | struct name *cursor = namelist_match (file_name,
length);
| |
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (6) returning to ‘name_scan’
from ‘namelist_match’
|13040 | if (cursor)
| | ~
| | |
| | (7) following ‘false’ branch (when ‘cursor’ is
NULL)...
|......
|13048 | if (same_order_option && namelist &&
namelist->found_count)
| | ~~~~~~~~~~~~~~~~~~
| | ||
| | |(8) ...to here
| | (9) following ‘true’ branch...
|13049 | {
|13050 | name_gather ();
| | ~~~~~~~~~~~~~~
| | |
| | (10) ...to here
| | (11) calling ‘name_gather’ from ‘name_scan’
|
+--> ‘name_gather’: events 12-13
|
|12170 | name_gather (void)
| | ^~~~~~~~~~~
| | |
| | (12) entry to ‘name_gather’
|......
|12179 | if (same_order_option)
| | ~
| | |
| | (13) following ‘true’ branch...
|
‘name_gather’: event 14
|
|cc1:
| (14): ...to here
|
‘name_gather’: event 15
|
|12183 | while ((ep = name_next_elt (0)) && ep->type
== NELT_CHDIR)
| | ^~~~~~~~~~~~~~~~~
| | |
| | (15) calling ‘name_next_elt’
from ‘name_gather’
|
+--> ‘name_next_elt’: events 16-19
|
|12110 | name_next_elt (int change_dirs)
| | ^~~~~~~~~~~~~
| | |
| | (16) entry to ‘name_next_elt’
|......
|12115 | while ((ep = name_head) !=
| | ~~~~~~~~~~~~~~~~~~~
| | |
| | (17) following
‘true’ branch (when ‘ep’ is non-NULL)...
|12116 | ((void *)0)
| | ~~~~~~~~~~~
|......
|12119 | switch (ep->type)
| | ~~~~~~~~
| | |
| | (18) ...to here
|......
|12122 | name_list_advance ();
| | ~~~~~~~~~~~~~~~~~~~~
| | |
| | (19) calling ‘name_list_advance’ from
‘name_next_elt’
|
+--> ‘name_list_advance’: events 20-24
|
|11759 | name_list_advance (void)
| | ^~~~~~~~~~~~~~~~~
| | |
| | (20) entry to ‘name_list_advance’
|......
|11767 | if (elt->type == NELT_OPTION ||
elt->type == NELT_CHDIR)
| | ~
| | |
| | (21) following ‘false’ branch...
|......
|11775 | if (elt->type != NELT_NOOP)
| | ~
| | |
| | (22) ...to here
| | (23) following ‘false’
branch...
|11776 | unconsumed_option_free ();
|11777 | free (elt);
| | ~~~~~~~~~~
| | |
| | (24) ...to here
|
<------+
|
‘name_next_elt’: events 25-28
|
|12115 | while ((ep = name_head) !=
| | ~~~~~~~~~~~~~~~~~~~
| | |
| | (26) following
‘true’ branch (when ‘ep’ is non-NULL)...
|12116 | ((void *)0)
| | ~~~~~~~~~~~
|......
|12119 | switch (ep->type)
| | ~~~~~~~~
| | |
| | (27) ...to here
|......
|12122 | name_list_advance ();
| | ^~~~~~~~~~~~~~~~~~~~
| | |
| | (25) returning to ‘name_next_elt’ from
‘name_list_advance’
|......
|12126 | if (read_next_name (ep, &entry) == 0)
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (28) calling ‘read_next_name’ from
‘name_next_elt’
|
+--> ‘read_next_name’: events 29-34
|
|12028 | read_next_name (struct name_elt *ent,
struct name_elt *ret)
| | ^~~~~~~~~~~~~~
| | |
| | (29) entry to ‘read_next_name’
|12029 | {
|12030 | if (!ent->v.file.fp)
| | ~
| | |
| | (30) following ‘true’ branch...
|12031 | {
|12032 | if (!strcmp (ent->v.file.name,
"-"))
| | ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (31) ...to here
| | (32) following ‘false’
branch (when the strings are non-equal)...
|......
|12041 | if (add_file_id
(ent->v.file.name))
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (33) ...to here
| | (34) calling ‘add_file_id’
from ‘read_next_name’
|
+--> ‘add_file_id’: events 35-37
|
|11891 | add_file_id (const char
*filename)
| | ^~~~~~~~~~~
| | |
| | (35) entry to ‘add_file_id’
|......
|11897 | if (stat (filename, &st))
| | ~
| | |
| | (36) following ‘false’
branch...
|11898 | stat_fatal (filename);
|11899 | reading_from =
file_list_name ();
| |
~~~~~~~~~~~~~~~~~
| | |
| | (37) ...to
here
|
<------+
|
‘read_next_name’: events 38-42
|
|12041 | if (add_file_id
(ent->v.file.name))
| | ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | ||
| | |(38) returning to
‘read_next_name’ from ‘add_file_id’
| | (39) following ‘false’
branch...
|......
|12046 | if ((ent->v.file.fp = fopen
(ent->v.file.name, "r")) ==
| | ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (40) ...to
here
| | | (41)
allocated here
| | (42) ‘fopen(*ent.v.file.name,
"r")’ leaks here; was allocated at (41)
|
t.i: In function ‘name_gather’:
t.i:12184:13: warning: leak of ‘xstrdup(*ep.v.name)’ [CWE-401]
[-Wanalyzer-malloc-leak]
12184 | change_dir = chdir_arg (xstrdup (ep->v.name));
| ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
‘name_scan’: events 1-2
|
|13033 | name_scan (const char *file_name)
| | ^~~~~~~~~
| | |
| | (1) entry to ‘name_scan’
|......
|13039 | struct name *cursor = namelist_match (file_name,
length);
| |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) calling ‘namelist_match’
from ‘name_scan’
|
+--> ‘namelist_match’: events 3-5
|
|12316 | namelist_match (char const *file_name, size_t
length)
| | ^~~~~~~~~~~~~~
| | |
| | (3) entry to ‘namelist_match’
|......
|12320 | for (p = namelist; p; p = p->next)
| | ~
| | |
| | (4) following ‘true’ branch
(when ‘p’ is non-NULL)...
|12321 | {
|12322 | if (p->name[0]
| | ~~~~~~~
| | |
| | (5) ...to here
|
<------+
|
‘name_scan’: events 6-11
|
|13039 | struct name *cursor = namelist_match (file_name,
length);
| |
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (6) returning to ‘name_scan’
from ‘namelist_match’
|13040 | if (cursor)
| | ~
| | |
| | (7) following ‘false’ branch (when ‘cursor’ is
NULL)...
|......
|13048 | if (same_order_option && namelist &&
namelist->found_count)
| | ~~~~~~~~~~~~~~~~~~
| | ||
| | |(8) ...to here
| | (9) following ‘true’ branch...
|13049 | {
|13050 | name_gather ();
| | ~~~~~~~~~~~~~~
| | |
| | (10) ...to here
| | (11) calling ‘name_gather’ from ‘name_scan’
|
+--> ‘name_gather’: events 12-13
|
|12170 | name_gather (void)
| | ^~~~~~~~~~~
| | |
| | (12) entry to ‘name_gather’
|......
|12179 | if (same_order_option)
| | ~
| | |
| | (13) following ‘true’ branch...
|
‘name_gather’: event 14
|
|cc1:
| (14): ...to here
|
‘name_gather’: event 15
|
|12183 | while ((ep = name_next_elt (0)) && ep->type
== NELT_CHDIR)
| | ^~~~~~~~~~~~~~~~~
| | |
| | (15) calling ‘name_next_elt’
from ‘name_gather’
|
+--> ‘name_next_elt’: events 16-20
|
|12110 | name_next_elt (int change_dirs)
| | ^~~~~~~~~~~~~
| | |
| | (16) entry to ‘name_next_elt’
|......
|12115 | while ((ep = name_head) !=
| | ~~~~~~~~~~~~~~~~~~~
| | |
| | (17) following
‘true’ branch (when ‘ep’ is non-NULL)...
|12116 | ((void *)0)
| | ~~~~~~~~~~~
|......
|12119 | switch (ep->type)
| | ~~~~~~~~
| | |
| | (18) ...to here
|......
|12131 | if (change_dirs)
| | ~
| | |
| | (19) following ‘false’ branch (when
‘change_dirs == 0’)...
|......
|12139 | copy_name (ep);
| | ~~~~~~~~~~~~~~
| | |
| | (20) ...to here
|
<------+
|
‘name_gather’: events 21-25
|
|12183 | while ((ep = name_next_elt (0)) && ep->type
== NELT_CHDIR)
| |
~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (22)
following ‘true’ branch...
| | (21) returning to ‘name_gather’
from ‘name_next_elt’
|12184 | change_dir = chdir_arg (xstrdup (ep->v.name));
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (23) ...to here
| | | (24) allocated here
| | (25) ‘xstrdup(*ep.v.name)’ leaks here;
was allocated at (24)
|
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-07-24 20:40 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-24 20:40 [Bug analyzer/106428] New: -Wanalyzer-file-leak false positive with if ((ptr = fopen(...)) == NULL) 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).