Bug Summary

File:src/sbin/quotacheck/../fsck/preen.c
Warning:line 170, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name preen.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/quotacheck/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sbin/quotacheck/../fsck -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/quotacheck/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/quotacheck/../fsck/preen.c
1/* $OpenBSD: preen.c,v 1.20 2015/01/16 06:39:57 deraadt Exp $ */
2/* $NetBSD: preen.c,v 1.15 1996/09/28 19:21:42 christos Exp $ */
3
4/*
5 * Copyright (c) 1990, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/stat.h>
34#include <sys/wait.h>
35#include <sys/queue.h>
36
37#include <fstab.h>
38#include <string.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <ctype.h>
42#include <unistd.h>
43#include <err.h>
44
45#include "fsutil.h"
46
47struct partentry {
48 TAILQ_ENTRY(partentry)struct { struct partentry *tqe_next; struct partentry **tqe_prev
; }
p_entries;
49 char *p_devname; /* device name */
50 char *p_mntpt; /* mount point */
51 char *p_type; /* filesystem type */
52 void *p_auxarg; /* auxiliary argument */
53};
54
55TAILQ_HEAD(part, partentry)struct part { struct partentry *tqh_first; struct partentry *
*tqh_last; }
badh;
56
57struct diskentry {
58 TAILQ_ENTRY(diskentry)struct { struct diskentry *tqe_next; struct diskentry **tqe_prev
; }
d_entries;
59 char *d_name; /* disk base name */
60 TAILQ_HEAD(prt, partentry)struct prt { struct partentry *tqh_first; struct partentry **
tqh_last; }
d_part; /* list of partitions on disk */
61 pid_t d_pid; /* 0 or pid of fsck proc */
62};
63
64TAILQ_HEAD(disk, diskentry)struct disk { struct diskentry *tqh_first; struct diskentry *
*tqh_last; }
diskh;
65
66static int nrun = 0, ndisks = 0;
67
68static struct diskentry *finddisk(const char *);
69static void addpart(const char *, const char *, const char *, void *);
70static int startdisk(struct diskentry *,
71 int (*)(const char *, const char *, const char *, void *, pid_t *));
72static void printpart(void);
73
74int
75checkfstab(int flags, int maxrun, void *(*docheck)(struct fstab *),
76 int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
77{
78 struct fstab *fs;
79 struct diskentry *d, *nextdisk;
80 struct partentry *p;
81 int ret, retcode, passno, sumstatus, status, maxp;
82 void *auxarg;
83 char *name;
84 pid_t pid;
85
86 TAILQ_INIT(&badh)do { (&badh)->tqh_first = ((void *)0); (&badh)->
tqh_last = &(&badh)->tqh_first; } while (0)
;
1
Loop condition is false. Exiting loop
87 TAILQ_INIT(&diskh)do { (&diskh)->tqh_first = ((void *)0); (&diskh)->
tqh_last = &(&diskh)->tqh_first; } while (0)
;
2
Loop condition is false. Exiting loop
88
89 sumstatus = 0;
90 maxp = 2;
91
92 for (passno = 1; passno <= maxp; passno++) {
3
Loop condition is true. Entering loop body
10
Loop condition is true. Entering loop body
28
Loop condition is false. Execution continues on line 135
93 if (setfsent() == 0) {
4
Assuming the condition is false
5
Taking false branch
11
Assuming the condition is false
12
Taking false branch
94 warnx("Can't open checklist file: %s", _PATH_FSTAB"/etc/fstab");
95 return (8);
96 }
97 while ((fs = getfsent()) != 0) {
6
Assuming the condition is false
7
Loop condition is false. Execution continues on line 131
13
Assuming the condition is true
14
Loop condition is true. Entering loop body
25
Assuming the condition is false
26
Loop condition is false. Execution continues on line 131
98 if ((auxarg = (*docheck)(fs)) == NULL((void *)0))
15
Assuming the condition is false
16
Taking false branch
99 continue;
100
101 name = blockcheck(fs->fs_spec);
102 if (flags & CHECK_DEBUG4)
17
Assuming the condition is false
18
Taking false branch
103 printf("pass %d, name %s\n", passno, name);
104 maxp = (fs->fs_passno > maxp) ? fs->fs_passno : maxp;
19
Assuming 'maxp' is >= field 'fs_passno'
20
'?' condition is false
105
106 if ((flags & CHECK_PREEN1) == 0 ||
107 (passno
20.1
'passno' is not equal to 1
== 1 && fs->fs_passno == 1)) {
108 if (name == NULL((void *)0)) {
109 if (flags & CHECK_PREEN1)
110 return 8;
111 else
112 continue;
113 }
114 sumstatus = (*checkit)(fs->fs_vfstype,
115 name, fs->fs_file, auxarg, NULL((void *)0));
116
117 if (sumstatus)
118 return (sumstatus);
119 } else {
120 if (name == NULL((void *)0)) {
21
Assuming 'name' is not equal to NULL
22
Taking false branch
121 (void) fprintf(stderr(&__sF[2]),
122 "BAD DISK NAME %s\n", fs->fs_spec);
123 sumstatus |= 8;
124 continue;
125 }
126 if (passno == fs->fs_passno)
23
Assuming 'passno' is not equal to field 'fs_passno'
24
Taking false branch
127 addpart(fs->fs_vfstype, name,
128 fs->fs_file, auxarg);
129 }
130 }
131 if ((flags & CHECK_PREEN1) == 0)
8
Assuming the condition is false
9
Taking false branch
27
Taking false branch
132 return 0;
133 }
134
135 if (flags & CHECK_DEBUG4)
29
Taking false branch
136 printpart();
137
138 if (flags & CHECK_PREEN1) {
30
Taking true branch
139 if (maxrun == 0)
31
Assuming 'maxrun' is not equal to 0
32
Taking false branch
140 maxrun = ndisks;
141 if (maxrun > ndisks)
33
Assuming 'maxrun' is <= 'ndisks'
34
Taking false branch
142 maxrun = ndisks;
143 nextdisk = TAILQ_FIRST(&diskh)((&diskh)->tqh_first);
144 for (passno = 0; passno < maxrun; ++passno) {
35
Assuming 'passno' is >= 'maxrun'
36
Loop condition is false. Execution continues on line 150
145 if ((ret = startdisk(nextdisk, checkit)) != 0)
146 return ret;
147 nextdisk = TAILQ_NEXT(nextdisk, d_entries)((nextdisk)->d_entries.tqe_next);
148 }
149
150 while ((pid = wait(&status)) != -1) {
37
Assuming the condition is true
38
Loop condition is true. Entering loop body
58
Assuming the condition is true
59
Loop condition is true. Entering loop body
151 TAILQ_FOREACH(d, &diskh, d_entries)for((d) = ((&diskh)->tqh_first); (d) != ((void *)0); (
d) = ((d)->d_entries.tqe_next))
39
Assuming 'd' is not equal to null
40
Loop condition is true. Entering loop body
60
Loop condition is true. Entering loop body
152 if (d->d_pid == pid)
41
Assuming 'pid' is equal to field 'd_pid'
42
Taking true branch
61
Assuming 'pid' is equal to field 'd_pid'
62
Taking true branch
153 break;
43
Execution continues on line 155
63
Execution continues on line 155
154
155 if (d
43.1
'd' is not equal to NULL
63.1
'd' is not equal to NULL
== NULL((void *)0)) {
44
Taking false branch
64
Taking false branch
156 warnx("Unknown pid %ld", (long)pid);
157 continue;
158 }
159
160
161 if (WIFEXITED(status)(((status) & 0177) == 0))
45
Assuming the condition is false
46
Taking false branch
65
Assuming the condition is false
66
Taking false branch
162 retcode = WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff);
163 else
164 retcode = 0;
165
166 p = TAILQ_FIRST(&d->d_part)((&d->d_part)->tqh_first);
167
168 if (flags & (CHECK_DEBUG4|CHECK_VERBOSE2))
47
Assuming the condition is true
48
Taking true branch
67
Taking true branch
169 (void) printf("done %s: %s (%s) = %x\n",
170 p->p_type, p->p_devname, p->p_mntpt,
68
Use of memory after it is freed
171 status);
172
173 if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
) {
49
Assuming the condition is false
174 (void) fprintf(stderr(&__sF[2]),
175 "%s: %s (%s): EXITED WITH SIGNAL %d\n",
176 p->p_type, p->p_devname, p->p_mntpt,
177 WTERMSIG(status)(((status) & 0177)));
178 retcode = 8;
179 }
180
181 TAILQ_REMOVE(&d->d_part, p, p_entries)do { if (((p)->p_entries.tqe_next) != ((void *)0)) (p)->
p_entries.tqe_next->p_entries.tqe_prev = (p)->p_entries
.tqe_prev; else (&d->d_part)->tqh_last = (p)->p_entries
.tqe_prev; *(p)->p_entries.tqe_prev = (p)->p_entries.tqe_next
; ; ; } while (0)
;
50
Assuming field 'tqe_next' is equal to null
51
Taking false branch
52
Loop condition is false. Exiting loop
182
183 if (retcode
52.1
'retcode' is equal to 0
!= 0) {
53
Taking false branch
184 TAILQ_INSERT_TAIL(&badh, p, p_entries)do { (p)->p_entries.tqe_next = ((void *)0); (p)->p_entries
.tqe_prev = (&badh)->tqh_last; *(&badh)->tqh_last
= (p); (&badh)->tqh_last = &(p)->p_entries.tqe_next
; } while (0)
;
185 sumstatus |= retcode;
186 } else {
187 free(p->p_type);
188 free(p->p_devname);
189 free(p);
54
Memory is released
190 }
191 d->d_pid = 0;
192 nrun--;
193
194 if (TAILQ_EMPTY(&d->d_part)(((&d->d_part)->tqh_first) == ((void *)0)))
55
Taking false branch
195 ndisks--;
196
197 if (nextdisk
55.1
'nextdisk' is not equal to NULL
== NULL((void *)0)) {
56
Taking false branch
198 if (!TAILQ_EMPTY(&d->d_part)(((&d->d_part)->tqh_first) == ((void *)0))) {
199 if ((ret = startdisk(d, checkit)) != 0)
200 return ret;
201 }
202 } else if (nrun < maxrun && nrun < ndisks) {
57
Assuming 'nrun' is >= 'maxrun'
203 for ( ;; ) {
204 nextdisk = TAILQ_NEXT(nextdisk,((nextdisk)->d_entries.tqe_next)
205 d_entries)((nextdisk)->d_entries.tqe_next);
206 if (nextdisk == NULL((void *)0))
207 nextdisk = TAILQ_FIRST(&diskh)((&diskh)->tqh_first);
208 if (!TAILQ_EMPTY(&nextdisk->d_part)(((&nextdisk->d_part)->tqh_first) == ((void *)0)) &&
209 nextdisk->d_pid == 0)
210 break;
211 }
212 if ((ret = startdisk(nextdisk, checkit)) != 0)
213 return ret;
214 }
215 }
216 }
217 if (sumstatus) {
218 p = TAILQ_FIRST(&badh)((&badh)->tqh_first);
219 if (p == NULL((void *)0))
220 return (sumstatus);
221
222 (void) fprintf(stderr(&__sF[2]),
223 "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
224 TAILQ_NEXT(p, p_entries)((p)->p_entries.tqe_next) ? "S" : "",
225 "UNEXPECTED INCONSISTENCY:");
226
227 for (; p; p = TAILQ_NEXT(p, p_entries)((p)->p_entries.tqe_next))
228 (void) fprintf(stderr(&__sF[2]),
229 "%s: %s (%s)%s", p->p_type, p->p_devname,
230 p->p_mntpt, TAILQ_NEXT(p, p_entries)((p)->p_entries.tqe_next) ? ", " : "\n");
231
232 return sumstatus;
233 }
234 (void) endfsent();
235 return (0);
236}
237
238
239static struct diskentry *
240finddisk(const char *name)
241{
242 const char *p;
243 size_t len = 0;
244 struct diskentry *d;
245
246 for (p = name + strlen(name) - 1; p >= name; --p)
247 if (isdigit((unsigned char)*p)) {
248 len = p - name + 1;
249 break;
250 }
251
252 if (p < name)
253 len = strlen(name);
254
255 TAILQ_FOREACH(d, &diskh, d_entries)for((d) = ((&diskh)->tqh_first); (d) != ((void *)0); (
d) = ((d)->d_entries.tqe_next))
256 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
257 return d;
258
259 d = emalloc(sizeof(*d));
260 d->d_name = estrdup(name);
261 d->d_name[len] = '\0';
262 TAILQ_INIT(&d->d_part)do { (&d->d_part)->tqh_first = ((void *)0); (&d
->d_part)->tqh_last = &(&d->d_part)->tqh_first
; } while (0)
;
263 d->d_pid = 0;
264
265 TAILQ_INSERT_TAIL(&diskh, d, d_entries)do { (d)->d_entries.tqe_next = ((void *)0); (d)->d_entries
.tqe_prev = (&diskh)->tqh_last; *(&diskh)->tqh_last
= (d); (&diskh)->tqh_last = &(d)->d_entries.tqe_next
; } while (0)
;
266 ndisks++;
267
268 return d;
269}
270
271
272static void
273printpart(void)
274{
275 struct diskentry *d;
276 struct partentry *p;
277
278 TAILQ_FOREACH(d, &diskh, d_entries)for((d) = ((&diskh)->tqh_first); (d) != ((void *)0); (
d) = ((d)->d_entries.tqe_next))
{
279 (void) printf("disk %s: ", d->d_name);
280 TAILQ_FOREACH(p, &d->d_part, p_entries)for((p) = ((&d->d_part)->tqh_first); (p) != ((void *
)0); (p) = ((p)->p_entries.tqe_next))
281 (void) printf("%s ", p->p_devname);
282 (void) printf("\n");
283 }
284}
285
286
287static void
288addpart(const char *type, const char *devname, const char *mntpt, void *auxarg)
289{
290 struct diskentry *d = finddisk(devname);
291 struct partentry *p;
292
293 TAILQ_FOREACH(p, &d->d_part, p_entries)for((p) = ((&d->d_part)->tqh_first); (p) != ((void *
)0); (p) = ((p)->p_entries.tqe_next))
294 if (strcmp(p->p_devname, devname) == 0) {
295 warnx("%s in fstab more than once!", devname);
296 return;
297 }
298
299 p = emalloc(sizeof(*p));
300 p->p_devname = estrdup(devname);
301 p->p_mntpt = estrdup(mntpt);
302 p->p_type = estrdup(type);
303 p->p_auxarg = auxarg;
304
305 TAILQ_INSERT_TAIL(&d->d_part, p, p_entries)do { (p)->p_entries.tqe_next = ((void *)0); (p)->p_entries
.tqe_prev = (&d->d_part)->tqh_last; *(&d->d_part
)->tqh_last = (p); (&d->d_part)->tqh_last = &
(p)->p_entries.tqe_next; } while (0)
;
306}
307
308
309static int
310startdisk(struct diskentry *d,
311 int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
312{
313 struct partentry *p = TAILQ_FIRST(&d->d_part)((&d->d_part)->tqh_first);
314 int rv;
315
316 while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
317 p->p_auxarg, &d->d_pid)) != 0 && nrun > 0)
318 sleep(10);
319
320 if (rv == 0)
321 nrun++;
322
323 return rv;
324}