Bug Summary

File:src/usr.bin/mg/region.c
Warning:line 658, column 6
Although the value stored to 'q' is used in the enclosing expression, the value is never actually read from 'q'

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 region.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/mg/obj -resource-dir /usr/local/lib/clang/13.0.0 -D REGEX -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/mg/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/mg/region.c
1/* $OpenBSD: region.c,v 1.39 2021/03/01 10:51:14 lum Exp $ */
2
3/* This file is in the public domain. */
4
5/*
6 * Region based commands.
7 * The routines in this file deal with the region, that magic space between
8 * "." and mark. Some functions are commands. Some functions are just for
9 * internal use.
10 */
11
12#include <sys/queue.h>
13#include <sys/socket.h>
14#include <sys/types.h>
15#include <sys/wait.h>
16#include <errno(*__errno()).h>
17#include <fcntl.h>
18#include <poll.h>
19#include <signal.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24
25#include "def.h"
26
27#define TIMEOUT10000 10000
28
29static char leftover[BUFSIZ1024];
30
31static int getregion(struct region *);
32static int iomux(int, char * const, int, struct buffer *);
33static int preadin(int, struct buffer *);
34static void pwriteout(int, char **, int *);
35static int setsize(struct region *, RSIZE);
36static int shellcmdoutput(char * const[], char * const, int);
37
38/*
39 * Kill the region. Ask "getregion" to figure out the bounds of the region.
40 * Move "." to the start, and kill the characters. Mark is cleared afterwards.
41 */
42/* ARGSUSED */
43int
44killregion(int f, int n)
45{
46 int s;
47 struct region region;
48
49 if ((s = getregion(&region)) != TRUE1)
50 return (s);
51 /* This is a kill-type command, so do magic kill buffer stuff. */
52 if ((lastflag & CFKILL0x0002) == 0)
53 kdelete();
54 thisflag |= CFKILL0x0002;
55 curwp->w_dotp = region.r_linep;
56 curwp->w_doto = region.r_offset;
57 curwp->w_dotline = region.r_lineno;
58 s = ldelete(region.r_size, KFORW0x01 | KREG0x04);
59 clearmark(FFARG7, 0);
60
61 return (s);
62}
63
64/*
65 * Copy all of the characters in the region to the kill buffer,
66 * clearing the mark afterwards.
67 * This is a bit like a kill region followed by a yank.
68 */
69/* ARGSUSED */
70int
71copyregion(int f, int n)
72{
73 struct line *linep;
74 struct region region;
75 int loffs;
76 int s;
77
78 if ((s = getregion(&region)) != TRUE1)
79 return (s);
80
81 /* kill type command */
82 if ((lastflag & CFKILL0x0002) == 0)
83 kdelete();
84 thisflag |= CFKILL0x0002;
85
86 /* current line */
87 linep = region.r_linep;
88
89 /* current offset */
90 loffs = region.r_offset;
91
92 while (region.r_size--) {
93 if (loffs == llength(linep)((linep)->l_used)) { /* End of line. */
94 if ((s = kinsert(*curbp->b_nlchr, KFORW0x01)) != TRUE1)
95 return (s);
96 linep = lforw(linep)((linep)->l_fp);
97 loffs = 0;
98 } else { /* Middle of line. */
99 if ((s = kinsert(lgetc(linep, loffs)(((unsigned char) ((linep)->l_text[(loffs)]))), KFORW0x01)) != TRUE1)
100 return (s);
101 ++loffs;
102 }
103 }
104 clearmark(FFARG7, 0);
105
106 return (TRUE1);
107}
108
109/*
110 * Lower case region. Zap all of the upper case characters in the region to
111 * lower case. Use the region code to set the limits. Scan the buffer, doing
112 * the changes. Call "lchange" to ensure that redisplay is done in all
113 * buffers.
114 */
115/* ARGSUSED */
116int
117lowerregion(int f, int n)
118{
119 struct line *linep;
120 struct region region;
121 int loffs, c, s;
122
123 if ((s = checkdirty(curbp)) != TRUE1)
124 return (s);
125 if (curbp->b_flag & BFREADONLY0x10) {
126 dobeep();
127 ewprintf("Buffer is read-only");
128 return (FALSE0);
129 }
130
131 if ((s = getregion(&region)) != TRUE1)
132 return (s);
133
134 undo_add_change(region.r_linep, region.r_offset, region.r_size);
135
136 lchange(WFFULL0x08);
137 linep = region.r_linep;
138 loffs = region.r_offset;
139 while (region.r_size--) {
140 if (loffs == llength(linep)((linep)->l_used)) {
141 linep = lforw(linep)((linep)->l_fp);
142 loffs = 0;
143 } else {
144 c = lgetc(linep, loffs)(((unsigned char) ((linep)->l_text[(loffs)])));
145 if (ISUPPER(c)((cinfo[((unsigned char) (c))]&0x02)!=0) != FALSE0)
146 lputc(linep, loffs, TOLOWER(c))((linep)->l_text[(loffs)]=(((c)+0x20)));
147 ++loffs;
148 }
149 }
150 return (TRUE1);
151}
152
153/*
154 * Upper case region. Zap all of the lower case characters in the region to
155 * upper case. Use the region code to set the limits. Scan the buffer,
156 * doing the changes. Call "lchange" to ensure that redisplay is done in all
157 * buffers.
158 */
159/* ARGSUSED */
160int
161upperregion(int f, int n)
162{
163 struct line *linep;
164 struct region region;
165 int loffs, c, s;
166
167 if ((s = checkdirty(curbp)) != TRUE1)
168 return (s);
169 if (curbp->b_flag & BFREADONLY0x10) {
170 dobeep();
171 ewprintf("Buffer is read-only");
172 return (FALSE0);
173 }
174 if ((s = getregion(&region)) != TRUE1)
175 return (s);
176
177 undo_add_change(region.r_linep, region.r_offset, region.r_size);
178
179 lchange(WFFULL0x08);
180 linep = region.r_linep;
181 loffs = region.r_offset;
182 while (region.r_size--) {
183 if (loffs == llength(linep)((linep)->l_used)) {
184 linep = lforw(linep)((linep)->l_fp);
185 loffs = 0;
186 } else {
187 c = lgetc(linep, loffs)(((unsigned char) ((linep)->l_text[(loffs)])));
188 if (ISLOWER(c)((cinfo[((unsigned char) (c))]&0x04)!=0) != FALSE0)
189 lputc(linep, loffs, TOUPPER(c))((linep)->l_text[(loffs)]=(((c)-0x20)));
190 ++loffs;
191 }
192 }
193 return (TRUE1);
194}
195
196/*
197 * This routine figures out the bound of the region in the current window,
198 * and stores the results into the fields of the REGION structure. Dot and
199 * mark are usually close together, but I don't know the order, so I scan
200 * outward from dot, in both directions, looking for mark. The size is kept
201 * in a long. At the end, after the size is figured out, it is assigned to
202 * the size field of the region structure. If this assignment loses any bits,
203 * then we print an error. This is "type independent" overflow checking. All
204 * of the callers of this routine should be ready to get an ABORT status,
205 * because I might add a "if regions is big, ask before clobbering" flag.
206 */
207static int
208getregion(struct region *rp)
209{
210 struct line *flp, *blp;
211 long fsize, bsize;
212
213 if (curwp->w_markp == NULL((void *)0)) {
214 dobeep();
215 ewprintf("No mark set in this window");
216 return (FALSE0);
217 }
218
219 /* "r_size" always ok */
220 if (curwp->w_dotp == curwp->w_markp) {
221 rp->r_linep = curwp->w_dotp;
222 rp->r_lineno = curwp->w_dotline;
223 if (curwp->w_doto < curwp->w_marko) {
224 rp->r_offset = curwp->w_doto;
225 rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto);
226 } else {
227 rp->r_offset = curwp->w_marko;
228 rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko);
229 }
230 return (TRUE1);
231 }
232 /* get region size */
233 flp = blp = curwp->w_dotp;
234 bsize = curwp->w_doto;
235 fsize = llength(flp)((flp)->l_used) - curwp->w_doto + 1;
236 while (lforw(flp)((flp)->l_fp) != curbp->b_headp || lback(blp)((blp)->l_bp) != curbp->b_headp) {
237 if (lforw(flp)((flp)->l_fp) != curbp->b_headp) {
238 flp = lforw(flp)((flp)->l_fp);
239 if (flp == curwp->w_markp) {
240 rp->r_linep = curwp->w_dotp;
241 rp->r_offset = curwp->w_doto;
242 rp->r_lineno = curwp->w_dotline;
243 return (setsize(rp,
244 (RSIZE)(fsize + curwp->w_marko)));
245 }
246 fsize += llength(flp)((flp)->l_used) + 1;
247 }
248 if (lback(blp)((blp)->l_bp) != curbp->b_headp) {
249 blp = lback(blp)((blp)->l_bp);
250 bsize += llength(blp)((blp)->l_used) + 1;
251 if (blp == curwp->w_markp) {
252 rp->r_linep = blp;
253 rp->r_offset = curwp->w_marko;
254 rp->r_lineno = curwp->w_markline;
255 return (setsize(rp,
256 (RSIZE)(bsize - curwp->w_marko)));
257 }
258 }
259 }
260 dobeep();
261 ewprintf("Bug: lost mark");
262 return (FALSE0);
263}
264
265/*
266 * Set size, and check for overflow.
267 */
268static int
269setsize(struct region *rp, RSIZE size)
270{
271 rp->r_size = size;
272 if (rp->r_size != size) {
273 dobeep();
274 ewprintf("Region is too large");
275 return (FALSE0);
276 }
277 return (TRUE1);
278}
279
280#define PREFIXLENGTH40 40
281static char prefix_string[PREFIXLENGTH40] = {'>', '\0'};
282
283/*
284 * Prefix the region with whatever is in prefix_string. Leaves dot at the
285 * beginning of the line after the end of the region. If an argument is
286 * given, prompts for the line prefix string.
287 */
288/* ARGSUSED */
289int
290prefixregion(int f, int n)
291{
292 struct line *first, *last;
293 struct region region;
294 char *prefix = prefix_string;
295 int nline;
296 int s;
297
298 if ((s = checkdirty(curbp)) != TRUE1)
299 return (s);
300 if (curbp->b_flag & BFREADONLY0x10) {
301 dobeep();
302 ewprintf("Buffer is read-only");
303 return (FALSE0);
304 }
305 if ((f == TRUE1) && ((s = setprefix(FFRAND8, 1)) != TRUE1))
306 return (s);
307
308 /* get # of lines to affect */
309 if ((s = getregion(&region)) != TRUE1)
310 return (s);
311 first = region.r_linep;
312 last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
313 for (nline = 1; first != last; nline++)
314 first = lforw(first)((first)->l_fp);
315
316 /* move to beginning of region */
317 curwp->w_dotp = region.r_linep;
318 curwp->w_doto = region.r_offset;
319 curwp->w_dotline = region.r_lineno;
320
321 /* for each line, go to beginning and insert the prefix string */
322 while (nline--) {
323 (void)gotobol(FFRAND8, 1);
324 for (prefix = prefix_string; *prefix; prefix++)
325 (void)linsert(1, *prefix);
326 (void)forwline(FFRAND8, 1);
327 }
328 (void)gotobol(FFRAND8, 1);
329 return (TRUE1);
330}
331
332/*
333 * Set line prefix string. Used by prefixregion.
334 */
335/* ARGSUSED */
336int
337setprefix(int f, int n)
338{
339 char buf[PREFIXLENGTH40], *rep;
340 int retval;
341
342 if (prefix_string[0] == '\0')
343 rep = eread("Prefix string: ", buf, sizeof(buf),
344 EFNEW0x0008 | EFCR0x0010);
345 else
346 rep = eread("Prefix string (default %s): ", buf, sizeof(buf),
347 EFNUL0x0040 | EFNEW0x0008 | EFCR0x0010, prefix_string);
348 if (rep == NULL((void *)0))
349 return (ABORT2);
350 if (rep[0] != '\0') {
351 (void)strlcpy(prefix_string, rep, sizeof(prefix_string));
352 retval = TRUE1;
353 } else if (rep[0] == '\0' && prefix_string[0] != '\0') {
354 /* CR -- use old one */
355 retval = TRUE1;
356 } else
357 retval = FALSE0;
358 return (retval);
359}
360
361int
362region_get_data(struct region *reg, char *buf, int len)
363{
364 int i, off;
365 struct line *lp;
366
367 off = reg->r_offset;
368 lp = reg->r_linep;
369 for (i = 0; i < len; i++) {
370 if (off == llength(lp)((lp)->l_used)) {
371 lp = lforw(lp)((lp)->l_fp);
372 if (lp == curbp->b_headp)
373 break;
374 off = 0;
375 buf[i] = *curbp->b_nlchr;
376 } else {
377 buf[i] = lgetc(lp, off)(((unsigned char) ((lp)->l_text[(off)])));
378 off++;
379 }
380 }
381 buf[i] = '\0';
382 return (i);
383}
384
385void
386region_put_data(const char *buf, int len)
387{
388 int i;
389
390 for (i = 0; buf[i] != '\0' && i < len; i++) {
391 if (buf[i] == *curbp->b_nlchr)
392 lnewline();
393 else
394 linsert(1, buf[i]);
395 }
396}
397
398/*
399 * Mark whole buffer by first traversing to end-of-buffer
400 * and then to beginning-of-buffer. Mark, dot are implicitly
401 * set to eob, bob respectively during traversal.
402 */
403int
404markbuffer(int f, int n)
405{
406 if (gotoeob(f,n) == FALSE0)
407 return (FALSE0);
408 (void) clearmark(f, n);
409 if (gotobob(f,n) == FALSE0)
410 return (FALSE0);
411 return (TRUE1);
412}
413
414/*
415 * Pipe text from current region to external command.
416 */
417/*ARGSUSED */
418int
419piperegion(int f, int n)
420{
421 struct region region;
422 int len;
423 char *cmd, cmdbuf[NFILEN1024], *text;
424 char *argv[] = {"sh", "-c", (char *) NULL((void *)0), (char *) NULL((void *)0)};
425
426 /* C-u M-| is not supported yet */
427 if (n > 1)
428 return (ABORT2);
429
430 if (curwp->w_markp == NULL((void *)0)) {
431 dobeep();
432 ewprintf("The mark is not set now, so there is no region");
433 return (FALSE0);
434 }
435
436 if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf),
437 EFNEW0x0008 | EFCR0x0010)) == NULL((void *)0) || (cmd[0] == '\0'))
438 return (ABORT2);
439
440 argv[2] = cmd;
441
442 if (getregion(&region) != TRUE1)
443 return (FALSE0);
444
445 len = region.r_size;
446
447 if ((text = malloc(len + 1)) == NULL((void *)0)) {
448 dobeep();
449 ewprintf("Cannot allocate memory.");
450 return (FALSE0);
451 }
452
453 region_get_data(&region, text, len);
454
455 return shellcmdoutput(argv, text, len);
456}
457
458/*
459 * Get command from mini-buffer and execute externally.
460 */
461/*ARGSUSED */
462int
463shellcommand(int f, int n)
464{
465
466 char *cmd, cmdbuf[NFILEN1024];
467 char *argv[] = {"sh", "-c", (char *) NULL((void *)0), (char *) NULL((void *)0)};
468
469 if (n > 1)
470 return (ABORT2);
471
472 if ((cmd = eread("Shell command: ", cmdbuf, sizeof(cmdbuf),
473 EFNEW0x0008 | EFCR0x0010)) == NULL((void *)0) || (cmd[0] == '\0'))
474 return (ABORT2);
475
476 argv[2] = cmd;
477
478 return shellcmdoutput(argv, NULL((void *)0), 0);
479}
480
481
482int
483shellcmdoutput(char* const argv[], char* const text, int len)
484{
485
486 struct buffer *bp;
487 char *shellp;
488 int ret;
489
490 bp = bfind("*Shell Command Output*", TRUE1);
491 bp->b_flag |= BFREADONLY0x10;
492 if (bclear(bp) != TRUE1) {
493 free(text);
494 return (FALSE0);
495 }
496
497 shellp = getenv("SHELL");
498
499 ret = pipeio(shellp, argv, text, len, bp);
500
501 if (ret == TRUE1) {
502 eerase();
503 if (lforw(bp->b_headp)((bp->b_headp)->l_fp) == bp->b_headp)
504 addline(bp, "(Shell command succeeded with no output)")addlinef(bp, "%s", "(Shell command succeeded with no output)"
)
;
505 }
506
507 free(text);
508 return (ret);
509}
510
511/*
512 * Create a socketpair, fork and execv path with argv.
513 * STDIN, STDOUT and STDERR of child process are redirected to socket.
514 * Parent writes len chars from text to socket.
515 */
516int
517pipeio(const char* const path, char* const argv[], char* const text, int len,
518 struct buffer *outbp)
519{
520 int s[2], ret;
521 char *err;
522 pid_t pid;
523
524 if (socketpair(AF_UNIX1, SOCK_STREAM1, PF_UNSPEC0, s) == -1) {
525 dobeep();
526 ewprintf("socketpair error");
527 return (FALSE0);
528 }
529
530 switch((pid = fork())) {
531 case -1:
532 dobeep();
533 ewprintf("Can't fork");
534 return (FALSE0);
535 case 0:
536 /* Child process */
537 close(s[0]);
538 if (dup2(s[1], STDIN_FILENO0) == -1)
539 _exit(1);
540 if (dup2(s[1], STDOUT_FILENO1) == -1)
541 _exit(1);
542 if (dup2(s[1], STDERR_FILENO2) == -1)
543 _exit(1);
544 if (path == NULL((void *)0))
545 _exit(1);
546
547 execv(path, argv);
548 err = strerror(errno(*__errno()));
549 write(s[1], err, strlen(err));
550 _exit(1);
551 default:
552 /* Parent process */
553 close(s[1]);
554 ret = iomux(s[0], text, len, outbp);
555 waitpid(pid, NULL((void *)0), 0); /* Collect child to prevent zombies */
556
557 return (ret);
558 }
559 return (FALSE0);
560}
561
562/*
563 * Multiplex read, write on socket fd passed. Put output in outbp
564 * Poll on the fd for both read and write readiness.
565 */
566int
567iomux(int fd, char* const text, int len, struct buffer *outbp)
568{
569 struct pollfd pfd[1];
570 int nfds;
571 char *textcopy;
572
573 textcopy = text;
574 fcntl(fd, F_SETFL4, O_NONBLOCK0x0004);
575 pfd[0].fd = fd;
576
577 /* There is nothing to write if len is zero
578 * but the cmd's output should be read so shutdown
579 * the socket for writing only and don't wait for POLLOUT
580 */
581 if (len == 0) {
582 shutdown(fd, SHUT_WR1);
583 pfd[0].events = POLLIN0x0001;
584 } else
585 pfd[0].events = POLLIN0x0001 | POLLOUT0x0004;
586
587 while ((nfds = poll(pfd, 1, TIMEOUT10000)) != -1 ||
588 (pfd[0].revents & (POLLERR0x0008 | POLLHUP0x0010 | POLLNVAL0x0020))) {
589 if (pfd[0].revents & POLLOUT0x0004 && len > 0)
590 pwriteout(fd, &textcopy, &len);
591 else if (pfd[0].revents & POLLIN0x0001)
592 if (preadin(fd, outbp) == FALSE0)
593 break;
594 if (len == 0 && pfd[0].events & POLLOUT0x0004)
595 pfd[0].events = POLLIN0x0001;
596 }
597 close(fd);
598
599 /* In case if last line doesn't have a '\n' add the leftover
600 * characters to buffer.
601 */
602 if (leftover[0] != '\0') {
603 addline(outbp, leftover)addlinef(outbp, "%s", leftover);
604 leftover[0] = '\0';
605 }
606 if (nfds == 0) {
607 dobeep();
608 ewprintf("poll timed out");
609 return (FALSE0);
610 } else if (nfds == -1) {
611 dobeep();
612 ewprintf("poll error");
613 return (FALSE0);
614 }
615 return (popbuftop(outbp, WNONE0x00));
616}
617
618/*
619 * Write some text from region to fd. Once done shutdown the
620 * write end.
621 */
622void
623pwriteout(int fd, char **text, int *len)
624{
625 int w;
626
627 if (((w = send(fd, *text, *len, MSG_NOSIGNAL0x400)) == -1)) {
628 switch(errno(*__errno())) {
629 case EPIPE32:
630 *len = -1;
631 break;
632 case EAGAIN35:
633 return;
634 }
635 } else
636 *len -= w;
637
638 *text += w;
639 if (*len <= 0)
640 shutdown(fd, SHUT_WR1);
641}
642
643/*
644 * Read some data from socket fd, break on '\n' and add
645 * to buffer. If couldn't break on newline hold leftover
646 * characters and append in next iteration.
647 */
648int
649preadin(int fd, struct buffer *bp)
650{
651 int len;
652 char buf[BUFSIZ1024], *p, *q;
653
654 if ((len = read(fd, buf, BUFSIZ1024 - 1)) <= 0)
655 return (FALSE0);
656
657 buf[len] = '\0';
658 p = q = buf;
Although the value stored to 'q' is used in the enclosing expression, the value is never actually read from 'q'
659 if (leftover[0] != '\0' && ((q = strchr(p, *bp->b_nlchr)) != NULL((void *)0))) {
660 *q++ = '\0';
661 if (strlcat(leftover, p, sizeof(leftover)) >=
662 sizeof(leftover)) {
663 dobeep();
664 ewprintf("line too long");
665 return (FALSE0);
666 }
667 addline(bp, leftover)addlinef(bp, "%s", leftover);
668 leftover[0] = '\0';
669 p = q;
670 }
671 while ((q = strchr(p, *bp->b_nlchr)) != NULL((void *)0)) {
672 *q++ = '\0';
673 addline(bp, p)addlinef(bp, "%s", p);
674 p = q;
675 }
676 if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) {
677 dobeep();
678 ewprintf("line too long");
679 return (FALSE0);
680 }
681 return (TRUE1);
682}