From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id D670E385AC20; Sat, 17 Feb 2024 05:30:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D670E385AC20 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1708147831; bh=j4b+tESYj3o7luQWGjLK7/otvAblqWJypt3Uw8GgbjE=; h=From:To:Subject:Date:From; b=ew+sWXLmwAJaTuI9MAp96DVDcbkRHypx2qTS7oKeQDlrGVLkbk98wBZRgz0v3dRde EJz3WN+HL5FdeTrnchM6WyCPZ9ARYgRT+NLKb/GwZiA+vYmzDGa9mTGw+PQIRX9SyP 9zpkdz38IvxJuBOZmTQlDYAhXZw45ilSwEjrWULk= From: "eggert at cs dot ucla.edu" To: gcc-bugs@gcc.gnu.org Subject: [Bug analyzer/113963] New: analyzer-null-dereference, analyzer-malloc-leak false alarms in Gnulib savedir.c Date: Sat, 17 Feb 2024 05:30:30 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: analyzer X-Bugzilla-Version: 13.2.1 X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: eggert at cs dot ucla.edu X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: dmalcolm at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter target_milestone attachments.created Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 List-Id: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D113963 Bug ID: 113963 Summary: analyzer-null-dereference, analyzer-malloc-leak false alarms in Gnulib savedir.c Product: gcc Version: 13.2.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 57441 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=3D57441&action=3Dedit test program with line number directives I ran into this problem when compiling programs using Gnulib's lib/savedir.c code. This is gcc (GCC) 13.2.1 20231205 (Red Hat 13.2.1-6) on x86-64. Compile the attached programs with: gcc -O2 -fanalyzer -S savedir.i gcc -O2 -fanalyzer -S savedis.i Two problems. First, although savedis.i is merely a copy of savedir.i with = line number directives removed, the second command outputs an extra -Wanalyzer-null-argument warning that the first command does not. Surely the presence of line number directives should not affect which warnings are iss= ued. Second and more important, all the warnings are false positives. The pointe= rs can't possibly be null when the sizes are nonzero, and there is no memory l= eak. The source files savedir.i and savedis.i are attached, compressed. Here are the incorrect warnings that I get: $ gcc -O2 -fanalyzer -S savedir.i savedir.c: In function =E2=80=98streamsavedir=E2=80=99: savedir.c:135:42: warning: dereference of NULL =E2=80=98entries=E2=80=99 [C= WE-476] [-Wanalyzer-null-dereference] 135 | entries[entries_used].name =3D used; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~ =E2=80=98streamsavedir=E2=80=99: event 1 | |savedir.c:106:6: | 106 | if (dirp =3D=3D NULL) | | ^ | | | | | (1) following =E2=80=98false=E2=80=99 branch (when =E2=80= =98dirp=E2=80=99 is non-NULL)... | =E2=80=98streamsavedir=E2=80=99: event 2 | |cc1: | (2): ...to here | =E2=80=98streamsavedir=E2=80=99: events 3-5 | |savedir.c:116:10: | 116 | if (! dp) | | ^ | | | | | (3) following =E2=80=98false=E2=80=99 branch (when = =E2=80=98dp=E2=80=99 is non-NULL)... |...... | 121 | entry =3D dp->d_name; | | ~~~~~~~~~~~~~~~~~~ | | | | | (4) ...to here | 122 | if (entry[entry[0] !=3D '.' ? 0 : entry[1] !=3D '.' ? 1 = : 2] !=3D '\0') | | ~ | | | | | (5) following =E2=80=98true=E2=80=99 branch... | =E2=80=98streamsavedir=E2=80=99: event 6 | |savedir.c:124:30: | 124 | idx_t entry_size =3D _D_EXACT_NAMLEN (dp) + 1; | =E2=80=98streamsavedir=E2=80=99: event 7 | |savedir.c:125:14: | 125 | if (allocated - used <=3D entry_size) | | ^ | | | | | (7) following =E2=80=98true=E2=80=99 branch... | =E2=80=98streamsavedir=E2=80=99: event 8 | | 126 | name_space =3D xpalloc (name_space, &allocated, | =E2=80=98streamsavedir=E2=80=99: events 9-14 | |savedir.c:130:14: | 130 | if (cmp) | | ^ | | | | | (9) following =E2=80=98true=E2=80=99 branch (when= =E2=80=98cmp=E2=80=99 is non-NULL)... | 131 | { | 132 | if (entries_allocated =3D=3D entries_used) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | (10) ...to here | | (11) following =E2=80=98false=E2=80=99 branch= ... |...... | 135 | entries[entries_used].name =3D used; | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | (12) ...to here (14) dereference of N= ULL =E2=80=98entries + (long unsigned int)entries_used * 16=E2=80=99 | | (13) =E2=80=98entries=E2=80=99 is NULL | savedir.c:169:3: warning: leak of =E2=80=98name_space=E2=80=99 [CWE-401] [-Wanalyzer-malloc-leak] 169 | free (entries); | ^~~~~~~~~~~~~~ =E2=80=98savedir=E2=80=99: events 1-2 | | 179 | savedir (char const *dir, enum savedir_option option) | | ^~~~~~~ | | | | | (1) entry to =E2=80=98savedir=E2=80=99 |...... | 182 | if (! dirp) | | ~ | | | | | (2) following =E2=80=98false=E2=80=99 branch (when =E2=80= =98dirp=E2=80=99 is non-NULL)... | =E2=80=98savedir=E2=80=99: events 3-5 | |savedir.c:186:26: | 186 | char *name_space =3D streamsavedir (dirp, option); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (3) ...to here | | (4) allocated here | | (5) calling =E2=80=98streamsavedir=E2= =80=99 from =E2=80=98savedir=E2=80=99 | +--> =E2=80=98streamsavedir=E2=80=99: event 6 | |savedir.c:96:1: | 96 | streamsavedir (DIR *dirp, enum savedir_option option) | | ^~~~~~~~~~~~~ | | | | | (6) entry to =E2=80=98streamsavedir=E2=80=99 | =E2=80=98streamsavedir=E2=80=99: event 7 | |savedir.c:106:6: | 106 | if (dirp =3D=3D NULL) | | ^ | | | | | (7) following =E2=80=98false=E2=80=99 branch (when= =E2=80=98dirp=E2=80=99 is non-NULL)... | =E2=80=98streamsavedir=E2=80=99: event 8 | |cc1: | (8): ...to here | =E2=80=98streamsavedir=E2=80=99: event 9 | |savedir.c:145:6: | 145 | if (errno !=3D 0) | | ^ | | | | | (9) following =E2=80=98true=E2=80=99 branch... | =E2=80=98streamsavedir=E2=80=99: event 10 | |savedir.c:147:7: | 147 | free (name_space); | | ^~~~~~~~~~~~~~~~~ | | | | | (10) ...to here | =E2=80=98streamsavedir=E2=80=99: event 11 | |savedir.c:169:3: | 169 | free (entries); | | ^~~~~~~~~~~~~~ | | | | | (11) =E2=80=98name_space=E2=80=99 leaks here; was all= ocated at (4) | $ gcc -O2 -fanalyzer -S savedis.i In function =E2=80=98memcpy=E2=80=99, inlined from =E2=80=98streamsavedir=E2=80=99 at savedis.i:2993:11: savedis.i:2502:10: warning: use of NULL =E2=80=98name_space=E2=80=99 where = non-null expected [CWE-476] [-Wanalyzer-null-argument] 2502 | return __builtin___memcpy_chk (__dest, __src, __len, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2503 | __builtin_object_size (__dest, 0)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ =E2=80=98streamsavedir=E2=80=99: event 1 | | 2958 | if (dirp =3D=3D | | ^ | | | | | (1) following =E2=80=98false=E2=80=99 branch (when =E2=80= =98dirp=E2=80=99 is non-NULL)... | =E2=80=98streamsavedir=E2=80=99: event 2 | |cc1: | (2): ...to here | =E2=80=98streamsavedir=E2=80=99: events 3-10 | | 2974 | if (! dp) | | ^ | | | | | (3) following =E2=80=98false=E2=80=99 branch (when = =E2=80=98dp=E2=80=99 is non-NULL)... |...... | 2979 | entry =3D dp->d_name; | | ~~~~~~~~~~~~~~~~~~ | | | | | (4) ...to here | 2980 | if (entry[entry[0] !=3D '.' ? 0 : entry[1] !=3D '.' ? 1 = : 2] !=3D '\0') | | ~ | | | | | (5) following =E2=80=98true=E2=80=99 branch... |...... | 2983 | (strlen (( | | ~~~~~~~~~~ | | | | | (6) ...to here | 2984 | dp | | ~~ | 2985 | )->d_name)) | | ~~~~~~~~~~~ | 2986 | + 1; | 2987 | if (allocated - used <=3D entry_size) | | ~ | | | | | (7) following =E2=80=98false=E2=80=99 branch... |...... | 2993 | memcpy (name_space + used, entry, entry_size); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | (8) ...to here (9) =E2=80=98name_space=E2=80=99 = is NULL | | (10) inlined call to =E2=80=98memcpy=E2=80=99 from = =E2=80=98streamsavedir=E2=80=99 | +--> =E2=80=98memcpy=E2=80=99: event 11 | | 2502 | return __builtin___memcpy_chk (__dest, __src, __len, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (11) argument 1 (=E2=80=98name_space + (sizety= pe)used=E2=80=99) NULL where non-null expected | 2503 | __builtin_object_size (__dest, 0)); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | : In function =E2=80=98streamsavedir=E2=80=99: : note: argument 1 of =E2=80=98__builtin___memcpy_chk=E2=80=99 mu= st be non-null savedis.i:2999:42: warning: dereference of NULL =E2=80=98entries=E2=80=99 [= CWE-476] [-Wanalyzer-null-dereference] 2999 | entries[entries_used].name =3D used; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~ =E2=80=98streamsavedir=E2=80=99: event 1 | | 2958 | if (dirp =3D=3D | | ^ | | | | | (1) following =E2=80=98false=E2=80=99 branch (when =E2=80= =98dirp=E2=80=99 is non-NULL)... | =E2=80=98streamsavedir=E2=80=99: event 2 | |cc1: | (2): ...to here | =E2=80=98streamsavedir=E2=80=99: events 3-14 | | 2974 | if (! dp) | | ^ | | | | | (3) following =E2=80=98false=E2=80=99 branch (when = =E2=80=98dp=E2=80=99 is non-NULL)... |...... | 2979 | entry =3D dp->d_name; | | ~~~~~~~~~~~~~~~~~~ | | | | | (4) ...to here | 2980 | if (entry[entry[0] !=3D '.' ? 0 : entry[1] !=3D '.' ? 1 = : 2] !=3D '\0') | | ~ | | | | | (5) following =E2=80=98true=E2=80=99 branch... |...... | 2983 | (strlen (( | | ~~~~~~~~~~ | | | | | (6) ...to here | 2984 | dp | | ~~ | 2985 | )->d_name)) | | ~~~~~~~~~~~ | 2986 | + 1; | 2987 | if (allocated - used <=3D entry_size) | | ~ | | | | | (7) following =E2=80=98true=E2=80=99 branch... | 2988 | name_space =3D xpalloc (name_space, &allocated, | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (8) ...to here | 2989 | entry_size - (allocated - us= ed), | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~ | 2990 | | | | 2991 | (9223372036854775807L) | | ~~~~~~~~~~~~~~~~~~~~~~ | 2992 | - 1, sizeof *name_spa= ce); | | ~~~~~~~~~~~~~~~~~~~~~= ~~~ | 2993 | memcpy (name_space + used, entry, entry_size); | 2994 | if (cmp) | | ~ | | | | | (9) following =E2=80=98true=E2=80=99 branch (when= =E2=80=98cmp=E2=80=99 is non-NULL)... | 2995 | { | 2996 | if (entries_allocated =3D=3D entries_used) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | (10) ...to here | | (11) following =E2=80=98false=E2=80=99 branch= ... |...... | 2999 | entries[entries_used].name =3D used; | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | (12) ...to here (14) dereference of N= ULL =E2=80=98entries + (long unsigned int)entries_used * 16=E2=80=99 | | (13) =E2=80=98entries=E2=80=99 is NULL | savedis.i:3037:3: warning: leak of =E2=80=98name_space=E2=80=99 [CWE-401] [-Wanalyzer-malloc-leak] 3037 | free (entries); | ^~~~~~~~~~~~~~ =E2=80=98savedir=E2=80=99: events 1-5 | | 3047 | savedir (char const *dir, enum savedir_option option) | | ^~~~~~~ | | | | | (1) entry to =E2=80=98savedir=E2=80=99 |...... | 3050 | if (! dirp) | | ~ | | | | | (2) following =E2=80=98false=E2=80=99 branch (when =E2=80= =98dirp=E2=80=99 is non-NULL)... |...... | 3056 | char *name_space =3D streamsavedir (dirp, option); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (3) ...to here | | (4) allocated here | | (5) calling =E2=80=98streamsavedir=E2= =80=99 from =E2=80=98savedir=E2=80=99 | +--> =E2=80=98streamsavedir=E2=80=99: events 6-7 | | 2944 | streamsavedir (DIR *dirp, enum savedir_option option) | | ^~~~~~~~~~~~~ | | | | | (6) entry to =E2=80=98streamsavedir=E2=80=99 |...... | 2958 | if (dirp =3D=3D | | ~ | | | | | (7) following =E2=80=98false=E2=80=99 branch (when= =E2=80=98dirp=E2=80=99 is non-NULL)... | =E2=80=98streamsavedir=E2=80=99: event 8 | |cc1: | (8): ...to here | =E2=80=98streamsavedir=E2=80=99: events 9-11 | | 3009 | if ( | | ^ | | | | | (9) following =E2=80=98true=E2=80=99 branch... |...... | 3013 | free (name_space); | | ~~~~~~~~~~~~~~~~~ | | | | | (10) ...to here |...... | 3037 | free (entries); | | ~~~~~~~~~~~~~~ | | | | | (11) =E2=80=98name_space=E2=80=99 leaks here; was all= ocated at (4) |=