Bug Summary

File:src/bin/ed/glbl.c
Warning:line 178, column 31
Access to field 'q_forw' results in a dereference of a null pointer (loaded from variable 'lp')

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 glbl.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/bin/ed/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/bin/ed/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/bin/ed/glbl.c
1/* $OpenBSD: glbl.c,v 1.20 2018/06/04 13:26:21 martijn Exp $ */
2/* $NetBSD: glbl.c,v 1.2 1995/03/21 09:04:41 cgd Exp $ */
3
4/* glob.c: This file contains the global command routines for the ed line
5 editor */
6/*-
7 * Copyright (c) 1993 Andrew Moore, Talke Studio.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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#include <sys/ioctl.h>
33#include <sys/wait.h>
34
35#include <regex.h>
36#include <signal.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41#include "ed.h"
42
43static int set_active_node(line_t *);
44static line_t *next_active_node(void);
45
46/* build_active_list: add line matching a pattern to the global-active list */
47int
48build_active_list(int isgcmd)
49{
50 regex_t *pat;
51 line_t *lp;
52 int n;
53 char *s;
54 char delimiter;
55
56 if ((delimiter = *ibufp) == ' ' || delimiter == '\n') {
57 seterrmsg("invalid pattern delimiter");
58 return ERR(-2);
59 } else if ((pat = get_compiled_pattern()) == NULL((void *)0))
60 return ERR(-2);
61 else if (*ibufp == delimiter)
62 ibufp++;
63 clear_active_list();
64 lp = get_addressed_line_node(first_addr);
65 for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw) {
66 if ((s = get_sbuf_line(lp)) == NULL((void *)0))
67 return ERR(-2);
68 if (isbinary)
69 NUL_TO_NEWLINE(s, lp->len)translit_text(s, lp->len, '\0', '\n');
70 if ((!regexec(pat, s, 0, NULL((void *)0), 0)) == isgcmd &&
71 set_active_node(lp) < 0)
72 return ERR(-2);
73 }
74 return 0;
75}
76
77
78/* exec_global: apply command list in the command buffer to the active
79 lines in a range; return command status */
80int
81exec_global(int interact, int gflag)
82{
83 static char *ocmd = NULL((void *)0);
84 static int ocmdsz = 0;
85
86 line_t *lp = NULL((void *)0);
87 int status;
88 int n;
89 char *cmd = NULL((void *)0);
90
91 if (!interact) {
92 if (!strcmp(ibufp, "\n"))
93 cmd = "p\n"; /* null cmd-list == `p' */
94 else if ((cmd = get_extended_line(&n, 0)) == NULL((void *)0))
95 return ERR(-2);
96 }
97 clear_undo_stack();
98 while ((lp = next_active_node()) != NULL((void *)0)) {
99 if ((current_addr = get_line_node_addr(lp)) < 0)
100 return ERR(-2);
101 if (interact) {
102 /* print current_addr; get a command in global syntax */
103 if (display_lines(current_addr, current_addr, gflag) < 0)
104 return ERR(-2);
105 while ((n = get_tty_line()) > 0 &&
106 ibuf[n - 1] != '\n')
107 clearerr(stdin)(!__isthreaded ? ((void)(((&__sF[0]))->_flags &= ~
(0x0040|0x0020))) : (clearerr)((&__sF[0])))
;
108 if (n < 0)
109 return ERR(-2);
110 else if (n == 0) {
111 seterrmsg("unexpected end-of-file");
112 return ERR(-2);
113 } else if (n == 1 && !strcmp(ibuf, "\n"))
114 continue;
115 else if (n == 2 && !strcmp(ibuf, "&\n")) {
116 if (cmd == NULL((void *)0)) {
117 seterrmsg("no previous command");
118 return ERR(-2);
119 } else cmd = ocmd;
120 } else if ((cmd = get_extended_line(&n, 0)) == NULL((void *)0))
121 return ERR(-2);
122 else {
123 REALLOC(ocmd, ocmdsz, n + 1, ERR)if ((n + 1) > (ocmdsz)) { int ti = (ocmdsz); char *ts; mutex
++; if ((ts = realloc((ocmd), ti += (((n + 1)) > (512) ? (
(n + 1)) : (512)))) == ((void *)0)) { perror(((void *)0)); seterrmsg
("out of memory"); do { if (--mutex == 0) { if (sighup) handle_hup
(1); if (sigint) handle_int(2); } } while (0); return (-2); }
(ocmdsz) = ti; (ocmd) = ts; do { if (--mutex == 0) { if (sighup
) handle_hup(1); if (sigint) handle_int(2); } } while (0); }
;
124 memcpy(ocmd, cmd, n + 1);
125 cmd = ocmd;
126 }
127
128 }
129 ibufp = cmd;
130 for (; *ibufp;)
131 if ((status = extract_addr_range()) < 0 ||
132 (status = exec_command()) < 0 ||
133 (status > 0 && (status = display_lines(
134 current_addr, current_addr, status)) < 0))
135 return status;
136 }
137 return 0;
138}
139
140
141static line_t **active_list; /* list of lines active in a global command */
142static int active_last; /* index of last active line in active_list */
143static int active_size; /* size of active_list */
144static int active_ptr; /* active_list index (non-decreasing) */
145static int active_ndx; /* active_list index (modulo active_last) */
146
147/* set_active_node: add a line node to the global-active list */
148static int
149set_active_node(line_t *lp)
150{
151 if (active_last + 1 > active_size) {
152 int ti = active_size;
153 line_t **ts;
154 SPL1()mutex++;
155 if ((ts = reallocarray(active_list,
156 (ti += MINBUFSZ512), sizeof(line_t **))) == NULL((void *)0)) {
157 perror(NULL((void *)0));
158 seterrmsg("out of memory");
159 SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint
) handle_int(2); } } while (0)
;
160 return ERR(-2);
161 }
162 active_size = ti;
163 active_list = ts;
164 SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint
) handle_int(2); } } while (0)
;
165 }
166 active_list[active_last++] = lp;
167 return 0;
168}
169
170
171/* unset_active_nodes: remove a range of lines from the global-active list */
172void
173unset_active_nodes(line_t *np, line_t *mp)
174{
175 line_t *lp;
176 int i;
177
178 for (lp = np; lp != mp; lp = lp->q_forw)
1
Assuming 'lp' is not equal to 'mp'
2
Loop condition is true. Entering loop body
10
Assuming 'lp' is not equal to 'mp'
11
Loop condition is true. Entering loop body
18
Value assigned to 'lp'
19
Assuming 'lp' is not equal to 'mp'
20
Loop condition is true. Entering loop body
26
Access to field 'q_forw' results in a dereference of a null pointer (loaded from variable 'lp')
179 for (i = 0; i
11.1
'i' is < 'active_last'
< active_last
; i++)
3
Assuming 'i' is < 'active_last'
4
Loop condition is true. Entering loop body
12
Loop condition is true. Entering loop body
21
Loop condition is true. Entering loop body
180 if (active_list[active_ndx] == lp) {
5
Assuming the condition is true
6
Taking true branch
13
Assuming the condition is true
14
Taking true branch
22
Assuming pointer value is null
23
Taking true branch
181 active_list[active_ndx] = NULL((void *)0);
182 active_ndx = INC_MOD(active_ndx, active_last - 1)((active_ndx) + 1 > (active_last - 1) ? 0 : (active_ndx) +
1)
;
7
Assuming the condition is true
8
'?' condition is true
15
Assuming the condition is true
16
'?' condition is true
24
'?' condition is true
183 break;
9
Execution continues on line 178
17
Execution continues on line 178
25
Execution continues on line 178
184 } else active_ndx = INC_MOD(active_ndx, active_last - 1)((active_ndx) + 1 > (active_last - 1) ? 0 : (active_ndx) +
1)
;
185}
186
187
188/* next_active_node: return the next global-active line node */
189static line_t *
190next_active_node(void)
191{
192 while (active_ptr < active_last && active_list[active_ptr] == NULL((void *)0))
193 active_ptr++;
194 return (active_ptr < active_last) ? active_list[active_ptr++] : NULL((void *)0);
195}
196
197
198/* clear_active_list: clear the global-active list */
199void
200clear_active_list(void)
201{
202 SPL1()mutex++;
203 active_size = active_last = active_ptr = active_ndx = 0;
204 free(active_list);
205 active_list = NULL((void *)0);
206 SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint
) handle_int(2); } } while (0)
;
207}