Bug Summary

File:src/lib/libcurses/tinfo/trim_sgr0.c
Warning:line 319, column 2
Argument to free() is a constant address (18446744073709551615), which is not memory allocated by malloc()

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 trim_sgr0.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/trim_sgr0.c
1/* $OpenBSD: trim_sgr0.c,v 1.1 2010/01/12 23:22:06 nicm Exp $ */
2
3/****************************************************************************
4 * Copyright (c) 2005-2006,2007 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: Thomas Dickey *
33 ****************************************************************************/
34
35#include <curses.priv.h>
36
37#include <ctype.h>
38
39#include <tic.h>
40#include <term_entry.h>
41
42MODULE_ID("$Id: trim_sgr0.c,v 1.1 2010/01/12 23:22:06 nicm Exp $")
43
44#undef CURtp->
45#define CURtp-> tp->
46
47#define CSI233 233
48#define ESC033 033 /* ^[ */
49#define L_BRACK'[' '['
50
51static char *
52set_attribute_9(TERMTYPE *tp, int flag)
53{
54 const char *result;
55
56 if ((result = tparm(set_attributestp-> Strings[131], 0, 0, 0, 0, 0, 0, 0, 0, flag)) == 0)
57 result = "";
58 return strdup(result);
59}
60
61static int
62is_csi(const char *s)
63{
64 if (UChar(s[0])((unsigned char)(s[0])) == CSI233)
65 return 1;
66 else if (s[0] == ESC033 && s[1] == L_BRACK'[')
67 return 2;
68 return 0;
69}
70
71static char *
72skip_zero(char *s)
73{
74 if (s[0] == '0') {
75 if (s[1] == ';')
76 s += 2;
77 else if (isalpha(UChar(s[1])((unsigned char)(s[1]))))
78 s += 1;
79 }
80 return s;
81}
82
83static const char *
84skip_delay(const char *s)
85{
86 if (s[0] == '$' && s[1] == '<') {
87 s += 2;
88 while (isdigit(UChar(*s)((unsigned char)(*s))) || *s == '/')
89 ++s;
90 if (*s == '>')
91 ++s;
92 }
93 return s;
94}
95
96/*
97 * Improve similar_sgr a little by moving the attr-string from the beginning
98 * to the end of the s-string.
99 */
100static bool_Bool
101rewrite_sgr(char *s, char *attr)
102{
103 if (PRESENT(s)(((s) != (char *)0) && ((s) != (char *)(-1)))) {
104 if (PRESENT(attr)(((attr) != (char *)0) && ((attr) != (char *)(-1)))) {
105 unsigned len_s = strlen(s);
106 unsigned len_a = strlen(attr);
107
108 if (len_s > len_a && !strncmp(attr, s, len_a)) {
109 unsigned n;
110 TR(TRACE_DATABASE, ("rewrite:\n\t%s", s));
111 for (n = 0; n < len_s - len_a; ++n) {
112 s[n] = s[n + len_a];
113 }
114 strlcpy(s + n, attr, len_s - n);
115 TR(TRACE_DATABASE, ("to:\n\t%s", s));
116 }
117 }
118 return TRUE1;
119 }
120 return FALSE0; /* oops */
121}
122
123static bool_Bool
124similar_sgr(char *a, char *b)
125{
126 bool_Bool result = FALSE0;
127 int csi_a = is_csi(a);
128 int csi_b = is_csi(b);
129 unsigned len_a;
130 unsigned len_b;
131
132 TR(TRACE_DATABASE, ("similar_sgr:\n\t%s\n\t%s",
133 _nc_visbuf2(1, a),
134 _nc_visbuf2(2, b)));
135 if (csi_a != 0 && csi_b != 0 && csi_a == csi_b) {
136 a += csi_a;
137 b += csi_b;
138 if (*a != *b) {
139 a = skip_zero(a);
140 b = skip_zero(b);
141 }
142 }
143 len_a = strlen(a);
144 len_b = strlen(b);
145 if (len_a && len_b) {
146 if (len_a > len_b)
147 result = (strncmp(a, b, len_b) == 0);
148 else
149 result = (strncmp(a, b, len_a) == 0);
150 }
151 TR(TRACE_DATABASE, ("...similar_sgr: %d\n\t%s\n\t%s", result,
152 _nc_visbuf2(1, a),
153 _nc_visbuf2(2, b)));
154 return result;
155}
156
157static unsigned
158chop_out(char *string, unsigned i, unsigned j)
159{
160 TR(TRACE_DATABASE, ("chop_out %d..%d from %s", i, j, _nc_visbuf(string)));
161 while (string[j] != '\0') {
162 string[i++] = string[j++];
163 }
164 string[i] = '\0';
165 return i;
166}
167
168/*
169 * Compare, ignoring delays. Some of the delay values are inconsistent, and
170 * we do not want to be stopped by that.
171 *
172 * Returns the number of chars from 'full' that we matched. If any mismatch
173 * occurs, return zero.
174 */
175static int
176compare_part(const char *part, const char *full)
177{
178 const char *next_part;
179 const char *next_full;
180 int used_full = 0;
181 int used_delay = 0;
182
183 while (*part != 0) {
184 if (*part != *full) {
185 used_full = 0;
186 break;
187 }
188
189 /*
190 * Adjust the return-value to allow the rare case of
191 * string<delay>string
192 * to remove the whole piece. The most common case is a delay at the
193 * end of the string. The adjusted string will retain the delay, which
194 * is conservative.
195 */
196 if (used_delay != 0) {
197 used_full += used_delay;
198 used_delay = 0;
199 }
200 if (*part == '$' && *full == '$') {
201 next_part = skip_delay(part);
202 next_full = skip_delay(full);
203 if (next_part != part && next_full != full) {
204 used_delay += (next_full - full);
205 full = next_full;
206 part = next_part;
207 continue;
208 }
209 }
210 ++used_full;
211 ++part;
212 ++full;
213 }
214 return used_full;
215}
216
217/*
218 * While 'sgr0' is the "same" as termcap 'me', there is a compatibility issue.
219 * The sgr/sgr0 capabilities include setting/clearing alternate character set
220 * mode. A termcap application cannot use sgr, so sgr0 strings that reset
221 * alternate character set mode will be misinterpreted. Here, we remove those
222 * from the more common ISO/ANSI/VT100 entries, which have sgr0 agreeing with
223 * sgr.
224 *
225 * This function returns the modified sgr0 if it can be modified, a null if
226 * an error occurs, or the original sgr0 if no change is needed.
227 */
228NCURSES_EXPORT(char *)char *
229_nc_trim_sgr0(TERMTYPE *tp)
230{
231 char *result = exit_attribute_modetp-> Strings[39];
232
233 T((T_CALLED("_nc_trim_sgr0()")));
234
235 if (PRESENT(exit_attribute_mode)(((tp-> Strings[39]) != (char *)0) && ((tp-> Strings
[39]) != (char *)(-1)))
1
Assuming the condition is true
2
Assuming the condition is true
5
Taking true branch
236 && PRESENT(set_attributes)(((tp-> Strings[131]) != (char *)0) && ((tp-> Strings
[131]) != (char *)(-1)))
) {
3
Assuming the condition is true
4
Assuming the condition is true
237 bool_Bool found = FALSE0;
238 char *on = set_attribute_9(tp, 1);
239 char *off = set_attribute_9(tp, 0);
240 char *end = strdup(exit_attribute_modetp-> Strings[39]);
241 char *tmp;
242 size_t i, j, k;
243
244 TR(TRACE_DATABASE, ("checking if we can trim sgr0 based on sgr"));
245 TR(TRACE_DATABASE, ("sgr0 %s", _nc_visbuf(end)));
246 TR(TRACE_DATABASE, ("sgr(9:off) %s", _nc_visbuf(off)));
247 TR(TRACE_DATABASE, ("sgr(9:on) %s", _nc_visbuf(on)));
248
249 if (!rewrite_sgr(on, enter_alt_charset_modetp-> Strings[25])
250 || !rewrite_sgr(off, exit_alt_charset_modetp-> Strings[38])
251 || !rewrite_sgr(end, exit_alt_charset_modetp-> Strings[38])) {
252 FreeIfNeeded(off)if ((off) != 0) free(off);
6
Assuming 'off' is equal to null
7
Taking false branch
253 } else if (similar_sgr(off, end)
254 && !similar_sgr(off, on)) {
255 TR(TRACE_DATABASE, ("adjusting sgr(9:off) : %s", _nc_visbuf(off)));
256 result = off;
257 /*
258 * If rmacs is a substring of sgr(0), remove that chunk.
259 */
260 if (exit_alt_charset_modetp-> Strings[38] != 0) {
261 TR(TRACE_DATABASE, ("scan for rmacs %s", _nc_visbuf(exit_alt_charset_mode)));
262 j = strlen(off);
263 k = strlen(exit_alt_charset_modetp-> Strings[38]);
264 if (j > k) {
265 for (i = 0; i <= (j - k); ++i) {
266 int k2 = compare_part(exit_alt_charset_modetp-> Strings[38], off + i);
267 if (k2 != 0) {
268 found = TRUE1;
269 chop_out(off, i, i + k2);
270 break;
271 }
272 }
273 }
274 }
275 /*
276 * SGR 10 would reset to normal font.
277 */
278 if (!found) {
279 if ((i = is_csi(off)) != 0
280 && off[strlen(off) - 1] == 'm') {
281 TR(TRACE_DATABASE, ("looking for SGR 10 in %s",
282 _nc_visbuf(off)));
283 tmp = skip_zero(off + i);
284 if (tmp[0] == '1'
285 && skip_zero(tmp + 1) != tmp + 1) {
286 i = tmp - off;
287 if (off[i - 1] == ';')
288 i--;
289 j = skip_zero(tmp + 1) - off;
290 i = chop_out(off, i, j);
291 found = TRUE1;
292 }
293 }
294 }
295 if (!found
296 && (tmp = strstr(end, off)) != 0
297 && strcmp(end, off) != 0) {
298 i = tmp - end;
299 j = strlen(off);
300 tmp = strdup(end);
301 chop_out(tmp, i, j);
302 free(off);
303 result = tmp;
304 }
305 TR(TRACE_DATABASE, ("...adjusted sgr0 : %s", _nc_visbuf(result)));
306 if (!strcmp(result, exit_attribute_modetp-> Strings[39])) {
307 TR(TRACE_DATABASE, ("...same result, discard"));
308 free(result);
309 result = exit_attribute_modetp-> Strings[39];
310 }
311 } else {
312 /*
313 * Either the sgr does not reference alternate character set,
314 * or it is incorrect. That's too hard to decide right now.
315 */
316 free(off);
317 }
318 FreeIfNeeded(end)if ((end) != 0) free(end);
8
Assuming 'end' is equal to null
9
Taking false branch
319 FreeIfNeeded(on)if ((on) != 0) free(on);
10
Taking true branch
11
Argument to free() is a constant address (18446744073709551615), which is not memory allocated by malloc()
320 } else {
321 /*
322 * Possibly some applications are confused if sgr0 contains rmacs,
323 * but that would be a different bug report -TD
324 */
325 }
326
327 returnPtr(result)return result;
328}