Bug Summary

File:src/bin/ed/buf.c
Warning:line 80, column 13
Array access (from variable 'sfbuf') results in a null pointer dereference

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 buf.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/buf.c
1/* $OpenBSD: buf.c,v 1.24 2019/06/28 13:34:59 deraadt Exp $ */
2/* $NetBSD: buf.c,v 1.15 1995/04/23 10:07:28 cgd Exp $ */
3
4/* buf.c: This file contains the scratch-file buffer routines for the
5 ed line 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/types.h>
33#include <sys/stat.h>
34
35#include <limits.h>
36#include <regex.h>
37#include <signal.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <string.h>
41#include <unistd.h>
42
43#include "ed.h"
44
45
46static FILE *sfp; /* scratch file pointer */
47static off_t sfseek; /* scratch file position */
48static int seek_write; /* seek before writing */
49static line_t buffer_head; /* incore buffer */
50
51/* get_sbuf_line: get a line of text from the scratch file; return pointer
52 to the text */
53char *
54get_sbuf_line(line_t *lp)
55{
56 static char *sfbuf = NULL((void *)0); /* buffer */
1
'sfbuf' initialized to a null pointer value
57 static int sfbufsz = 0; /* buffer size */
58 int len;
59
60 if (lp == &buffer_head)
2
Assuming the condition is false
3
Taking false branch
61 return NULL((void *)0);
62 seek_write = 1; /* force seek on write */
63 /* out of position */
64 if (sfseek != lp->seek) {
4
Assuming 'sfseek' is equal to field 'seek'
5
Taking false branch
65 sfseek = lp->seek;
66 if (fseeko(sfp, sfseek, SEEK_SET0) == -1) {
67 perror(NULL((void *)0));
68 seterrmsg("cannot seek temp file");
69 return NULL((void *)0);
70 }
71 }
72 len = lp->len;
73 REALLOC(sfbuf, sfbufsz, len + 1, NULL)if ((len + 1) > (sfbufsz)) { int ti = (sfbufsz); char *ts;
mutex++; if ((ts = realloc((sfbuf), ti += (((len + 1)) > (
512) ? ((len + 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 ((void *)0); } (sfbufsz) = ti; (sfbuf) = ts; do {
if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint) handle_int
(2); } } while (0); }
;
6
Assuming the condition is false
7
Taking false branch
74 if (fread(sfbuf, sizeof(char), len, sfp) != len) {
8
Assuming the condition is false
9
Taking false branch
75 perror(NULL((void *)0));
76 seterrmsg("cannot read temp file");
77 return NULL((void *)0);
78 }
79 sfseek += len; /* update file position */
80 sfbuf[len] = '\0';
10
Array access (from variable 'sfbuf') results in a null pointer dereference
81 return sfbuf;
82}
83
84
85/* put_sbuf_line: write a line of text to the scratch file and add a line node
86 to the editor buffer; return a pointer to the end of the text */
87char *
88put_sbuf_line(char *cs)
89{
90 line_t *lp;
91 int len;
92 char *s;
93
94 if ((lp = malloc(sizeof(line_t))) == NULL((void *)0)) {
95 perror(NULL((void *)0));
96 seterrmsg("out of memory");
97 return NULL((void *)0);
98 }
99 /* assert: cs is '\n' terminated */
100 for (s = cs; *s != '\n'; s++)
101 ;
102 if (s - cs >= LINECHARS2147483647) {
103 seterrmsg("line too long");
104 free(lp);
105 return NULL((void *)0);
106 }
107 len = s - cs;
108 /* out of position */
109 if (seek_write) {
110 if (fseek(sfp, 0L, SEEK_END2) == -1) {
111 perror(NULL((void *)0));
112 seterrmsg("cannot seek temp file");
113 free(lp);
114 return NULL((void *)0);
115 }
116 sfseek = ftello(sfp);
117 seek_write = 0;
118 }
119 /* assert: SPL1() */
120 if (fwrite(cs, sizeof(char), len, sfp) != len) {
121 sfseek = -1;
122 perror(NULL((void *)0));
123 seterrmsg("cannot write temp file");
124 free(lp);
125 return NULL((void *)0);
126 }
127 lp->len = len;
128 lp->seek = sfseek;
129 add_line_node(lp);
130 sfseek += len; /* update file position */
131 return ++s;
132}
133
134
135/* add_line_node: add a line node in the editor buffer after the current line */
136void
137add_line_node(line_t *lp)
138{
139 line_t *cp;
140
141 /* this get_addressed_line_node last! */
142 cp = get_addressed_line_node(current_addr);
143 INSQUE(lp, cp){ ((lp))->q_forw = ((cp)->q_forw), ((cp)->q_forw)->
q_back = ((lp)); ((cp))->q_forw = (lp), (lp)->q_back = (
(cp)); }
;
144 addr_last++;
145 current_addr++;
146}
147
148
149/* get_line_node_addr: return line number of pointer */
150int
151get_line_node_addr(line_t *lp)
152{
153 line_t *cp = &buffer_head;
154 int n = 0;
155
156 while (cp != lp && (cp = cp->q_forw) != &buffer_head)
157 n++;
158 if (n && cp == &buffer_head) {
159 seterrmsg("invalid address");
160 return ERR(-2);
161 }
162 return n;
163}
164
165
166/* get_addressed_line_node: return pointer to a line node in the editor buffer */
167line_t *
168get_addressed_line_node(int n)
169{
170 static line_t *lp = &buffer_head;
171 static int on = 0;
172
173 SPL1()mutex++;
174 if (n > on) {
175 if (n <= (on + addr_last) >> 1)
176 for (; on < n; on++)
177 lp = lp->q_forw;
178 else {
179 lp = buffer_head.q_back;
180 for (on = addr_last; on > n; on--)
181 lp = lp->q_back;
182 }
183 } else {
184 if (n >= on >> 1)
185 for (; on > n; on--)
186 lp = lp->q_back;
187 else {
188 lp = &buffer_head;
189 for (on = 0; on < n; on++)
190 lp = lp->q_forw;
191 }
192 }
193 SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint
) handle_int(2); } } while (0)
;
194 return lp;
195}
196
197
198extern int newline_added;
199
200#define SCRATCH_TEMPLATE"/tmp/ed.XXXXXXXXXX" "/tmp/ed.XXXXXXXXXX"
201static char sfn[sizeof(SCRATCH_TEMPLATE"/tmp/ed.XXXXXXXXXX")+1] = ""; /* scratch file name */
202
203/* open_sbuf: open scratch file */
204int
205open_sbuf(void)
206{
207 int fd = -1;
208
209 isbinary = newline_added = 0;
210 strlcpy(sfn, SCRATCH_TEMPLATE"/tmp/ed.XXXXXXXXXX", sizeof sfn);
211 if ((fd = mkstemp(sfn)) == -1 ||
212 (sfp = fdopen(fd, "w+")) == NULL((void *)0)) {
213 if (fd != -1)
214 close(fd);
215 perror(sfn);
216 seterrmsg("cannot open temp file");
217 return ERR(-2);
218 }
219 return 0;
220}
221
222
223/* close_sbuf: close scratch file */
224int
225close_sbuf(void)
226{
227 if (sfp) {
228 if (fclose(sfp) == EOF(-1)) {
229 perror(sfn);
230 seterrmsg("cannot close temp file");
231 return ERR(-2);
232 }
233 sfp = NULL((void *)0);
234 unlink(sfn);
235 }
236 sfseek = seek_write = 0;
237 return 0;
238}
239
240
241/* quit: remove_lines scratch file and exit */
242void
243quit(int n)
244{
245 if (sfp) {
246 fclose(sfp);
247 unlink(sfn);
248 }
249 exit(n);
250}
251
252
253static unsigned char ctab[256]; /* character translation table */
254
255/* init_buffers: open scratch buffer; initialize line queue */
256void
257init_buffers(void)
258{
259 int i = 0;
260
261 /* Read stdin one character at a time to avoid i/o contention
262 with shell escapes invoked by nonterminal input, e.g.,
263 ed - <<EOF
264 !cat
265 hello, world
266 EOF */
267 setvbuf(stdin(&__sF[0]), NULL((void *)0), _IONBF2, 0);
268 if (open_sbuf() < 0)
269 quit(2);
270 REQUE(&buffer_head, &buffer_head)(&buffer_head)->q_forw = (&buffer_head), (&buffer_head
)->q_back = (&buffer_head)
;
271 for (i = 0; i < 256; i++)
272 ctab[i] = i;
273}
274
275
276/* translit_text: translate characters in a string */
277char *
278translit_text(char *s, int len, int from, int to)
279{
280 static int i = 0;
281
282 unsigned char *us;
283
284 ctab[i] = i; /* restore table to initial state */
285 ctab[i = from] = to;
286 for (us = (unsigned char *) s; len-- > 0; us++)
287 *us = ctab[*us];
288 return s;
289}