Bug Summary

File:src/usr.bin/vi/build/../common/seq.c
Warning:line 249, column 8
Use of memory after it is freed

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 seq.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/vi/build/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/vi/build -I /usr/src/usr.bin/vi/build/../include -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/vi/build/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/vi/build/../common/seq.c
1/* $OpenBSD: seq.c,v 1.14 2017/04/18 01:45:35 deraadt Exp $ */
2
3/*-
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7 * Keith Bostic. All rights reserved.
8 *
9 * See the LICENSE file for redistribution information.
10 */
11
12#include "config.h"
13
14#include <sys/queue.h>
15
16#include <bitstring.h>
17#include <ctype.h>
18#include <errno(*__errno()).h>
19#include <limits.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "common.h"
25
26#define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b))
27
28/*
29 * seq_set --
30 * Internal version to enter a sequence.
31 *
32 * PUBLIC: int seq_set(SCR *, CHAR_T *,
33 * PUBLIC: size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int);
34 */
35int
36seq_set(SCR *sp, CHAR_T *name, size_t nlen, CHAR_T *input, size_t ilen,
37 CHAR_T *output, size_t olen, seq_t stype, int flags)
38{
39 CHAR_T *p;
40 SEQ *lastqp, *qp;
41 int sv_errno;
42
43 /*
44 * An input string must always be present. The output string
45 * can be NULL, when set internally, that's how we throw away
46 * input.
47 *
48 * Just replace the output field if the string already set.
49 */
50 if ((qp =
51 seq_find(sp, &lastqp, NULL((void *)0), input, ilen, stype, NULL((void *)0))) != NULL((void *)0)) {
52 if (LF_ISSET(SEQ_NOOVERWRITE)((flags) & ((0x02))))
53 return (0);
54 if (output == NULL((void *)0) || olen == 0) {
55 p = NULL((void *)0);
56 olen = 0;
57 } else if ((p = v_strdup(sp, output, olen)) == NULL((void *)0)) {
58 sv_errno = errno(*__errno());
59 goto mem1;
60 }
61 free(qp->output);
62 qp->olen = olen;
63 qp->output = p;
64 return (0);
65 }
66
67 /* Allocate and initialize SEQ structure. */
68 CALLOC(sp, qp, 1, sizeof(SEQ)){ if (((qp) = calloc((1), (sizeof(SEQ)))) == ((void *)0)) msgq
((sp), M_SYSERR, ((void *)0)); }
;
69 if (qp == NULL((void *)0)) {
70 sv_errno = errno(*__errno());
71 goto mem1;
72 }
73
74 /* Name. */
75 if (name == NULL((void *)0) || nlen == 0)
76 qp->name = NULL((void *)0);
77 else if ((qp->name = v_strdup(sp, name, nlen)) == NULL((void *)0)) {
78 sv_errno = errno(*__errno());
79 goto mem2;
80 }
81 qp->nlen = nlen;
82
83 /* Input. */
84 if ((qp->input = v_strdup(sp, input, ilen)) == NULL((void *)0)) {
85 sv_errno = errno(*__errno());
86 goto mem3;
87 }
88 qp->ilen = ilen;
89
90 /* Output. */
91 if (output == NULL((void *)0)) {
92 qp->output = NULL((void *)0);
93 olen = 0;
94 } else if ((qp->output = v_strdup(sp, output, olen)) == NULL((void *)0)) {
95 sv_errno = errno(*__errno());
96 free(qp->input);
97mem3: free(qp->name);
98mem2: free(qp);
99mem1: errno(*__errno()) = sv_errno;
100 msgq(sp, M_SYSERR, NULL((void *)0));
101 return (1);
102 }
103 qp->olen = olen;
104
105 /* Type, flags. */
106 qp->stype = stype;
107 qp->flags = flags;
108
109 /* Link into the chain. */
110 if (lastqp == NULL((void *)0)) {
111 LIST_INSERT_HEAD(&sp->gp->seqq, qp, q)do { if (((qp)->q.le_next = (&sp->gp->seqq)->
lh_first) != ((void *)0)) (&sp->gp->seqq)->lh_first
->q.le_prev = &(qp)->q.le_next; (&sp->gp->
seqq)->lh_first = (qp); (qp)->q.le_prev = &(&sp
->gp->seqq)->lh_first; } while (0)
;
112 } else {
113 LIST_INSERT_AFTER(lastqp, qp, q)do { if (((qp)->q.le_next = (lastqp)->q.le_next) != ((void
*)0)) (lastqp)->q.le_next->q.le_prev = &(qp)->q
.le_next; (lastqp)->q.le_next = (qp); (qp)->q.le_prev =
&(lastqp)->q.le_next; } while (0)
;
114 }
115
116 /* Set the fast lookup bit. */
117 if (qp->input[0] < MAX_BIT_SEQ128)
118 bit_set(sp->gp->seqb, qp->input[0])((sp->gp->seqb)[((qp->input[0]) >> 3)] |= (1 <<
((qp->input[0])&0x7)))
;
119
120 return (0);
121}
122
123/*
124 * seq_delete --
125 * Delete a sequence.
126 *
127 * PUBLIC: int seq_delete(SCR *, CHAR_T *, size_t, seq_t);
128 */
129int
130seq_delete(SCR *sp, CHAR_T *input, size_t ilen, seq_t stype)
131{
132 SEQ *qp;
133
134 if ((qp = seq_find(sp, NULL((void *)0), NULL((void *)0), input, ilen, stype, NULL((void *)0))) == NULL((void *)0))
135 return (1);
136 return (seq_mdel(qp));
137}
138
139/*
140 * seq_mdel --
141 * Delete a map entry, without lookup.
142 *
143 * PUBLIC: int seq_mdel(SEQ *);
144 */
145int
146seq_mdel(SEQ *qp)
147{
148 LIST_REMOVE(qp, q)do { if ((qp)->q.le_next != ((void *)0)) (qp)->q.le_next
->q.le_prev = (qp)->q.le_prev; *(qp)->q.le_prev = (qp
)->q.le_next; ; ; } while (0)
;
149 free(qp->name);
150 free(qp->input);
151 free(qp->output);
152 free(qp);
153 return (0);
154}
155
156/*
157 * seq_find --
158 * Search the sequence list for a match to a buffer, if ispartial
159 * isn't NULL, partial matches count.
160 *
161 * PUBLIC: SEQ *seq_find
162 * PUBLIC:(SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *);
163 */
164SEQ *
165seq_find(SCR *sp, SEQ **lastqp, EVENT *e_input, CHAR_T *c_input, size_t ilen,
166 seq_t stype, int *ispartialp)
167{
168 SEQ *lqp, *qp;
169 int diff;
170
171 /*
172 * Ispartialp is a location where we return if there was a
173 * partial match, i.e. if the string were extended it might
174 * match something.
175 *
176 * XXX
177 * Overload the meaning of ispartialp; only the terminal key
178 * search doesn't want the search limited to complete matches,
179 * i.e. ilen may be longer than the match.
180 */
181 if (ispartialp != NULL((void *)0))
182 *ispartialp = 0;
183 for (lqp = NULL((void *)0), qp = LIST_FIRST(&sp->gp->seqq)((&sp->gp->seqq)->lh_first);
184 qp != NULL((void *)0); lqp = qp, qp = LIST_NEXT(qp, q)((qp)->q.le_next)) {
185 /*
186 * Fast checks on the first character and type, and then
187 * a real comparison.
188 */
189 if (e_input == NULL((void *)0)) {
190 if (qp->input[0] > c_input[0])
191 break;
192 if (qp->input[0] < c_input[0] ||
193 qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP)(((qp)->flags) & ((0x01))))
194 continue;
195 diff = memcmp(qp->input, c_input, MINIMUM(qp->ilen, ilen)(((qp->ilen) < (ilen)) ? (qp->ilen) : (ilen)));
196 } else {
197 if (qp->input[0] > e_input->e_c_u_event._e_ch.c)
198 break;
199 if (qp->input[0] < e_input->e_c_u_event._e_ch.c ||
200 qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP)(((qp)->flags) & ((0x01))))
201 continue;
202 diff =
203 e_memcmp(qp->input, e_input, MINIMUM(qp->ilen, ilen)(((qp->ilen) < (ilen)) ? (qp->ilen) : (ilen)));
204 }
205 if (diff > 0)
206 break;
207 if (diff < 0)
208 continue;
209 /*
210 * If the entry is the same length as the string, return a
211 * match. If the entry is shorter than the string, return a
212 * match if called from the terminal key routine. Otherwise,
213 * keep searching for a complete match.
214 */
215 if (qp->ilen <= ilen) {
216 if (qp->ilen == ilen || ispartialp != NULL((void *)0)) {
217 if (lastqp != NULL((void *)0))
218 *lastqp = lqp;
219 return (qp);
220 }
221 continue;
222 }
223 /*
224 * If the entry longer than the string, return partial match
225 * if called from the terminal key routine. Otherwise, no
226 * match.
227 */
228 if (ispartialp != NULL((void *)0))
229 *ispartialp = 1;
230 break;
231 }
232 if (lastqp != NULL((void *)0))
233 *lastqp = lqp;
234 return (NULL((void *)0));
235}
236
237/*
238 * seq_close --
239 * Discard all sequences.
240 *
241 * PUBLIC: void seq_close(GS *);
242 */
243void
244seq_close(GS *gp)
245{
246 SEQ *qp;
247
248 while ((qp = LIST_FIRST(&gp->seqq)((&gp->seqq)->lh_first)) != NULL((void *)0)) {
1
Assuming the condition is true
2
Loop condition is true. Entering loop body
7
Loop condition is true. Entering loop body
249 free(qp->name);
8
Use of memory after it is freed
250 free(qp->input);
251 free(qp->output);
252 LIST_REMOVE(qp, q)do { if ((qp)->q.le_next != ((void *)0)) (qp)->q.le_next
->q.le_prev = (qp)->q.le_prev; *(qp)->q.le_prev = (qp
)->q.le_next; ; ; } while (0)
;
3
Assuming field 'le_next' is equal to null
4
Taking false branch
5
Loop condition is false. Exiting loop
253 free(qp);
6
Memory is released
254 }
255}
256
257/*
258 * seq_dump --
259 * Display the sequence entries of a specified type.
260 *
261 * PUBLIC: int seq_dump(SCR *, seq_t, int);
262 */
263int
264seq_dump(SCR *sp, seq_t stype, int isname)
265{
266 CHAR_T *p;
267 GS *gp;
268 SEQ *qp;
269 int cnt, len, olen;
270
271 cnt = 0;
272 gp = sp->gp;
273 LIST_FOREACH(qp, &gp->seqq, q)for((qp) = ((&gp->seqq)->lh_first); (qp)!= ((void *
)0); (qp) = ((qp)->q.le_next))
{
274 if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP)(((qp)->flags) & ((0x01))))
275 continue;
276 ++cnt;
277 for (p = qp->input,
278 olen = qp->ilen, len = 0; olen > 0; --olen, ++p)
279 len += ex_puts(sp, KEY_NAME(sp, *p)((unsigned char)(*p) <= 254 ? (sp)->gp->cname[(unsigned
char)(*p)].name : v_key_name((sp), (*p)))
);
280 for (len = STANDARD_TAB6 - len % STANDARD_TAB6; len > 0;)
281 len -= ex_puts(sp, " ");
282
283 if (qp->output != NULL((void *)0))
284 for (p = qp->output,
285 olen = qp->olen, len = 0; olen > 0; --olen, ++p)
286 len += ex_puts(sp, KEY_NAME(sp, *p)((unsigned char)(*p) <= 254 ? (sp)->gp->cname[(unsigned
char)(*p)].name : v_key_name((sp), (*p)))
);
287 else
288 len = 0;
289
290 if (isname && qp->name != NULL((void *)0)) {
291 for (len = STANDARD_TAB6 - len % STANDARD_TAB6; len > 0;)
292 len -= ex_puts(sp, " ");
293 for (p = qp->name,
294 olen = qp->nlen; olen > 0; --olen, ++p)
295 (void)ex_puts(sp, KEY_NAME(sp, *p)((unsigned char)(*p) <= 254 ? (sp)->gp->cname[(unsigned
char)(*p)].name : v_key_name((sp), (*p)))
);
296 }
297 (void)ex_puts(sp, "\n");
298 }
299 return (cnt);
300}
301
302/*
303 * seq_save --
304 * Save the sequence entries to a file.
305 *
306 * PUBLIC: int seq_save(SCR *, FILE *, char *, seq_t);
307 */
308int
309seq_save(SCR *sp, FILE *fp, char *prefix, seq_t stype)
310{
311 CHAR_T *p;
312 SEQ *qp;
313 size_t olen;
314 int ch;
315
316 /* Write a sequence command for all keys the user defined. */
317 LIST_FOREACH(qp, &sp->gp->seqq, q)for((qp) = ((&sp->gp->seqq)->lh_first); (qp)!= (
(void *)0); (qp) = ((qp)->q.le_next))
{
318 if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF)(((qp)->flags) & ((0x08))))
319 continue;
320 if (prefix)
321 (void)fprintf(fp, "%s", prefix);
322 for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
323 ch = *p++;
324 if (ch == CH_LITERAL'\026' || ch == '|' ||
325 isblank(ch) || KEY_VAL(sp, ch)((unsigned char)(ch) <= 254 ? (sp)->gp->special_key[
(unsigned char)(ch)] : (unsigned char)(ch) > (sp)->gp->
max_special ? 0 : v_key_val((sp),(ch)))
== K_NL)
326 (void)putc(CH_LITERAL, fp)(!__isthreaded ? __sputc('\026', fp) : (putc)('\026', fp));
327 (void)putc(ch, fp)(!__isthreaded ? __sputc(ch, fp) : (putc)(ch, fp));
328 }
329 (void)putc(' ', fp)(!__isthreaded ? __sputc(' ', fp) : (putc)(' ', fp));
330 if (qp->output != NULL((void *)0))
331 for (p = qp->output,
332 olen = qp->olen; olen > 0; --olen) {
333 ch = *p++;
334 if (ch == CH_LITERAL'\026' || ch == '|' ||
335 KEY_VAL(sp, ch)((unsigned char)(ch) <= 254 ? (sp)->gp->special_key[
(unsigned char)(ch)] : (unsigned char)(ch) > (sp)->gp->
max_special ? 0 : v_key_val((sp),(ch)))
== K_NL)
336 (void)putc(CH_LITERAL, fp)(!__isthreaded ? __sputc('\026', fp) : (putc)('\026', fp));
337 (void)putc(ch, fp)(!__isthreaded ? __sputc(ch, fp) : (putc)(ch, fp));
338 }
339 (void)putc('\n', fp)(!__isthreaded ? __sputc('\n', fp) : (putc)('\n', fp));
340 }
341 return (0);
342}
343
344/*
345 * e_memcmp --
346 * Compare a string of EVENT's to a string of CHAR_T's.
347 *
348 * PUBLIC: int e_memcmp(CHAR_T *, EVENT *, size_t);
349 */
350int
351e_memcmp(CHAR_T *p1, EVENT *ep, size_t n)
352{
353 if (n != 0) {
354 do {
355 if (*p1++ != ep->e_c_u_event._e_ch.c)
356 return (*--p1 - ep->e_c_u_event._e_ch.c);
357 ++ep;
358 } while (--n != 0);
359 }
360 return (0);
361}