Bug Summary

File:src/games/sail/sync.c
Warning:line 379, column 10
Null pointer passed as 2nd argument to string copy function

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 sync.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/sail/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/sail/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/sail/sync.c
1/* $OpenBSD: sync.c,v 1.16 2019/06/28 13:32:52 deraadt Exp $ */
2/* $NetBSD: sync.c,v 1.9 1998/08/30 09:19:40 veego Exp $ */
3
4/*
5 * Copyright (c) 1983, 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
35#include <errno(*__errno()).h>
36#ifdef LOCK_EX
37#include <fcntl.h>
38#endif
39#include <signal.h>
40#include <stdlib.h>
41#include <string.h>
42#include <time.h>
43#include <unistd.h>
44
45#include "extern.h"
46#include "machdep.h"
47#include "pathnames.h"
48#include "player.h"
49
50#define BUFSIZE4096 4096
51
52static const char SF[] = _PATH_SYNC"/tmp/#sailsink.%d";
53static const char LF[] = _PATH_LOCK"/tmp/#saillock.%d";
54static char sync_buf[BUFSIZE4096];
55static char *sync_bp = sync_buf;
56static char sync_lock[sizeof SF];
57static char sync_file[sizeof LF];
58static long sync_seek;
59static FILE *sync_fp;
60
61void
62fmtship(char *buf, size_t len, const char *fmt, struct ship *ship)
63{
64 if (len == 0)
65 abort(); /* XXX */
66
67 while (*fmt && len > 1) {
68 if (*fmt == '$' && fmt[1] == '$') {
69 size_t l;
70 snprintf(buf, len, "%s (%c%c)",
71 ship->shipname, colours(ship), sterncolour(ship)((ship)->file->stern+'0'-((ship)->file->captured?
10:0))
);
72 l = strlen(buf);
73 buf += l;
74 len -= l;
75 fmt += 2;
76 } else {
77 *buf++ = *fmt++;
78 len--;
79 }
80 }
81
82 *buf = '\0';
83}
84
85
86void
87makesignal(struct ship *from, const char *fmt, struct ship *ship, ...)
88{
89 char message[BUFSIZ1024];
90 char format[BUFSIZ1024];
91 va_list ap;
92
93 va_start(ap, ship)__builtin_va_start(ap, ship);
94 fmtship(format, sizeof(format), fmt, ship);
95 (void) vsnprintf(message, sizeof message, format, ap);
96 va_end(ap)__builtin_va_end(ap);
97 Writestr(W_SIGNAL24, from, message);
98}
99
100void
101makemsg(struct ship *from, const char *fmt, ...)
102{
103 char message[BUFSIZ1024];
104 va_list ap;
105
106 va_start(ap, fmt)__builtin_va_start(ap, fmt);
107 (void) vsnprintf(message, sizeof message, fmt, ap);
108 va_end(ap)__builtin_va_end(ap);
109 Writestr(W_SIGNAL24, from, message);
110}
111
112int
113sync_exists(int game)
114{
115 char buf[sizeof sync_file];
116 struct stat s;
117 time_t t;
118
119 (void) snprintf(buf, sizeof buf, SF, game);
120 (void) time(&t);
121 setegid(egid);
122 if (stat(buf, &s) == -1) {
123 setegid(gid);
124 return 0;
125 }
126 if (s.st_mtimest_mtim.tv_sec < t - 60*60*2) { /* 2 hours */
127 (void) unlink(buf);
128 (void) snprintf(buf, sizeof buf, LF, game);
129 (void) unlink(buf);
130 setegid(gid);
131 return 0;
132 }
133 setegid(gid);
134 return 1;
135}
136
137int
138sync_open(void)
139{
140 struct stat tmp;
141
142 if (sync_fp != NULL((void *)0))
143 (void) fclose(sync_fp);
144 (void) snprintf(sync_lock, sizeof sync_lock, LF, game);
145 (void) snprintf(sync_file, sizeof sync_file, SF, game);
146 setegid(egid);
147 if (stat(sync_file, &tmp) == -1) {
148 mode_t omask = umask(002);
149 sync_fp = fopen(sync_file, "w+");
150 (void) umask(omask);
151 } else
152 sync_fp = fopen(sync_file, "r+");
153 setegid(gid);
154 if (sync_fp == NULL((void *)0))
155 return -1;
156 sync_seek = 0;
157 return 0;
158}
159
160void
161sync_close(int remove)
162{
163 if (sync_fp != 0)
164 (void) fclose(sync_fp);
165 if (remove) {
166 setegid(egid);
167 (void) unlink(sync_file);
168 setegid(gid);
169 }
170}
171
172void
173Write(int type, struct ship *ship, long a, long b, long c, long d)
174{
175 (void) snprintf(sync_bp, sync_buf + sizeof sync_buf - sync_bp,
176 "%d %d 0 %ld %ld %ld %ld\n",
177 type, ship->file->index, a, b, c, d);
178 while (*sync_bp++)
179 ;
180 sync_bp--;
181 if (sync_bp >= &sync_buf[sizeof sync_buf])
182 abort();
183 (void) sync_update(type, ship, NULL((void *)0), a, b, c, d);
184}
185
186void
187Writestr(int type, struct ship *ship, const char *a)
188{
189 (void) snprintf(sync_bp, sync_buf + sizeof sync_buf - sync_bp,
190 "%d %d 1 %s\n",
191 type, ship->file->index, a);
192 while (*sync_bp++)
193 ;
194 sync_bp--;
195 if (sync_bp >= &sync_buf[sizeof sync_buf])
196 abort();
197 (void) sync_update(type, ship, a, 0, 0, 0, 0);
198}
199
200int
201Sync(void)
202{
203 sig_t sighup, sigint;
204 int n;
205 int type, shipnum, isstr;
206 char *astr;
207 long a, b, c, d;
208 char buf[80];
209 char erred = 0;
210
211 sighup = signal(SIGHUP1, SIG_IGN(void (*)(int))1);
212 sigint = signal(SIGINT2, SIG_IGN(void (*)(int))1);
213 for (n = TIMEOUT300; --n >= 0;) {
1
Loop condition is true. Entering loop body
214#ifdef LOCK_EX
215 if (flock(fileno(sync_fp)(!__isthreaded ? ((sync_fp)->_file) : (fileno)(sync_fp)), LOCK_EX|LOCK_NB) >= 0)
216 break;
217 if (errno(*__errno()) != EWOULDBLOCK35)
218 return -1;
219#else
220 setegid(egid);
221 if (link(sync_file, sync_lock) >= 0) {
2
Assuming the condition is true
3
Taking true branch
222 setegid(gid);
223 break;
4
Execution continues on line 231
224 }
225 setegid(gid);
226 if (errno(*__errno()) != EEXIST17)
227 return -1;
228#endif
229 sleep(1);
230 }
231 if (n
4.1
'n' is > 0
<= 0)
5
Taking false branch
232 return -1;
233 (void) fseek(sync_fp, sync_seek, SEEK_SET0);
234 for (;;) {
6
Loop condition is true. Entering loop body
235 switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) {
7
Control jumps to 'case 3:' at line 236
236 case 3:
237 break;
8
Execution continues on line 243
238 case EOF(-1):
239 goto out;
240 default:
241 goto bad;
242 }
243 if (shipnum < 0 || shipnum >= cc->vessels)
9
Assuming 'shipnum' is >= 0
10
Assuming 'shipnum' is < field 'vessels'
11
Taking false branch
244 goto bad;
245 if (isstr != 0 && isstr != 1)
12
Assuming 'isstr' is equal to 0
246 goto bad;
247 if (isstr
12.1
'isstr' is 0
) {
13
Taking false branch
248 int ch;
249 char *p;
250
251 for (p = buf;;) {
252 ch = getc(sync_fp)(!__isthreaded ? (--(sync_fp)->_r < 0 ? __srget(sync_fp
) : (int)(*(sync_fp)->_p++)) : (getc)(sync_fp))
;
253 switch (ch) {
254 case '\n':
255 case EOF(-1):
256 break;
257 default:
258 if (p < buf + sizeof buf)
259 *p++ = ch;
260 continue;
261 }
262 break;
263 }
264 *p = 0;
265 for (p = buf; *p == ' '; p++)
266 ;
267 astr = p;
268 a = b = c = d = 0;
269 } else {
270 if (fscanf(sync_fp, "%ld%ld%ld%ld", &a, &b, &c, &d) != 4)
14
Assuming the condition is false
15
Taking false branch
271 goto bad;
272 astr = NULL((void *)0);
16
Null pointer value stored to 'astr'
273 }
274 if (sync_update(type, SHIP(shipnum)(&cc->ship[shipnum]), astr, a, b, c, d) < 0)
17
Passing null pointer value via 3rd parameter 'astr'
18
Calling 'sync_update'
275 goto bad;
276 }
277bad:
278 erred++;
279out:
280 if (!erred && sync_bp != sync_buf) {
281 (void) fseek(sync_fp, 0L, SEEK_END2);
282 (void) fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf,
283 sync_fp);
284 (void) fflush(sync_fp);
285 sync_bp = sync_buf;
286 }
287 sync_seek = ftell(sync_fp);
288#ifdef LOCK_EX
289 (void) flock(fileno(sync_fp)(!__isthreaded ? ((sync_fp)->_file) : (fileno)(sync_fp)), LOCK_UN);
290#else
291 setegid(egid);
292 (void) unlink(sync_lock);
293 setegid(gid);
294#endif
295 (void) signal(SIGHUP1, sighup);
296 (void) signal(SIGINT2, sigint);
297 return erred ? -1 : 0;
298}
299
300int
301sync_update(int type, struct ship *ship, const char *astr, long a, long b,
302 long c, long d)
303{
304 switch (type) {
19
Control jumps to 'case 1:' at line 378
305 case W_DBP5: {
306 struct BP *p = &ship->file->DBP[a];
307 p->turnsent = b;
308 p->toship = SHIP(c)(&cc->ship[c]);
309 p->mensent = d;
310 break;
311 }
312 case W_OBP14: {
313 struct BP *p = &ship->file->OBP[a];
314 p->turnsent = b;
315 p->toship = SHIP(c)(&cc->ship[c]);
316 p->mensent = d;
317 break;
318 }
319 case W_FOUL9: {
320 struct snag *p = &ship->file->foul[a];
321 if (SHIP(a)(&cc->ship[a])->file->dir == 0)
322 break;
323 if (p->sn_count++ == 0)
324 p->sn_turn = turn;
325 ship->file->nfoul++;
326 break;
327 }
328 case W_GRAP32: {
329 struct snag *p = &ship->file->grap[a];
330 if (SHIP(a)(&cc->ship[a])->file->dir == 0)
331 break;
332 if (p->sn_count++ == 0)
333 p->sn_turn = turn;
334 ship->file->ngrap++;
335 break;
336 }
337 case W_UNFOUL16: {
338 struct snag *p = &ship->file->foul[a];
339 if (p->sn_count > 0) {
340 if (b) {
341 ship->file->nfoul -= p->sn_count;
342 p->sn_count = 0;
343 } else {
344 ship->file->nfoul--;
345 p->sn_count--;
346 }
347 }
348 break;
349 }
350 case W_UNGRAP19: {
351 struct snag *p = &ship->file->grap[a];
352 if (p->sn_count > 0) {
353 if (b) {
354 ship->file->ngrap -= p->sn_count;
355 p->sn_count = 0;
356 } else {
357 ship->file->ngrap--;
358 p->sn_count--;
359 }
360 }
361 break;
362 }
363 case W_SIGNAL24:
364 if (mode == MODE_PLAYER1) {
365 if (nobells)
366 Signal("$$: %s", ship, astr);
367 else
368 Signal("\7$$: %s", ship, astr);
369 }
370 break;
371 case W_CREW4: {
372 struct shipspecs *s = ship->specs;
373 s->crew1 = a;
374 s->crew2 = b;
375 s->crew3 = c;
376 break;
377 }
378 case W_CAPTAIN1:
379 (void) strlcpy(ship->file->captain, astr,
20
Null pointer passed as 2nd argument to string copy function
380 sizeof ship->file->captain);
381 break;
382 case W_CAPTURED2:
383 if (a < 0)
384 ship->file->captured = 0;
385 else
386 ship->file->captured = SHIP(a)(&cc->ship[a]);
387 break;
388 case W_CLASS3:
389 ship->specs->class = a;
390 break;
391 case W_DRIFT6:
392 ship->file->drift = a;
393 break;
394 case W_EXPLODE7:
395 if ((ship->file->explode = a) == 2)
396 ship->file->dir = 0;
397 break;
398 case W_FS31:
399 ship->file->FS = a;
400 break;
401 case W_GUNL10: {
402 struct shipspecs *s = ship->specs;
403 s->gunL = a;
404 s->carL = b;
405 break;
406 }
407 case W_GUNR11: {
408 struct shipspecs *s = ship->specs;
409 s->gunR = a;
410 s->carR = b;
411 break;
412 }
413 case W_HULL12:
414 ship->specs->hull = a;
415 break;
416 case W_MOVE13:
417 (void) strlcpy(ship->file->movebuf, astr,
418 sizeof ship->file->movebuf);
419 break;
420 case W_PCREW15:
421 ship->file->pcrew = a;
422 break;
423 case W_POINTS17:
424 ship->file->points = a;
425 break;
426 case W_QUAL18:
427 ship->specs->qual = a;
428 break;
429 case W_RIGG20: {
430 struct shipspecs *s = ship->specs;
431 s->rig1 = a;
432 s->rig2 = b;
433 s->rig3 = c;
434 s->rig4 = d;
435 break;
436 }
437 case W_RIG133:
438 ship->specs->rig1 = a;
439 break;
440 case W_RIG234:
441 ship->specs->rig2 = a;
442 break;
443 case W_RIG335:
444 ship->specs->rig3 = a;
445 break;
446 case W_RIG436:
447 ship->specs->rig4 = a;
448 break;
449 case W_COL21:
450 ship->file->col = a;
451 break;
452 case W_DIR22:
453 ship->file->dir = a;
454 break;
455 case W_ROW23:
456 ship->file->row = a;
457 break;
458 case W_SINK25:
459 if ((ship->file->sink = a) == 2)
460 ship->file->dir = 0;
461 break;
462 case W_STRUCK26:
463 ship->file->struck = a;
464 break;
465 case W_TA27:
466 ship->specs->ta = a;
467 break;
468 case W_ALIVE28:
469 alive = 1;
470 break;
471 case W_TURN29:
472 turn = a;
473 break;
474 case W_WIND30:
475 winddir = a;
476 windspeed = b;
477 break;
478 case W_BEGIN37:
479 (void) strlcpy(ship->file->captain, "begin",
480 sizeof ship->file->captain);
481 people++;
482 break;
483 case W_END38:
484 *ship->file->captain = 0;
485 ship->file->points = 0;
486 people--;
487 break;
488 case W_DDEAD39:
489 hasdriver = 0;
490 break;
491 default:
492 fprintf(stderr(&__sF[2]), "sync_update: unknown type %d\r\n", type);
493 return -1;
494 }
495 return 0;
496}