Bug Summary

File:src/lib/libcurses/tinfo/alloc_entry.c
Warning:line 200, column 12
Null pointer passed as 2nd 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 alloc_entry.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/lib/libcurses/obj -resource-dir /usr/local/lib/clang/13.0.0 -I . -I /usr/src/lib/libcurses -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libcurses/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/lib/libcurses/tinfo/alloc_entry.c
1/* $OpenBSD: alloc_entry.c,v 1.7 2018/06/28 15:34:10 deraadt Exp $ */
2
3/****************************************************************************
4 * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc. *
5 * *
6 * Permission is hereby granted, free of charge, to any person obtaining a *
7 * copy of this software and associated documentation files (the *
8 * "Software"), to deal in the Software without restriction, including *
9 * without limitation the rights to use, copy, modify, merge, publish, *
10 * distribute, distribute with modifications, sublicense, and/or sell *
11 * copies of the Software, and to permit persons to whom the Software is *
12 * furnished to do so, subject to the following conditions: *
13 * *
14 * The above copyright notice and this permission notice shall be included *
15 * in all copies or substantial portions of the Software. *
16 * *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
20 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
23 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
24 * *
25 * Except as contained in this notice, the name(s) of the above copyright *
26 * holders shall not be used in advertising or otherwise to promote the *
27 * sale, use or other dealings in this Software without prior written *
28 * authorization. *
29 ****************************************************************************/
30
31/****************************************************************************
32 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
33 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
34 * and: Thomas E. Dickey 1996-on *
35 ****************************************************************************/
36
37/*
38 * alloc_entry.c -- allocation functions for terminfo entries
39 *
40 * _nc_copy_entry()
41 * _nc_init_entry()
42 * _nc_merge_entry()
43 * _nc_save_str()
44 * _nc_wrap_entry()
45 *
46 */
47
48#include <curses.priv.h>
49
50#include <tic.h>
51#include <term_entry.h>
52
53MODULE_ID("$Id: alloc_entry.c,v 1.7 2018/06/28 15:34:10 deraadt Exp $")
54
55#define ABSENT_OFFSET-1 -1
56#define CANCELLED_OFFSET-2 -2
57
58#define MAX_STRTAB4096 4096 /* documented maximum entry size */
59
60static char *stringbuf; /* buffer for string capabilities */
61static size_t next_free; /* next free character in stringbuf */
62
63NCURSES_EXPORT(void)void
64_nc_init_entry(TERMTYPE *const tp)
65/* initialize a terminal type data block */
66{
67 unsigned i;
68
69#if NO_LEAKS0
70 if (tp == 0 && stringbuf != 0) {
71 FreeAndNull(stringbuf)free(stringbuf); stringbuf = 0;
72 return;
73 }
74#endif
75
76 if (stringbuf == 0)
77 stringbuf = (char *) malloc(MAX_STRTAB4096);
78
79#if NCURSES_XNAMES1
80 tp->num_Booleans = BOOLCOUNT44;
81 tp->num_Numbers = NUMCOUNT39;
82 tp->num_Strings = STRCOUNT414;
83 tp->ext_Booleans = 0;
84 tp->ext_Numbers = 0;
85 tp->ext_Strings = 0;
86#endif
87 if (tp->Booleans == 0)
88 tp->Booleans = typeMalloc(NCURSES_SBOOL, BOOLCOUNT)(signed char *)malloc((44)*sizeof(signed char));
89 if (tp->Numbers == 0)
90 tp->Numbers = typeMalloc(short, NUMCOUNT)(short *)malloc((39)*sizeof(short));
91 if (tp->Strings == 0)
92 tp->Strings = typeMalloc(char *, STRCOUNT)(char * *)malloc((414)*sizeof(char *));
93
94 for_each_boolean(i, tp)for(i = 0; i < (tp)->num_Booleans; i++)
95 tp->Booleans[i] = FALSE0;
96
97 for_each_number(i, tp)for(i = 0; i < (tp)->num_Numbers; i++)
98 tp->Numbers[i] = ABSENT_NUMERIC(-1);
99
100 for_each_string(i, tp)for(i = 0; i < (tp)->num_Strings; i++)
101 tp->Strings[i] = ABSENT_STRING(char *)0;
102
103 next_free = 0;
104}
105
106NCURSES_EXPORT(ENTRY *)ENTRY *
107_nc_copy_entry(ENTRY * oldp)
108{
109 ENTRY *newp = typeCalloc(ENTRY, 1)(ENTRY *)calloc((1),sizeof(ENTRY));
110
111 if (newp != 0) {
112 *newp = *oldp;
113 _nc_copy_termtype(&(newp->tterm), &(oldp->tterm));
114 }
115 return newp;
116}
117
118/* save a copy of string in the string buffer */
119NCURSES_EXPORT(char *)char *
120_nc_save_str(const char *const string)
121{
122 char *result = 0;
123 size_t old_next_free = next_free;
124 size_t len = strlen(string) + 1;
125
126 if (len == 1 && next_free != 0) {
4
Assuming 'len' is not equal to 1
127 /*
128 * Cheat a little by making an empty string point to the end of the
129 * previous string.
130 */
131 if (next_free < MAX_STRTAB4096) {
132 result = (stringbuf + next_free - 1);
133 }
134 } else if (next_free + len < MAX_STRTAB4096) {
5
Assuming the condition is false
6
Taking false branch
135 strlcpy(&stringbuf[next_free], string, MAX_STRTAB4096 - next_free);
136 DEBUG(7, ("Saved string %s", _nc_visbuf(string)));
137 DEBUG(7, ("at location %d", (int) next_free));
138 next_free += len;
139 result = (stringbuf + old_next_free);
140 } else {
141 _nc_warning("Too much data, some is lost");
7
Value assigned to 'stringbuf'
142 }
143 return result;
144}
145
146NCURSES_EXPORT(void)void
147_nc_wrap_entry(ENTRY * const ep, bool_Bool copy_strings)
148/* copy the string parts to allocated storage, preserving pointers to it */
149{
150 int offsets[MAX_ENTRY_SIZE4096 / sizeof(short)];
151 int useoffsets[MAX_USES32];
152 unsigned i, n;
153 unsigned nuses = ep->nuses;
154 TERMTYPE *tp = &(ep->tterm);
155
156 if (copy_strings) {
1
Assuming 'copy_strings' is true
2
Taking true branch
157 next_free = 0; /* clear static storage */
158
159 /* copy term_names, Strings, uses */
160 tp->term_names = _nc_save_str(tp->term_names);
3
Calling '_nc_save_str'
8
Returning from '_nc_save_str'
161 for_each_string(i, tp)for(i = 0; i < (tp)->num_Strings; i++) {
9
Assuming 'i' is < field 'num_Strings'
10
Loop condition is true. Entering loop body
14
Assuming 'i' is >= field 'num_Strings'
15
Loop condition is false. Execution continues on line 168
162 if (tp->Strings[i] != ABSENT_STRING(char *)0 &&
11
Assuming the condition is true
13
Taking true branch
163 tp->Strings[i] != CANCELLED_STRING(char *)(-1)) {
12
Assuming the condition is true
164 tp->Strings[i] = _nc_save_str(tp->Strings[i]);
165 }
166 }
167
168 for (i = 0; i < nuses; i++) {
16
Assuming 'i' is >= 'nuses'
17
Loop condition is false. Execution continues on line 174
169 if (ep->uses[i].name == 0) {
170 ep->uses[i].name = _nc_save_str(ep->uses[i].name);
171 }
172 }
173
174 free(tp->str_table);
175 }
176
177 assert(tp->term_names >= stringbuf)((void)0);
178 n = (unsigned) (tp->term_names - stringbuf);
179 for_each_string(i, &(ep->tterm))for(i = 0; i < (&(ep->tterm))->num_Strings; i++) {
18
Loop condition is true. Entering loop body
22
Loop condition is false. Execution continues on line 191
180 if (i < SIZEOF(offsets)(sizeof(offsets)/sizeof(offsets[0]))) {
19
Taking true branch
181 if (tp->Strings[i] == ABSENT_STRING(char *)0) {
20
Assuming pointer value is null
21
Taking true branch
182 offsets[i] = ABSENT_OFFSET-1;
183 } else if (tp->Strings[i] == CANCELLED_STRING(char *)(-1)) {
184 offsets[i] = CANCELLED_OFFSET-2;
185 } else {
186 offsets[i] = tp->Strings[i] - stringbuf;
187 }
188 }
189 }
190
191 for (i = 0; i < nuses; i++) {
23
Loop condition is false. Execution continues on line 198
192 if (ep->uses[i].name == 0)
193 useoffsets[i] = ABSENT_OFFSET-1;
194 else
195 useoffsets[i] = ep->uses[i].name - stringbuf;
196 }
197
198 if ((tp->str_table = typeMalloc(char, next_free)(char *)malloc((next_free)*sizeof(char))) == (char *) 0)
24
Assuming the condition is false
25
Taking false branch
199 _nc_err_abort(MSG_NO_MEMORY"Out of memory");
200 (void) memcpy(tp->str_table, stringbuf, next_free);
26
Null pointer passed as 2nd argument to memory copy function
201
202 tp->term_names = tp->str_table + n;
203 for_each_string(i, &(ep->tterm))for(i = 0; i < (&(ep->tterm))->num_Strings; i++) {
204 if (i < SIZEOF(offsets)(sizeof(offsets)/sizeof(offsets[0]))) {
205 if (offsets[i] == ABSENT_OFFSET-1) {
206 tp->Strings[i] = ABSENT_STRING(char *)0;
207 } else if (offsets[i] == CANCELLED_OFFSET-2) {
208 tp->Strings[i] = CANCELLED_STRING(char *)(-1);
209 } else {
210 tp->Strings[i] = tp->str_table + offsets[i];
211 }
212 }
213 }
214
215#if NCURSES_XNAMES1
216 if (!copy_strings) {
217 if ((n = (unsigned) NUM_EXT_NAMES(tp)((tp)->ext_Booleans + (tp)->ext_Numbers + (tp)->ext_Strings
)
) != 0) {
218 if (n < SIZEOF(offsets)(sizeof(offsets)/sizeof(offsets[0]))) {
219 size_t copied, length, strtabsize = 0;
220 for (i = 0; i < n; i++) {
221 strtabsize += strlen(tp->ext_Names[i]) + 1;
222 offsets[i] = tp->ext_Names[i] - stringbuf;
223 }
224 if ((tp->ext_str_table = typeMalloc(char, strtabsize)(char *)malloc((strtabsize)*sizeof(char))) == 0)
225 _nc_err_abort(MSG_NO_MEMORY"Out of memory");
226 for (i = 0, length = 0; i < n; i++) {
227 tp->ext_Names[i] = tp->ext_str_table + length;
228 copied = strlcpy(tp->ext_Names[i], stringbuf + offsets[i],
229 strtabsize) + 1;
230 if (copied > strtabsize)
231 _nc_err_abort("Buffer overflow");
232 length += copied;
233 strtabsize -= copied;
234 }
235 }
236 }
237 }
238#endif
239
240 for (i = 0; i < nuses; i++) {
241 if (useoffsets[i] == ABSENT_OFFSET-1)
242 ep->uses[i].name = 0;
243 else
244 ep->uses[i].name = (tp->str_table + useoffsets[i]);
245 }
246}
247
248NCURSES_EXPORT(void)void
249_nc_merge_entry(TERMTYPE *const to, TERMTYPE *const from)
250/* merge capabilities from `from' entry into `to' entry */
251{
252 unsigned i;
253
254#if NCURSES_XNAMES1
255 _nc_align_termtype(to, from);
256#endif
257 for_each_boolean(i, from)for(i = 0; i < (from)->num_Booleans; i++) {
258 if (to->Booleans[i] != CANCELLED_BOOLEAN((signed char)-2)) {
259 int mergebool = from->Booleans[i];
260
261 if (mergebool == CANCELLED_BOOLEAN((signed char)-2))
262 to->Booleans[i] = FALSE0;
263 else if (mergebool == TRUE1)
264 to->Booleans[i] = (char) mergebool;
265 }
266 }
267
268 for_each_number(i, from)for(i = 0; i < (from)->num_Numbers; i++) {
269 if (to->Numbers[i] != CANCELLED_NUMERIC(-2)) {
270 short mergenum = from->Numbers[i];
271
272 if (mergenum == CANCELLED_NUMERIC(-2))
273 to->Numbers[i] = ABSENT_NUMERIC(-1);
274 else if (mergenum != ABSENT_NUMERIC(-1))
275 to->Numbers[i] = mergenum;
276 }
277 }
278
279 /*
280 * Note: the copies of strings this makes don't have their own
281 * storage. This is OK right now, but will be a problem if we
282 * we ever want to deallocate entries.
283 */
284 for_each_string(i, from)for(i = 0; i < (from)->num_Strings; i++) {
285 if (to->Strings[i] != CANCELLED_STRING(char *)(-1)) {
286 char *mergestring = from->Strings[i];
287
288 if (mergestring == CANCELLED_STRING(char *)(-1))
289 to->Strings[i] = ABSENT_STRING(char *)0;
290 else if (mergestring != ABSENT_STRING(char *)0)
291 to->Strings[i] = mergestring;
292 }
293 }
294}
295
296#if NO_LEAKS0
297NCURSES_EXPORT(void)void
298_nc_alloc_entry_leaks(void)
299{
300 if (stringbuf != 0) {
301 FreeAndNull(stringbuf)free(stringbuf); stringbuf = 0;
302 }
303 next_free = 0;
304}
305#endif