Bug Summary

File:src/games/worms/worms.c
Warning:line 252, column 9
Dereference of null pointer

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 worms.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/games/worms/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/games/worms/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/games/worms/worms.c
1/* $OpenBSD: worms.c,v 1.30 2021/10/23 11:22:49 mestre Exp $ */
2
3/*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 *
34 * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@
35 * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@
36 * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@
37 * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
38 * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
39 * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@
40 * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@
41 * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@
42 * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@
43 *
44 * Eric P. Scott
45 * Caltech High Energy Physics
46 * October, 1980
47 *
48 */
49#include <curses.h>
50#include <err.h>
51#include <signal.h>
52#include <stdlib.h>
53#include <termios.h>
54#include <unistd.h>
55
56static const struct options {
57 int nopts;
58 int opts[3];
59}
60 normal[8] = {
61 { 3, { 7, 0, 1 } },
62 { 3, { 0, 1, 2 } },
63 { 3, { 1, 2, 3 } },
64 { 3, { 2, 3, 4 } },
65 { 3, { 3, 4, 5 } },
66 { 3, { 4, 5, 6 } },
67 { 3, { 5, 6, 7 } },
68 { 3, { 6, 7, 0 } }
69}, upper[8] = {
70 { 1, { 1, 0, 0 } },
71 { 2, { 1, 2, 0 } },
72 { 0, { 0, 0, 0 } },
73 { 0, { 0, 0, 0 } },
74 { 0, { 0, 0, 0 } },
75 { 2, { 4, 5, 0 } },
76 { 1, { 5, 0, 0 } },
77 { 2, { 1, 5, 0 } }
78},
79 left[8] = {
80 { 0, { 0, 0, 0 } },
81 { 0, { 0, 0, 0 } },
82 { 0, { 0, 0, 0 } },
83 { 2, { 2, 3, 0 } },
84 { 1, { 3, 0, 0 } },
85 { 2, { 3, 7, 0 } },
86 { 1, { 7, 0, 0 } },
87 { 2, { 7, 0, 0 } }
88},
89 right[8] = {
90 { 1, { 7, 0, 0 } },
91 { 2, { 3, 7, 0 } },
92 { 1, { 3, 0, 0 } },
93 { 2, { 3, 4, 0 } },
94 { 0, { 0, 0, 0 } },
95 { 0, { 0, 0, 0 } },
96 { 0, { 0, 0, 0 } },
97 { 2, { 6, 7, 0 } }
98},
99 lower[8] = {
100 { 0, { 0, 0, 0 } },
101 { 2, { 0, 1, 0 } },
102 { 1, { 1, 0, 0 } },
103 { 2, { 1, 5, 0 } },
104 { 1, { 5, 0, 0 } },
105 { 2, { 5, 6, 0 } },
106 { 0, { 0, 0, 0 } },
107 { 0, { 0, 0, 0 } }
108},
109 upleft[8] = {
110 { 0, { 0, 0, 0 } },
111 { 0, { 0, 0, 0 } },
112 { 0, { 0, 0, 0 } },
113 { 0, { 0, 0, 0 } },
114 { 0, { 0, 0, 0 } },
115 { 1, { 3, 0, 0 } },
116 { 2, { 1, 3, 0 } },
117 { 1, { 1, 0, 0 } }
118},
119 upright[8] = {
120 { 2, { 3, 5, 0 } },
121 { 1, { 3, 0, 0 } },
122 { 0, { 0, 0, 0 } },
123 { 0, { 0, 0, 0 } },
124 { 0, { 0, 0, 0 } },
125 { 0, { 0, 0, 0 } },
126 { 0, { 0, 0, 0 } },
127 { 1, { 5, 0, 0 } }
128},
129 lowleft[8] = {
130 { 3, { 7, 0, 1 } },
131 { 0, { 0, 0, 0 } },
132 { 0, { 0, 0, 0 } },
133 { 1, { 1, 0, 0 } },
134 { 2, { 1, 7, 0 } },
135 { 1, { 7, 0, 0 } },
136 { 0, { 0, 0, 0 } },
137 { 0, { 0, 0, 0 } }
138},
139 lowright[8] = {
140 { 0, { 0, 0, 0 } },
141 { 1, { 7, 0, 0 } },
142 { 2, { 5, 7, 0 } },
143 { 1, { 5, 0, 0 } },
144 { 0, { 0, 0, 0 } },
145 { 0, { 0, 0, 0 } },
146 { 0, { 0, 0, 0 } },
147 { 0, { 0, 0, 0 } }
148};
149
150static const char flavor[] = {
151 'O', '*', '#', '$', '%', '0', '@', '~'
152};
153static const short xinc[] = {
154 1, 1, 1, 0, -1, -1, -1, 0
155}, yinc[] = {
156 -1, 0, 1, 1, 1, 0, -1, -1
157};
158static struct worm {
159 int orientation, head;
160 short *xpos, *ypos;
161} *worm;
162
163volatile sig_atomic_t sig_caught = 0;
164
165void nomem(void);
166void onsig(int);
167
168int
169main(int argc, char *argv[])
170{
171 int x, y, h, n;
172 struct worm *w;
173 const struct options *op;
174 short *ip;
175 int CO, LI, last, bottom, ch, length, number, trail;
176 short **ref;
177 const char *field, *errstr;
178 struct timespec sleeptime;
179 struct termios term;
180 speed_t speed;
181 time_t delay = 0;
182
183 /* set default delay based on terminal baud rate */
184 if (tcgetattr(STDOUT_FILENO1, &term) == 0 &&
1
Assuming the condition is false
185 (speed = cfgetospeed(&term)) > B96009600)
186 delay = (speed / B96009600) - 1;
187
188 length = 16;
189 number = 3;
190 trail = ' ';
191 field = NULL((void *)0);
192 while ((ch = getopt(argc, argv, "d:fhl:n:t")) != -1)
2
Assuming the condition is false
3
Loop condition is false. Execution continues on line 226
193 switch(ch) {
194 case 'd':
195 delay = (time_t)strtonum(optarg, 0, 1000, &errstr);
196 if (errstr)
197 errx(1, "delay (0-1000) is %s: %s", errstr,
198 optarg);
199 break;
200 case 'f':
201 field = "WORM";
202 break;
203 case 'l':
204 length = strtonum(optarg, 2, 1024, &errstr);
205 if (errstr)
206 errx(1, "length (2-1024) is %s: %s", errstr,
207 optarg);
208 break;
209 case 'n':
210 number = strtonum(optarg, 1, 100, &errstr);
211 if (errstr)
212 errx(1, "number of worms (1-100) is %s: %s",
213 errstr, optarg);
214 break;
215 case 't':
216 trail = '.';
217 break;
218 case 'h':
219 default:
220 (void)fprintf(stderr(&__sF[2]), "usage: %s [-ft] [-d delay] "
221 "[-l length] [-n number]\n", getprogname());
222 return 1;
223 }
224
225 /* Convert delay from ms -> ns */
226 sleeptime.tv_sec = 0;
227 sleeptime.tv_nsec = delay * 500000;
228 timespecadd(&sleeptime, &sleeptime, &sleeptime)do { (&sleeptime)->tv_sec = (&sleeptime)->tv_sec
+ (&sleeptime)->tv_sec; (&sleeptime)->tv_nsec =
(&sleeptime)->tv_nsec + (&sleeptime)->tv_nsec;
if ((&sleeptime)->tv_nsec >= 1000000000L) { (&
sleeptime)->tv_sec++; (&sleeptime)->tv_nsec -= 1000000000L
; } } while (0)
;
4
Taking false branch
5
Loop condition is false. Exiting loop
229
230 if (!(worm = calloc(number, sizeof(struct worm))))
6
Assuming 'worm' is non-null
7
Taking false branch
231 nomem();
232 initscr();
233
234 if (pledge("stdio tty", NULL((void *)0)) == -1)
8
Assuming the condition is false
9
Taking false branch
235 err(1, "pledge");
236
237 curs_set(0);
238 CO = COLS;
239 LI = LINES;
240 last = CO - 1;
241 bottom = LI - 1;
242 if (!(ip = reallocarray(NULL((void *)0), LI, CO * sizeof(short))) ||
10
Assuming 'ip' is non-null
12
Taking false branch
243 !(ref = calloc(LI, sizeof(short *)))) {
11
Assuming 'ref' is non-null
244 endwin();
245 nomem();
246 }
247 for (n = 0; n < LI; ++n) {
13
Assuming 'n' is >= 'LI'
14
Loop condition is false. Execution continues on line 251
248 ref[n] = ip;
249 ip += CO;
250 }
251 for (ip = ref[0], n = LI * CO; --n >= 0;)
15
Assuming the condition is true
16
Loop condition is true. Entering loop body
252 *ip++ = 0;
17
Null pointer value stored to 'ip'
18
Dereference of null pointer
253 for (n = number, w = &worm[0]; --n >= 0; w++) {
254 w->orientation = w->head = 0;
255 if (!(ip = calloc(length, sizeof(short)))) {
256 endwin();
257 nomem();
258 }
259 w->xpos = ip;
260 for (x = length; --x >= 0;)
261 *ip++ = -1;
262 if (!(ip = calloc(length, sizeof(short)))) {
263 endwin();
264 nomem();
265 }
266 w->ypos = ip;
267 for (y = length; --y >= 0;)
268 *ip++ = -1;
269 }
270
271 (void)signal(SIGHUP1, onsig);
272 (void)signal(SIGINT2, onsig);
273 (void)signal(SIGQUIT3, onsig);
274 (void)signal(SIGSTOP17, onsig);
275 (void)signal(SIGTSTP18, onsig);
276 (void)signal(SIGTERM15, onsig);
277
278 if (field) {
279 const char *p = field;
280
281 for (y = LI; --y >= 0;) {
282 for (x = CO; --x >= 0;) {
283 addch(*p++)waddch(stdscr,*p++);
284 if (!*p)
285 p = field;
286 }
287 refresh()wrefresh(stdscr);
288 }
289 }
290 for (;;) {
291 refresh()wrefresh(stdscr);
292 if (sig_caught) {
293 endwin();
294 return 0;
295 }
296 nanosleep(&sleeptime, NULL((void *)0));
297 for (n = 0, w = &worm[0]; n < number; n++, w++) {
298 if ((x = w->xpos[h = w->head]) < 0) {
299 mvaddch(y = w->ypos[h] = bottom,(wmove(stdscr,y = w->ypos[h] = bottom,x = w->xpos[h] = 0
) == (-1) ? (-1) : waddch(stdscr,flavor[n % sizeof(flavor)]))
300 x = w->xpos[h] = 0,(wmove(stdscr,y = w->ypos[h] = bottom,x = w->xpos[h] = 0
) == (-1) ? (-1) : waddch(stdscr,flavor[n % sizeof(flavor)]))
301 flavor[n % sizeof(flavor)])(wmove(stdscr,y = w->ypos[h] = bottom,x = w->xpos[h] = 0
) == (-1) ? (-1) : waddch(stdscr,flavor[n % sizeof(flavor)]))
;
302 ref[y][x]++;
303 }
304 else
305 y = w->ypos[h];
306 if (++h == length)
307 h = 0;
308 if (w->xpos[w->head = h] >= 0) {
309 int x1, y1;
310
311 x1 = w->xpos[h];
312 y1 = w->ypos[h];
313 if (--ref[y1][x1] == 0)
314 mvaddch(y1, x1, trail)(wmove(stdscr,y1,x1) == (-1) ? (-1) : waddch(stdscr,trail));
315 }
316
317 if (x == 0) {
318 if (y == 0)
319 op = &upleft[w->orientation];
320 else if (y == bottom)
321 op = &lowleft[w->orientation];
322 else
323 op = &left[w->orientation];
324 } else if (x == last) {
325 if (y == 0)
326 op = &upright[w->orientation];
327 else if (y == bottom)
328 op = &lowright[w->orientation];
329 else
330 op = &right[w->orientation];
331 } else {
332 if (y == 0)
333 op = &upper[w->orientation];
334 else if (y == bottom)
335 op = &lower[w->orientation];
336 else
337 op = &normal[w->orientation];
338 }
339
340 switch (op->nopts) {
341 case 0:
342 endwin();
343 return(1);
344 case 1:
345 w->orientation = op->opts[0];
346 break;
347 default:
348 w->orientation =
349 op->opts[arc4random_uniform(op->nopts)];
350 }
351 mvaddch(y += yinc[w->orientation],(wmove(stdscr,y += yinc[w->orientation],x += xinc[w->orientation
]) == (-1) ? (-1) : waddch(stdscr,flavor[n % sizeof(flavor)])
)
352 x += xinc[w->orientation],(wmove(stdscr,y += yinc[w->orientation],x += xinc[w->orientation
]) == (-1) ? (-1) : waddch(stdscr,flavor[n % sizeof(flavor)])
)
353 flavor[n % sizeof(flavor)])(wmove(stdscr,y += yinc[w->orientation],x += xinc[w->orientation
]) == (-1) ? (-1) : waddch(stdscr,flavor[n % sizeof(flavor)])
)
;
354 ref[w->ypos[h] = y][w->xpos[h] = x]++;
355 }
356 }
357}
358
359void
360onsig(int signo)
361{
362 sig_caught = 1;
363}
364
365void
366nomem(void)
367{
368 errx(1, "not enough memory.");
369}