Bug Summary

File:src/usr.bin/vi/build/../vi/v_increment.c
Warning:line 176, column 3
Null pointer passed as 1st argument to memory copy function

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 v_increment.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/../vi/v_increment.c
1/* $OpenBSD: v_increment.c,v 1.9 2016/01/06 22:28:52 millert 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/types.h>
15#include <sys/queue.h>
16#include <sys/time.h>
17
18#include <bitstring.h>
19#include <ctype.h>
20#include <errno(*__errno()).h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "../common/common.h"
27#include "vi.h"
28
29static char * const fmt[] = {
30#define DEC0 0
31 "%ld",
32#define SDEC1 1
33 "%+ld",
34#define HEXC2 2
35 "0X%0*lX",
36#define HEXL3 3
37 "0x%0*lx",
38#define OCTAL4 4
39 "%#0*lo",
40};
41
42static void inc_err(SCR *, enum nresult);
43
44/*
45 * v_increment -- [count]#[#+-]
46 * Increment/decrement a keyword number.
47 *
48 * PUBLIC: int v_increment(SCR *, VICMD *);
49 */
50int
51v_increment(SCR *sp, VICMD *vp)
52{
53 enum nresult nret;
54 u_long ulval;
55 long change, ltmp, lval;
56 size_t beg, blen, end, len, nlen, wlen;
57 int base, isempty, rval;
58 char *bp, *ntype, *p, *t, nbuf[100];
59
60 /* Validate the operator. */
61 if (vp->character == '#')
1
Assuming the condition is false
2
Taking false branch
62 vp->character = '+';
63 if (vp->character != '+' && vp->character != '-') {
3
Assuming the condition is false
64 v_emsg(sp, vp->kp->usage, VIM_USAGE);
65 return (1);
66 }
67
68 /* If new value set, save it off, but it has to fit in a long. */
69 if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800)))) {
4
Assuming the condition is false
5
Taking false branch
70 if (vp->count > LONG_MAX9223372036854775807L) {
71 inc_err(sp, NUM_OVER);
72 return (1);
73 }
74 change = vp->count;
75 } else
76 change = 1;
77
78 /* Get the line. */
79 if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
6
Assuming the condition is false
7
Taking false branch
80 if (isempty)
81 goto nonum;
82 return (1);
83 }
84
85 /*
86 * Skip any leading space before the number. Getting a cursor word
87 * implies moving the cursor to its beginning, if we moved, refresh
88 * now.
89 */
90 for (beg = vp->m_start.cno; beg < len && isspace(p[beg]); ++beg);
8
Assuming 'beg' is < 'len'
9
Loop condition is false. Execution continues on line 91
91 if (beg
9.1
'beg' is < 'len'
>= len)
10
Taking false branch
92 goto nonum;
93 if (beg
10.1
'beg' is equal to field 'cno'
!= vp->m_start.cno) {
11
Taking false branch
94 sp->cno = beg;
95 (void)vs_refresh(sp, 0);
96 }
97
98#undef ishex
99#define ishex(c)(isdigit(c) || strchr("abcdefABCDEF", (c))) (isdigit(c) || strchr("abcdefABCDEF", (c)))
100#undef isoctal
101#define isoctal(c)(isdigit(c) && (c) != '8' && (c) != '9') (isdigit(c) && (c) != '8' && (c) != '9')
102
103 /*
104 * Look for 0[Xx], or leading + or - signs, guess at the base.
105 * The character after that must be a number. Wlen is set to
106 * the remaining characters in the line that could be part of
107 * the number.
108 */
109 wlen = len - beg;
110 if (p[beg] == '0' && wlen > 2 &&
12
Assuming the condition is false
111 (p[beg + 1] == 'X' || p[beg + 1] == 'x')) {
112 base = 16;
113 end = beg + 2;
114 if (!ishex(p[end])(isdigit(p[end]) || strchr("abcdefABCDEF", (p[end]))))
115 goto decimal;
116 ntype = p[beg + 1] == 'X' ? fmt[HEXC2] : fmt[HEXL3];
117 } else if (p[beg] == '0' && wlen > 1) {
13
Assuming the condition is false
118 base = 8;
119 end = beg + 1;
120 if (!isoctal(p[end])(isdigit(p[end]) && (p[end]) != '8' && (p[end
]) != '9')
)
121 goto decimal;
122 ntype = fmt[OCTAL4];
123 } else if (wlen >= 1 && (p[beg] == '+' || p[beg] == '-')) {
14
Assuming 'wlen' is >= 1
15
Assuming the condition is true
124 base = 10;
125 end = beg + 1;
126 ntype = fmt[SDEC1];
127 if (!isdigit(p[end]))
16
Taking false branch
128 goto nonum;
129 } else {
130decimal: base = 10;
131 end = beg;
132 ntype = fmt[DEC0];
133 if (!isdigit(p[end])) {
134nonum: msgq(sp, M_ERR, "Cursor not in a number");
135 return (1);
136 }
137 }
138
139 /* Find the end of the word, possibly correcting the base. */
140 while (++end < len) {
17
Assuming the condition is false
18
Loop condition is false. Execution continues on line 165
141 switch (base) {
142 case 8:
143 if (isoctal(p[end])(isdigit(p[end]) && (p[end]) != '8' && (p[end
]) != '9')
)
144 continue;
145 if (p[end] == '8' || p[end] == '9') {
146 base = 10;
147 ntype = fmt[DEC0];
148 continue;
149 }
150 break;
151 case 10:
152 if (isdigit(p[end]))
153 continue;
154 break;
155 case 16:
156 if (ishex(p[end])(isdigit(p[end]) || strchr("abcdefABCDEF", (p[end]))))
157 continue;
158 break;
159 default:
160 abort();
161 /* NOTREACHED */
162 }
163 break;
164 }
165 wlen = (end - beg);
166
167 /*
168 * XXX
169 * If the line was at the end of the buffer, we have to copy it
170 * so we can guarantee that it's NULL-terminated. We make the
171 * buffer big enough to fit the line changes as well, and only
172 * allocate once.
173 */
174 GET_SPACE_RET(sp, bp, blen, len + 50){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((len + 50)) > ((blen))) { if ((L__bincp = binc(((sp)), ((
bp)), &((blen)), ((len + 50)))) == ((void *)0)) return (1
); ((bp)) = L__bincp; } }; } else { { void *L__bincp; if (((len
+ 50)) > (L__gp->tmp_blen)) { if ((L__bincp = binc(((sp
)), (L__gp->tmp_bp), &(L__gp->tmp_blen), ((len + 50
)))) == ((void *)0)) return (1); (L__gp->tmp_bp) = L__bincp
; } }; (bp) = L__gp->tmp_bp; (blen) = L__gp->tmp_blen; (
((L__gp)->flags) |= ((0x0100))); } }
;
19
Assuming 'sp' is equal to null
20
'?' condition is true
21
Null pointer value stored to 'bp'
22
Assuming the condition is false
23
Taking false branch
175 if (end == len) {
24
Assuming 'end' is equal to 'len'
25
Taking true branch
176 memmove(bp, &p[beg], wlen);
26
Null pointer passed as 1st argument to memory copy function
177 bp[wlen] = '\0';
178 t = bp;
179 } else
180 t = &p[beg];
181
182 /*
183 * Octal or hex deal in unsigned longs, everything else is done
184 * in signed longs.
185 */
186 if (base == 10) {
187 if ((nret = nget_slong(&lval, t, NULL((void *)0), 10)) != NUM_OK)
188 goto err;
189 ltmp = vp->character == '-' ? -change : change;
190 if (lval > 0 && ltmp > 0 && !NPFITS(LONG_MAX, lval, ltmp)(((unsigned long)(9223372036854775807L)) - (lval) >= (ltmp
))
) {
191 nret = NUM_OVER;
192 goto err;
193 }
194 if (lval < 0 && ltmp < 0 && !NNFITS(LONG_MIN, lval, ltmp)(((long)((-9223372036854775807L -1L))) - (lval) <= (ltmp))) {
195 nret = NUM_UNDER;
196 goto err;
197 }
198 lval += ltmp;
199 /* If we cross 0, signed numbers lose their sign. */
200 if (lval == 0 && ntype == fmt[SDEC1])
201 ntype = fmt[DEC0];
202 nlen = snprintf(nbuf, sizeof(nbuf), ntype, lval);
203 if (nlen >= sizeof(nbuf))
204 nlen = sizeof(nbuf) - 1;
205 } else {
206 if ((nret = nget_uslong(&ulval, t, NULL((void *)0), base)) != NUM_OK)
207 goto err;
208 if (vp->character == '+') {
209 if (!NPFITS(ULONG_MAX, ulval, change)(((unsigned long)((9223372036854775807L *2UL+1UL))) - (ulval)
>= (change))
) {
210 nret = NUM_OVER;
211 goto err;
212 }
213 ulval += change;
214 } else {
215 if (ulval < change) {
216 nret = NUM_UNDER;
217 goto err;
218 }
219 ulval -= change;
220 }
221
222 /* Correct for literal "0[Xx]" in format. */
223 if (base == 16)
224 wlen -= 2;
225
226 nlen = snprintf(nbuf, sizeof(nbuf), ntype, wlen, ulval);
227 if (nlen >= sizeof(nbuf))
228 nlen = sizeof(nbuf) - 1;
229 }
230
231 /* Build the new line. */
232 memmove(bp, p, beg);
233 memmove(bp + beg, nbuf, nlen);
234 memmove(bp + beg + nlen, p + end, len - beg - (end - beg));
235 len = beg + nlen + (len - beg - (end - beg));
236
237 nret = NUM_OK;
238 rval = db_set(sp, vp->m_start.lno, bp, len);
239
240 if (0) {
241err: rval = 1;
242 inc_err(sp, nret);
243 }
244 if (bp != NULL((void *)0))
245 FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
246 return (rval);
247}
248
249static void
250inc_err(SCR *sp, enum nresult nret)
251{
252 switch (nret) {
253 case NUM_ERR:
254 break;
255 case NUM_OK:
256 abort();
257 /* NOREACHED */
258 case NUM_OVER:
259 msgq(sp, M_ERR, "Resulting number too large");
260 break;
261 case NUM_UNDER:
262 msgq(sp, M_ERR, "Resulting number too small");
263 break;
264 }
265}