Bug Summary

File:src/games/hunt/hunt/playit.c
Warning:line 113, column 9
Although the value stored to 'ch' is used in the enclosing expression, the value is never actually read from 'ch'

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 playit.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/hunt/hunt/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/games/hunt/hunt/../huntd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/games/hunt/hunt/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/hunt/hunt/playit.c
1/* $OpenBSD: playit.c,v 1.13 2016/08/27 02:06:40 guenther Exp $ */
2/* $NetBSD: playit.c,v 1.4 1997/10/20 00:37:15 lukem Exp $ */
3/*
4 * Copyright (c) 1983-2003, Regents of the University of California.
5 * 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 are
9 * met:
10 *
11 * + Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * + 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 * + Neither the name of the University of California, San Francisco nor
17 * the names of its contributors may be used to endorse or promote
18 * products derived from this software without specific prior written
19 * permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <sys/select.h>
35#include <ctype.h>
36#include <err.h>
37#include <errno(*__errno()).h>
38#include <stdio.h>
39#include <string.h>
40#include <termios.h>
41#include <unistd.h>
42
43#include "display.h"
44#include "hunt.h"
45#include "client.h"
46
47static int nchar_send;
48static FLAG Last_player;
49static int Otto_expect;
50
51# define MAX_SEND5 5
52
53/*
54 * ibuf is the input buffer used for the stream from the driver.
55 * It is small because we do not check for user input when there
56 * are characters in the input buffer.
57 */
58static int icnt = 0;
59static unsigned char ibuf[256], *iptr = ibuf;
60
61#define GETCHR()(--icnt < 0 ? getchr() : *iptr++) (--icnt < 0 ? getchr() : *iptr++)
62
63static unsigned char getchr(void);
64static void send_stuff(void);
65
66/*
67 * playit:
68 * Play a given game, handling all the curses commands from
69 * the driver.
70 */
71void
72playit(void)
73{
74 int ch;
75 int y, x;
76 u_int32_t version;
77 int otto_y, otto_x;
78 char otto_face = ' ';
79 int chars_processed;
80
81 if (read(Socket, &version, sizeof version) != sizeof version) {
82 bad_con();
83 }
84 if (ntohl(version)(__uint32_t)(__builtin_constant_p(version) ? (__uint32_t)(((__uint32_t
)(version) & 0xff) << 24 | ((__uint32_t)(version) &
0xff00) << 8 | ((__uint32_t)(version) & 0xff0000) >>
8 | ((__uint32_t)(version) & 0xff000000) >> 24) : __swap32md
(version))
!= HUNT_VERSION(-1)) {
85 bad_ver();
86 }
87 errno(*__errno()) = 0;
88 nchar_send = MAX_SEND5;
89 Otto_expect = 0;
90 while ((ch = GETCHR()(--icnt < 0 ? getchr() : *iptr++)) != EOF(-1)) {
91 switch (ch & 0377) {
92 case MOVE('m' | 0200):
93 y = GETCHR()(--icnt < 0 ? getchr() : *iptr++);
94 x = GETCHR()(--icnt < 0 ? getchr() : *iptr++);
95 display_move(y, x);
96 break;
97
98 case CLRTOEOL('c' | 0200):
99 display_clear_eol();
100 break;
101 case CLEAR('C' | 0200):
102 display_clear_the_screen();
103 break;
104 case REFRESH('r' | 0200):
105 display_refresh();
106 break;
107 case REDRAW('R' | 0200):
108 display_redraw_screen();
109 display_refresh();
110 break;
111 case ENDWIN('e' | 0200):
112 display_refresh();
113 if ((ch = GETCHR()(--icnt < 0 ? getchr() : *iptr++)) == LAST_PLAYER('l' | 0200))
Although the value stored to 'ch' is used in the enclosing expression, the value is never actually read from 'ch'
114 Last_player = TRUE1;
115 ch = EOF(-1);
116 goto out;
117 case BELL('b' | 0200):
118 display_beep();
119 break;
120 case READY('g' | 0200):
121 chars_processed = GETCHR()(--icnt < 0 ? getchr() : *iptr++);
122 display_refresh();
123 if (nchar_send < 0)
124 tcflush(STDIN_FILENO0, TCIFLUSH1);
125 nchar_send = MAX_SEND5;
126 if (Otto_mode) {
127 /*
128 * The driver returns the number of keypresses
129 * that it has processed. Use this to figure
130 * out if otto's commands have completed.
131 */
132 Otto_expect -= chars_processed;
133 if (Otto_expect == 0) {
134 /* not very fair! */
135 static char buf[MAX_SEND5 * 2];
136 int len;
137
138 /* Ask otto what it wants to do: */
139 len = otto(otto_y, otto_x, otto_face,
140 buf, sizeof buf);
141 if (len) {
142 /* Pass it on to the driver: */
143 write(Socket, buf, len);
144 /* Update expectations: */
145 Otto_expect += len;
146 }
147 }
148 }
149 break;
150 case ADDCH('a' | 0200):
151 ch = GETCHR()(--icnt < 0 ? getchr() : *iptr++);
152 /* FALLTHROUGH */
153 default:
154 if (!isprint(ch))
155 ch = ' ';
156 display_put_ch(ch);
157 if (Otto_mode)
158 switch (ch) {
159 case '<':
160 case '>':
161 case '^':
162 case 'v':
163 otto_face = ch;
164 display_getyx(&otto_y, &otto_x);
165 otto_x--;
166 break;
167 }
168 break;
169 }
170 }
171out:
172 (void) close(Socket);
173}
174
175/*
176 * getchr:
177 * Grab input and pass it along to the driver
178 * Return any characters from the driver
179 * When this routine is called by GETCHR, we already know there are
180 * no characters in the input buffer.
181 */
182static unsigned char
183getchr(void)
184{
185 fd_set readfds, s_readfds;
186 int nfds, s_nfds;
187
188 FD_ZERO(&s_readfds)do { fd_set *_p = (&s_readfds); __size_t _n = (((1024) + (
(((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)(sizeof
(__fd_mask) * 8)))); while (_n > 0) _p->fds_bits[--_n] =
0; } while (0)
;
189 FD_SET(Socket, &s_readfds)__fd_set((Socket), (&s_readfds));
190 FD_SET(STDIN_FILENO, &s_readfds)__fd_set((0), (&s_readfds));
191 s_nfds = (Socket > STDIN_FILENO0) ? Socket : STDIN_FILENO0;
192 s_nfds++;
193
194one_more_time:
195 do {
196 errno(*__errno()) = 0;
197 readfds = s_readfds;
198 nfds = s_nfds;
199 nfds = select(nfds, &readfds, NULL((void *)0), NULL((void *)0), NULL((void *)0));
200 } while (nfds <= 0 && errno(*__errno()) == EINTR4);
201
202 if (FD_ISSET(STDIN_FILENO, &readfds)__fd_isset((0), (&readfds)))
203 send_stuff();
204 if (!FD_ISSET(Socket, &readfds)__fd_isset((Socket), (&readfds)))
205 goto one_more_time;
206 icnt = read(Socket, ibuf, sizeof ibuf);
207 if (icnt <= 0) {
208 bad_con();
209 }
210 iptr = ibuf;
211 icnt--;
212 return *iptr++;
213}
214
215/*
216 * send_stuff:
217 * Send standard input characters to the driver
218 */
219static void
220send_stuff(void)
221{
222 int count;
223 char *sp, *nsp;
224 static char inp[BUFSIZ1024];
225 static char Buf[BUFSIZ1024];
226
227 /* Drain the user's keystrokes: */
228 count = read(STDIN_FILENO0, Buf, sizeof Buf);
229 if (count < 0)
230 err(1, "read");
231 if (count == 0)
232 return;
233
234 if (nchar_send <= 0 && !no_beep) {
235 display_beep();
236 return;
237 }
238
239 /*
240 * look for 'q'uit commands; if we find one,
241 * confirm it. If it is not confirmed, strip
242 * it out of the input
243 */
244 Buf[count] = '\0';
245 for (sp = Buf, nsp = inp; *sp != '\0'; sp++, nsp++) {
246 *nsp = map_key[(int)*sp];
247 if (*nsp == 'q')
248 intr(0);
249 }
250 count = nsp - inp;
251 if (count) {
252 nchar_send -= count;
253 if (nchar_send < 0)
254 count += nchar_send;
255 (void) write(Socket, inp, count);
256 if (Otto_mode) {
257 /*
258 * The user can insert commands over otto.
259 * So, otto shouldn't be alarmed when the
260 * server processes more than otto asks for.
261 */
262 Otto_expect += count;
263 }
264 }
265}
266
267/*
268 * quit:
269 * Handle the end of the game when the player dies
270 */
271int
272quit(int old_status)
273{
274 int explain, ch;
275
276 if (Last_player)
277 return Q_QUIT0;
278 if (Otto_mode)
279 return otto_quit(old_status);
280 display_move(HEIGHT23, 0);
281 display_put_str("Re-enter game [ynwo]? ");
282 display_clear_eol();
283 explain = FALSE0;
284 for (;;) {
285 display_refresh();
286 if (isupper(ch = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
))
287 ch = tolower(ch);
288 if (ch == 'y')
289 return old_status;
290 else if (ch == 'o')
291 break;
292 else if (ch == 'n') {
293 display_move(HEIGHT23, 0);
294 display_put_str("Write a parting message [yn]? ");
295 display_clear_eol();
296 display_refresh();
297 for (;;) {
298 if (isupper(ch = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
))
299 ch = tolower(ch);
300 if (ch == 'y')
301 goto get_message;
302 if (ch == 'n')
303 return Q_QUIT0;
304 }
305 }
306 else if (ch == 'w') {
307 static char buf[WIDTH51 + WIDTH51 % 2];
308 char *cp, c;
309
310get_message:
311 c = ch; /* save how we got here */
312 display_move(HEIGHT23, 0);
313 display_put_str("Message: ");
314 display_clear_eol();
315 display_refresh();
316 cp = buf;
317 for (;;) {
318 display_refresh();
319 if ((ch = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
) == '\n' || ch == '\r')
320 break;
321 if (display_iserasechar(ch))
322 {
323 if (cp > buf) {
324 int y, x;
325
326 display_getyx(&y, &x);
327 display_move(y, x - 1);
328 cp -= 1;
329 display_clear_eol();
330 }
331 continue;
332 }
333 else if (display_iskillchar(ch))
334 {
335 int y, x;
336
337 display_getyx(&y, &x);
338 display_move(y, x - (cp - buf));
339 cp = buf;
340 display_clear_eol();
341 continue;
342 } else if (!isprint(ch)) {
343 display_beep();
344 continue;
345 }
346 display_put_ch(ch);
347 *cp++ = ch;
348 if (cp + 1 >= buf + sizeof buf)
349 break;
350 }
351 *cp = '\0';
352 Send_message = buf;
353 return (c == 'w') ? old_status : Q_MESSAGE4;
354 }
355 display_beep();
356 if (!explain) {
357 display_put_str("(Yes, No, Write message, or Options) ");
358 explain = TRUE1;
359 }
360 }
361
362 display_move(HEIGHT23, 0);
363 display_put_str("Scan, Cloak, Flying, or Quit? ");
364 display_clear_eol();
365 display_refresh();
366 explain = FALSE0;
367 for (;;) {
368 if (isupper(ch = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
))
369 ch = tolower(ch);
370 if (ch == 's')
371 return Q_SCAN3;
372 else if (ch == 'c')
373 return Q_CLOAK1;
374 else if (ch == 'f')
375 return Q_FLY2;
376 else if (ch == 'q')
377 return Q_QUIT0;
378 display_beep();
379 if (!explain) {
380 display_put_str("[SCFQ] ");
381 explain = TRUE1;
382 }
383 display_refresh();
384 }
385}
386
387/*
388 * do_message:
389 * Send a message to the driver and return
390 */
391void
392do_message(void)
393{
394 u_int32_t version;
395
396 if (read(Socket, &version, sizeof version) != sizeof version) {
397 bad_con();
398 }
399 if (ntohl(version)(__uint32_t)(__builtin_constant_p(version) ? (__uint32_t)(((__uint32_t
)(version) & 0xff) << 24 | ((__uint32_t)(version) &
0xff00) << 8 | ((__uint32_t)(version) & 0xff0000) >>
8 | ((__uint32_t)(version) & 0xff000000) >> 24) : __swap32md
(version))
!= HUNT_VERSION(-1)) {
400 bad_ver();
401 }
402 if (write(Socket, Send_message, strlen(Send_message)) < 0) {
403 bad_con();
404 }
405 (void) close(Socket);
406}