Bug Summary

File:src/usr.bin/sndiod/file.c
Warning:line 362, column 5
1st function call argument is an uninitialized value

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 file.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/usr.bin/sndiod/obj -resource-dir /usr/local/lib/clang/13.0.0 -D DEBUG -I /usr/src/usr.bin/sndiod/../../lib/libsndio -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/sndiod/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/usr.bin/sndiod/file.c
1/* $OpenBSD: file.c,v 1.25 2019/11/27 08:18:22 ratchov Exp $ */
2/*
3 * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17/*
18 * non-blocking file i/o module: each file can be read or written (or
19 * both). To achieve non-blocking io, we simply use the poll() syscall
20 * in an event loop and dispatch events to sub-modules.
21 *
22 * the module also provides trivial timeout implementation,
23 * derived from:
24 *
25 * anoncvs@moule.caoua.org:/midish
26 *
27 * midish/timo.c rev 1.18
28 * midish/mdep.c rev 1.71
29 *
30 * A timeout is used to schedule the call of a routine (the callback)
31 * there is a global list of timeouts that is processed inside the
32 * event loop. Timeouts work as follows:
33 *
34 * first the timo structure must be initialized with timo_set()
35 *
36 * then the timeout is scheduled (only once) with timo_add()
37 *
38 * if the timeout expires, the call-back is called; then it can
39 * be scheduled again if needed. It's OK to reschedule it again
40 * from the callback
41 *
42 * the timeout can be aborted with timo_del(), it is OK to try to
43 * abort a timout that has expired
44 *
45 */
46
47#include <sys/types.h>
48
49#include <errno(*__errno()).h>
50#include <fcntl.h>
51#include <poll.h>
52#include <signal.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <time.h>
56
57#include "file.h"
58#include "utils.h"
59
60#define MAXFDS100 100
61#define TIMER_MSEC5 5
62
63void timo_update(unsigned int);
64void timo_init(void);
65void timo_done(void);
66void file_process(struct file *, struct pollfd *);
67
68struct timespec file_ts;
69struct file *file_list;
70struct timo *timo_queue;
71unsigned int timo_abstime;
72int file_slowaccept = 0, file_nfds;
73#ifdef DEBUG1
74long long file_wtime, file_utime;
75#endif
76
77/*
78 * initialise a timeout structure, arguments are callback and argument
79 * that will be passed to the callback
80 */
81void
82timo_set(struct timo *o, void (*cb)(void *), void *arg)
83{
84 o->cb = cb;
85 o->arg = arg;
86 o->set = 0;
87}
88
89/*
90 * schedule the callback in 'delta' 24-th of microseconds. The timeout
91 * must not be already scheduled
92 */
93void
94timo_add(struct timo *o, unsigned int delta)
95{
96 struct timo **i;
97 unsigned int val;
98 int diff;
99
100#ifdef DEBUG1
101 if (o->set) {
102 log_puts("timo_add: already set\n");
103 panic();
104 }
105 if (delta == 0) {
106 log_puts("timo_add: zero timeout is evil\n");
107 panic();
108 }
109#endif
110 val = timo_abstime + delta;
111 for (i = &timo_queue; *i != NULL((void*)0); i = &(*i)->next) {
112 diff = (*i)->val - val;
113 if (diff > 0) {
114 break;
115 }
116 }
117 o->set = 1;
118 o->val = val;
119 o->next = *i;
120 *i = o;
121}
122
123/*
124 * abort a scheduled timeout
125 */
126void
127timo_del(struct timo *o)
128{
129 struct timo **i;
130
131 for (i = &timo_queue; *i != NULL((void*)0); i = &(*i)->next) {
132 if (*i == o) {
133 *i = o->next;
134 o->set = 0;
135 return;
136 }
137 }
138#ifdef DEBUG1
139 if (log_level >= 4)
140 log_puts("timo_del: not found\n");
141#endif
142}
143
144/*
145 * routine to be called by the timer when 'delta' 24-th of microsecond
146 * elapsed. This routine updates time referece used by timeouts and
147 * calls expired timeouts
148 */
149void
150timo_update(unsigned int delta)
151{
152 struct timo *to;
153 int diff;
154
155 /*
156 * update time reference
157 */
158 timo_abstime += delta;
159
160 /*
161 * remove from the queue and run expired timeouts
162 */
163 while (timo_queue != NULL((void*)0)) {
164 /*
165 * there is no overflow here because + and - are
166 * modulo 2^32, they are the same for both signed and
167 * unsigned integers
168 */
169 diff = timo_queue->val - timo_abstime;
170 if (diff > 0)
171 break;
172 to = timo_queue;
173 timo_queue = to->next;
174 to->set = 0;
175 to->cb(to->arg);
176 }
177}
178
179/*
180 * initialize timeout queue
181 */
182void
183timo_init(void)
184{
185 timo_queue = NULL((void*)0);
186 timo_abstime = 0;
187}
188
189/*
190 * destroy timeout queue
191 */
192void
193timo_done(void)
194{
195#ifdef DEBUG1
196 if (timo_queue != NULL((void*)0)) {
197 log_puts("timo_done: timo_queue not empty!\n");
198 panic();
199 }
200#endif
201 timo_queue = (struct timo *)0xdeadbeef;
202}
203
204#ifdef DEBUG1
205void
206file_log(struct file *f)
207{
208 static char *states[] = { "ini", "zom" };
209
210 log_puts(f->ops->name);
211 if (log_level >= 3) {
212 log_puts("(");
213 log_puts(f->name);
214 log_puts("|");
215 log_puts(states[f->state]);
216 log_puts(")");
217 }
218}
219#endif
220
221struct file *
222file_new(struct fileops *ops, void *arg, char *name, unsigned int nfds)
223{
224 struct file *f;
225
226 if (file_nfds + nfds > MAXFDS100) {
227#ifdef DEBUG1
228 if (log_level >= 1) {
229 log_puts(name);
230 log_puts(": too many polled files\n");
231 }
232#endif
233 return NULL((void*)0);
234 }
235 f = xmalloc(sizeof(struct file));
236 f->max_nfds = nfds;
237 f->nfds = 0;
238 f->ops = ops;
239 f->arg = arg;
240 f->name = name;
241 f->state = FILE_INIT0;
242 f->next = file_list;
243 file_list = f;
244#ifdef DEBUG1
245 if (log_level >= 3) {
246 file_log(f);
247 log_puts(": created\n");
248 }
249#endif
250 file_nfds += f->max_nfds;
251 return f;
252}
253
254void
255file_del(struct file *f)
256{
257#ifdef DEBUG1
258 if (f->state == FILE_ZOMB1) {
259 log_puts("bad state in file_del()\n");
260 panic();
261 }
262#endif
263 file_nfds -= f->max_nfds;
264 f->state = FILE_ZOMB1;
265#ifdef DEBUG1
266 if (log_level >= 3) {
267 file_log(f);
268 log_puts(": destroyed\n");
269 }
270#endif
271}
272
273void
274file_process(struct file *f, struct pollfd *pfd)
275{
276 int revents;
277#ifdef DEBUG1
278 struct timespec ts0, ts1;
279 long us;
280#endif
281
282#ifdef DEBUG1
283 if (log_level >= 3)
284 clock_gettime(CLOCK_UPTIME5, &ts0);
285#endif
286 revents = (f->state != FILE_ZOMB1) ?
287 f->ops->revents(f->arg, pfd) : 0;
288 if ((revents & POLLHUP0x0010) && (f->state != FILE_ZOMB1))
289 f->ops->hup(f->arg);
290 if ((revents & POLLIN0x0001) && (f->state != FILE_ZOMB1))
291 f->ops->in(f->arg);
292 if ((revents & POLLOUT0x0004) && (f->state != FILE_ZOMB1))
293 f->ops->out(f->arg);
294#ifdef DEBUG1
295 if (log_level >= 3) {
296 clock_gettime(CLOCK_UPTIME5, &ts1);
297 us = 1000000L * (ts1.tv_sec - ts0.tv_sec);
298 us += (ts1.tv_nsec - ts0.tv_nsec) / 1000;
299 if (log_level >= 4 || us >= 5000) {
300 file_log(f);
301 log_puts(": processed in ");
302 log_putu(us);
303 log_puts("us\n");
304 }
305 }
306#endif
307}
308
309int
310file_poll(void)
311{
312 struct pollfd pfds[MAXFDS100], *pfd;
313 struct file *f, **pf;
314 struct timespec ts;
315#ifdef DEBUG1
316 struct timespec sleepts;
317 int i;
318#endif
319 long long delta_nsec;
320 int nfds, res, timo;
321
322 /*
323 * cleanup zombies
324 */
325 pf = &file_list;
326 while ((f = *pf) != NULL((void*)0)) {
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 334
327 if (f->state == FILE_ZOMB1) {
328 *pf = f->next;
329 xfree(f);
330 } else
331 pf = &f->next;
332 }
333
334 if (file_list
2.1
'file_list' is equal to NULL
== NULL((void*)0) && timo_queue == NULL((void*)0)) {
3
Assuming 'timo_queue' is not equal to NULL
4
Taking false branch
335#ifdef DEBUG1
336 if (log_level >= 3)
337 log_puts("nothing to do...\n");
338#endif
339 return 0;
340 }
341
342 /*
343 * fill pollfd structures
344 */
345 nfds = 0;
346 for (f = file_list; f != NULL((void*)0); f = f->next) {
5
Loop condition is false. Execution continues on line 353
347 f->nfds = f->ops->pollfd(f->arg, pfds + nfds);
348 if (f->nfds == 0)
349 continue;
350 nfds += f->nfds;
351 }
352#ifdef DEBUG1
353 if (log_level >= 4) {
6
Assuming 'log_level' is >= 4
7
Taking true branch
354 log_puts("poll:");
355 pfd = pfds;
356 for (f = file_list; f != NULL((void*)0); f = f->next) {
8
Assuming 'f' is not equal to NULL
9
Loop condition is true. Entering loop body
357 log_puts(" ");
358 log_puts(f->ops->name);
359 log_puts(":");
360 for (i = 0; i < f->nfds; i++) {
10
Assuming 'i' is < field 'nfds'
11
Loop condition is true. Entering loop body
361 log_puts(" ");
362 log_putx(pfd->events);
12
1st function call argument is an uninitialized value
363 pfd++;
364 }
365 }
366 log_puts("\n");
367 }
368#endif
369
370 /*
371 * process files that do not rely on poll
372 */
373 for (f = file_list; f != NULL((void*)0); f = f->next) {
374 if (f->nfds > 0)
375 continue;
376 file_process(f, NULL((void*)0));
377 }
378
379 /*
380 * Sleep. Calculate the number of milliseconds poll(2) must
381 * wait before the timo_update() needs to be called. If there are
382 * no timeouts scheduled, then call poll(2) with infinite
383 * timeout (i.e -1).
384 */
385#ifdef DEBUG1
386 clock_gettime(CLOCK_UPTIME5, &sleepts);
387 file_utime += 1000000000LL * (sleepts.tv_sec - file_ts.tv_sec);
388 file_utime += sleepts.tv_nsec - file_ts.tv_nsec;
389#endif
390 if (timo_queue != NULL((void*)0)) {
391 timo = ((int)timo_queue->val - (int)timo_abstime) / 1000;
392 if (timo < TIMER_MSEC5)
393 timo = TIMER_MSEC5;
394 } else
395 timo = -1;
396 log_flush();
397 res = poll(pfds, nfds, timo);
398 if (res == -1) {
399 if (errno(*__errno()) != EINTR4) {
400 log_puts("poll failed");
401 panic();
402 }
403 return 1;
404 }
405
406 /*
407 * run timeouts
408 */
409 clock_gettime(CLOCK_UPTIME5, &ts);
410#ifdef DEBUG1
411 file_wtime += 1000000000LL * (ts.tv_sec - sleepts.tv_sec);
412 file_wtime += ts.tv_nsec - sleepts.tv_nsec;
413#endif
414 if (timo_queue) {
415 delta_nsec = 1000000000LL * (ts.tv_sec - file_ts.tv_sec);
416 delta_nsec += ts.tv_nsec - file_ts.tv_nsec;
417 if (delta_nsec >= 0 && delta_nsec < 60000000000LL)
418 timo_update(delta_nsec / 1000);
419 else {
420 if (log_level >= 2)
421 log_puts("out-of-bounds clock delta\n");
422 }
423 }
424 file_ts = ts;
425
426 /*
427 * process files that rely on poll
428 */
429 pfd = pfds;
430 for (f = file_list; f != NULL((void*)0); f = f->next) {
431 if (f->nfds == 0)
432 continue;
433 file_process(f, pfd);
434 pfd += f->nfds;
435 }
436 return 1;
437}
438
439void
440filelist_init(void)
441{
442 sigset_t set;
443
444 if (clock_gettime(CLOCK_UPTIME5, &file_ts) == -1) {
445 log_puts("filelist_init: CLOCK_UPTIME unsupported\n");
446 panic();
447 }
448 sigemptyset(&set);
449 sigaddset(&set, SIGPIPE13);
450 sigprocmask(SIG_BLOCK1, &set, NULL((void*)0));
451 file_list = NULL((void*)0);
452 log_sync = 0;
453 timo_init();
454}
455
456void
457filelist_done(void)
458{
459#ifdef DEBUG1
460 struct file *f;
461
462 if (file_list != NULL((void*)0)) {
463 for (f = file_list; f != NULL((void*)0); f = f->next) {
464 file_log(f);
465 log_puts(" not closed\n");
466 }
467 panic();
468 }
469 log_sync = 1;
470 log_flush();
471#endif
472 timo_done();
473}