Bug Summary

File:src/libexec/ftpd/../../bin/ls/print.c
Warning:line 196, column 17
Array access (from variable 'array') results in a null pointer dereference

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 print.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/libexec/ftpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/libexec/ftpd -I /usr/src/libexec/ftpd/../../bin/ls -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/libexec/ftpd/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/libexec/ftpd/../../bin/ls/print.c
1/* $OpenBSD: print.c,v 1.39 2020/10/07 21:03:09 millert Exp $ */
2/* $NetBSD: print.c,v 1.15 1996/12/11 03:25:39 thorpej Exp $ */
3
4/*
5 * Copyright (c) 1989, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Michael Fischbein.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/types.h>
37#include <sys/stat.h>
38
39#include <err.h>
40#include <errno(*__errno()).h>
41#include <fts.h>
42#include <grp.h>
43#include <pwd.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <time.h>
48#include <unistd.h>
49#include <limits.h>
50#include <util.h>
51
52#include "ls.h"
53#include "extern.h"
54
55static int printaname(FTSENT *, int, int);
56static void printlink(FTSENT *);
57static void printsize(int, off_t);
58static void printtime(time_t);
59static int printtype(mode_t);
60static int compute_columns(DISPLAY *, int *);
61
62#define IS_NOPRINT(p)((p)->fts_number == 1) ((p)->fts_number == NO_PRINT1)
63
64#define DATELEN64 64
65
66#define SECSPERDAY(24 * 60 * 60) (24 * 60 * 60)
67#define SIXMONTHS((24 * 60 * 60) * 365 / 2) (SECSPERDAY(24 * 60 * 60) * 365 / 2)
68
69void
70printscol(DISPLAY *dp)
71{
72 FTSENT *p;
73
74 for (p = dp->list; p; p = p->fts_link) {
75 if (IS_NOPRINT(p)((p)->fts_number == 1))
76 continue;
77 (void)printaname(p, dp->s_inode, dp->s_block);
78 (void)putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
79 }
80}
81
82void
83printlong(DISPLAY *dp)
84{
85 struct stat *sp;
86 FTSENT *p;
87 NAMES *np;
88 char buf[20];
89
90 if ((dp->list == NULL((void *)0) || dp->list->fts_level != FTS_ROOTLEVEL0) &&
91 (f_longform || f_size))
92 (void)printf("total %llu\n", howmany(dp->btotal, blocksize)(((dp->btotal) + ((blocksize) - 1)) / (blocksize)));
93
94 for (p = dp->list; p; p = p->fts_link) {
95 if (IS_NOPRINT(p)((p)->fts_number == 1))
96 continue;
97 sp = p->fts_statp;
98 if (f_inode)
99 (void)printf("%*llu ", dp->s_inode,
100 (unsigned long long)sp->st_ino);
101 if (f_size)
102 (void)printf("%*lld ", dp->s_block,
103 howmany((long long)sp->st_blocks, blocksize)((((long long)sp->st_blocks) + ((blocksize) - 1)) / (blocksize
))
);
104 (void)strmode(sp->st_mode, buf);
105 np = p->fts_pointer;
106 (void)printf("%s %*u ", buf, dp->s_nlink, sp->st_nlink);
107 if (!f_grouponly)
108 (void)printf("%-*s ", dp->s_user, np->user);
109 (void)printf("%-*s ", dp->s_group, np->group);
110 if (f_flags)
111 (void)printf("%-*s ", dp->s_flags, np->flags);
112 if (S_ISCHR(sp->st_mode)((sp->st_mode & 0170000) == 0020000) || S_ISBLK(sp->st_mode)((sp->st_mode & 0170000) == 0060000))
113 (void)printf("%3u, %3u ",
114 major(sp->st_rdev)(((unsigned)(sp->st_rdev) >> 8) & 0xff), minor(sp->st_rdev)((unsigned)((sp->st_rdev) & 0xff) | (((sp->st_rdev)
& 0xffff0000) >> 8))
);
115 else if (dp->bcfile)
116 (void)printf("%*s%*lld ",
117 8 - dp->s_size, "", dp->s_size,
118 (long long)sp->st_size);
119 else
120 printsize(dp->s_size, sp->st_size);
121 if (f_accesstime)
122 printtime(sp->st_atimest_atim.tv_sec);
123 else if (f_statustime)
124 printtime(sp->st_ctimest_ctim.tv_sec);
125 else
126 printtime(sp->st_mtimest_mtim.tv_sec);
127 (void)mbsprint(p->fts_name, 1);
128 if (f_type || (f_typedir && S_ISDIR(sp->st_mode)((sp->st_mode & 0170000) == 0040000)))
129 (void)printtype(sp->st_mode);
130 if (S_ISLNK(sp->st_mode)((sp->st_mode & 0170000) == 0120000))
131 printlink(p);
132 (void)putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
133 }
134}
135
136static int
137compute_columns(DISPLAY *dp, int *pnum)
138{
139 int colwidth;
140 extern int termwidth;
141 int mywidth;
142
143 colwidth = dp->maxlen;
144 if (f_inode)
3
Assuming 'f_inode' is 0
4
Taking false branch
145 colwidth += dp->s_inode + 1;
146 if (f_size)
5
Assuming 'f_size' is 0
6
Taking false branch
147 colwidth += dp->s_block + 1;
148 if (f_type || f_typedir)
7
Assuming 'f_type' is 0
8
Assuming 'f_typedir' is 0
9
Taking false branch
149 colwidth += 1;
150
151 colwidth += 1;
152 mywidth = termwidth + 1; /* no extra space for last column */
153
154 if (mywidth < 2 * colwidth) {
10
Assuming the condition is false
11
Taking false branch
155 printscol(dp);
156 return (0);
157 }
158
159 *pnum = mywidth / colwidth;
160 return (mywidth / *pnum); /* spread out if possible */
12
Returning without writing to 'dp->list', which participates in a condition later
161}
162
163void
164printcol(DISPLAY *dp)
165{
166 static FTSENT **array;
1
'array' initialized to a null pointer value
167 static int lastentries = -1;
168 FTSENT *p;
169 int base, chcnt, col, colwidth, num;
170 int numcols, numrows, row;
171
172 if ((colwidth = compute_columns(dp, &numcols)) == 0)
2
Calling 'compute_columns'
13
Returning from 'compute_columns'
14
Assuming the condition is false
15
Taking false branch
173 return;
174 /*
175 * Have to do random access in the linked list -- build a table
176 * of pointers.
177 */
178 if (dp->entries > lastentries) {
16
Assuming 'lastentries' is >= field 'entries'
17
Taking false branch
179 FTSENT **a;
180
181 if ((a = reallocarray(array, dp->entries, sizeof(FTSENT *))) ==
182 NULL((void *)0)) {
183 free(array);
184 array = NULL((void *)0);
185 dp->entries = 0;
186 lastentries = -1;
187 warn(NULL((void *)0));
188 printscol(dp);
189 return;
190 }
191 lastentries = dp->entries;
192 array = a;
193 }
194 for (p = dp->list, num = 0; p; p = p->fts_link)
18
Loop condition is true. Entering loop body
195 if (p->fts_number != NO_PRINT1)
19
Assuming field 'fts_number' is not equal to NO_PRINT
20
Taking true branch
196 array[num++] = p;
21
Array access (from variable 'array') results in a null pointer dereference
197
198 numrows = num / numcols;
199 if (num % numcols)
200 ++numrows;
201
202 if ((dp->list == NULL((void *)0) || dp->list->fts_level != FTS_ROOTLEVEL0) &&
203 (f_longform || f_size))
204 (void)printf("total %llu\n", howmany(dp->btotal, blocksize)(((dp->btotal) + ((blocksize) - 1)) / (blocksize)));
205 for (row = 0; row < numrows; ++row) {
206 for (base = row, col = 0;;) {
207 chcnt = printaname(array[base], dp->s_inode, dp->s_block);
208 if ((base += numrows) >= num)
209 break;
210 if (++col == numcols)
211 break;
212 while (chcnt++ < colwidth)
213 putchar(' ')(!__isthreaded ? __sputc(' ', (&__sF[1])) : (putc)(' ', (
&__sF[1])))
;
214 }
215 (void)putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
216 }
217}
218
219/*
220 * print [inode] [size] name
221 * return # of characters printed, no trailing characters.
222 */
223static int
224printaname(FTSENT *p, int inodefield, int sizefield)
225{
226 struct stat *sp;
227 int chcnt;
228
229 sp = p->fts_statp;
230 chcnt = 0;
231 if (f_inode)
232 chcnt += printf("%*llu ", inodefield,
233 (unsigned long long)sp->st_ino);
234 if (f_size)
235 chcnt += printf("%*lld ", sizefield,
236 howmany((long long)sp->st_blocks, blocksize)((((long long)sp->st_blocks) + ((blocksize) - 1)) / (blocksize
))
);
237 chcnt += mbsprint(p->fts_name, 1);
238 if (f_type || (f_typedir && S_ISDIR(sp->st_mode)((sp->st_mode & 0170000) == 0040000)))
239 chcnt += printtype(sp->st_mode);
240 return (chcnt);
241}
242
243static void
244printtime(time_t ftime)
245{
246 char f_date[DATELEN64];
247 static time_t now;
248 static int now_set = 0;
249
250 if (! now_set) {
251 now = time(NULL((void *)0));
252 now_set = 1;
253 }
254
255 /*
256 * convert time to string, and print
257 */
258 if (strftime(f_date, sizeof(f_date), f_sectime ? "%b %e %H:%M:%S %Y" :
259 (ftime <= now - SIXMONTHS((24 * 60 * 60) * 365 / 2) || ftime > now) ? "%b %e %Y" :
260 "%b %e %H:%M", localtime(&ftime)) == 0)
261 f_date[0] = '\0';
262
263 printf("%s ", f_date);
264}
265
266void
267printacol(DISPLAY *dp)
268{
269 FTSENT *p;
270 int chcnt, col, colwidth;
271 int numcols;
272
273 if ( (colwidth = compute_columns(dp, &numcols)) == 0)
274 return;
275
276 if ((dp->list == NULL((void *)0) || dp->list->fts_level != FTS_ROOTLEVEL0) &&
277 (f_longform || f_size))
278 (void)printf("total %llu\n", howmany(dp->btotal, blocksize)(((dp->btotal) + ((blocksize) - 1)) / (blocksize)));
279 col = 0;
280 for (p = dp->list; p; p = p->fts_link) {
281 if (IS_NOPRINT(p)((p)->fts_number == 1))
282 continue;
283 if (col >= numcols) {
284 col = 0;
285 (void)putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
286 }
287 chcnt = printaname(p, dp->s_inode, dp->s_block);
288 col++;
289 if (col < numcols)
290 while (chcnt++ < colwidth)
291 (void)putchar(' ')(!__isthreaded ? __sputc(' ', (&__sF[1])) : (putc)(' ', (
&__sF[1])))
;
292 }
293 (void)putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
294}
295
296void
297printstream(DISPLAY *dp)
298{
299 extern int termwidth;
300 FTSENT *p;
301 int col;
302 int extwidth;
303
304 extwidth = 0;
305 if (f_inode)
306 extwidth += dp->s_inode + 1;
307 if (f_size)
308 extwidth += dp->s_block + 1;
309 if (f_type)
310 extwidth += 1;
311
312 for (col = 0, p = dp->list; p != NULL((void *)0); p = p->fts_link) {
313 if (IS_NOPRINT(p)((p)->fts_number == 1))
314 continue;
315 if (col > 0) {
316 (void)putchar(',')(!__isthreaded ? __sputc(',', (&__sF[1])) : (putc)(',', (
&__sF[1])))
, col++;
317 if (col + 1 + extwidth + mbsprint(p->fts_name, 0) >=
318 termwidth)
319 (void)putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
, col = 0;
320 else
321 (void)putchar(' ')(!__isthreaded ? __sputc(' ', (&__sF[1])) : (putc)(' ', (
&__sF[1])))
, col++;
322 }
323 col += printaname(p, dp->s_inode, dp->s_block);
324 }
325 (void)putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
326}
327
328static int
329printtype(mode_t mode)
330{
331 switch (mode & S_IFMT0170000) {
332 case S_IFDIR0040000:
333 (void)putchar('/')(!__isthreaded ? __sputc('/', (&__sF[1])) : (putc)('/', (
&__sF[1])))
;
334 return (1);
335 case S_IFIFO0010000:
336 (void)putchar('|')(!__isthreaded ? __sputc('|', (&__sF[1])) : (putc)('|', (
&__sF[1])))
;
337 return (1);
338 case S_IFLNK0120000:
339 (void)putchar('@')(!__isthreaded ? __sputc('@', (&__sF[1])) : (putc)('@', (
&__sF[1])))
;
340 return (1);
341 case S_IFSOCK0140000:
342 (void)putchar('=')(!__isthreaded ? __sputc('=', (&__sF[1])) : (putc)('=', (
&__sF[1])))
;
343 return (1);
344 }
345 if (mode & (S_IXUSR0000100 | S_IXGRP0000010 | S_IXOTH0000001)) {
346 (void)putchar('*')(!__isthreaded ? __sputc('*', (&__sF[1])) : (putc)('*', (
&__sF[1])))
;
347 return (1);
348 }
349 return (0);
350}
351
352static void
353printlink(FTSENT *p)
354{
355 int lnklen;
356 char name[PATH_MAX1024], path[PATH_MAX1024];
357
358 if (p->fts_level == FTS_ROOTLEVEL0)
359 (void)snprintf(name, sizeof(name), "%s", p->fts_name);
360 else
361 (void)snprintf(name, sizeof(name),
362 "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
363 if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
364 (void)fprintf(stderr(&__sF[2]), "\nls: %s: %s\n", name, strerror(errno(*__errno())));
365 return;
366 }
367 path[lnklen] = '\0';
368 (void)printf(" -> ");
369 (void)mbsprint(path, 1);
370}
371
372static void
373printsize(int width, off_t bytes)
374{
375 char ret[FMT_SCALED_STRSIZE7];
376
377 if ((f_humanval) && (fmt_scaled(bytes, ret) != -1)) {
378 (void)printf("%*s ", width, ret);
379 return;
380 }
381 (void)printf("%*lld ", width, (long long)bytes);
382}