Bug Summary

File:src/gnu/lib/libreadline/tilde.c
Warning:line 204, column 18
Although the value stored to 'result_size' is used in the enclosing expression, the value is never actually read from 'result_size'

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 tilde.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 -fhalf-no-semantic-interposition -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/gnu/lib/libreadline/obj -resource-dir /usr/local/lib/clang/13.0.0 -D HAVE_CONFIG_H -I /usr/src/gnu/lib/libreadline -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/gnu/lib/libreadline/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/gnu/lib/libreadline/tilde.c
1/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
2
3/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
4
5 This file is part of GNU Readline, a library for reading lines
6 of text with interactive input and history editing.
7
8 Readline is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 Readline is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Readline; see the file COPYING. If not, write to the Free
20 Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
21
22#if defined (HAVE_CONFIG_H1)
23# include <config.h>
24#endif
25
26#if defined (HAVE_UNISTD_H1)
27# ifdef _MINIX
28# include <sys/types.h>
29# endif
30# include <unistd.h>
31#endif
32
33#if defined (HAVE_STRING_H1)
34# include <string.h>
35#else /* !HAVE_STRING_H */
36# include <strings.h>
37#endif /* !HAVE_STRING_H */
38
39#if defined (HAVE_STDLIB_H1)
40# include <stdlib.h>
41#else
42# include "ansi_stdlib.h"
43#endif /* HAVE_STDLIB_H */
44
45#include <sys/types.h>
46#include <pwd.h>
47
48#include "tilde.h"
49
50#if defined (TEST) || defined (STATIC_MALLOC)
51static void *xmalloc (), *xrealloc ();
52#else
53# include "xmalloc.h"
54#endif /* TEST || STATIC_MALLOC */
55
56#if !defined (HAVE_GETPW_DECLS1)
57extern struct passwd *getpwuid PARAMS((uid_t))(uid_t);
58extern struct passwd *getpwnam PARAMS((const char *))(const char *);
59#endif /* !HAVE_GETPW_DECLS */
60
61#if !defined (savestring)
62#include <stdio.h>
63static char *
64xstrdup(const char *s)
65{
66 char * cp;
67 cp = strdup(s);
68 if (cp == NULL((void *)0)) {
69 fprintf (stderr(&__sF[2]), "xstrdup: out of virtual memory\n");
70 exit (2);
71 }
72 return(cp);
73}
74#define savestring(x)xstrdup(x) xstrdup(x)
75#endif /* !savestring */
76
77#if !defined (NULL((void *)0))
78# if defined (__STDC__1)
79# define NULL((void *)0) ((void *) 0)
80# else
81# define NULL((void *)0) 0x0
82# endif /* !__STDC__ */
83#endif /* !NULL */
84
85/* If being compiled as part of bash, these will be satisfied from
86 variables.o. If being compiled as part of readline, they will
87 be satisfied from shell.o. */
88extern char *sh_get_home_dir PARAMS((void))(void);
89extern char *sh_get_env_value PARAMS((const char *))(const char *);
90
91/* The default value of tilde_additional_prefixes. This is set to
92 whitespace preceding a tilde so that simple programs which do not
93 perform any word separation get desired behaviour. */
94static const char *default_prefixes[] =
95 { " ~", "\t~", (const char *)NULL((void *)0) };
96
97/* The default value of tilde_additional_suffixes. This is set to
98 whitespace or newline so that simple programs which do not
99 perform any word separation get desired behaviour. */
100static const char *default_suffixes[] =
101 { " ", "\n", (const char *)NULL((void *)0) };
102
103/* If non-null, this contains the address of a function that the application
104 wants called before trying the standard tilde expansions. The function
105 is called with the text sans tilde, and returns a malloc()'ed string
106 which is the expansion, or a NULL pointer if the expansion fails. */
107tilde_hook_func_t *tilde_expansion_preexpansion_hook = (tilde_hook_func_t *)NULL((void *)0);
108
109/* If non-null, this contains the address of a function to call if the
110 standard meaning for expanding a tilde fails. The function is called
111 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
112 which is the expansion, or a NULL pointer if there is no expansion. */
113tilde_hook_func_t *tilde_expansion_failure_hook = (tilde_hook_func_t *)NULL((void *)0);
114
115/* When non-null, this is a NULL terminated array of strings which
116 are duplicates for a tilde prefix. Bash uses this to expand
117 `=~' and `:~'. */
118char **tilde_additional_prefixes = (char **)default_prefixes;
119
120/* When non-null, this is a NULL terminated array of strings which match
121 the end of a username, instead of just "/". Bash sets this to
122 `:' and `=~'. */
123char **tilde_additional_suffixes = (char **)default_suffixes;
124
125static int tilde_find_prefix PARAMS((const char *, int *))(const char *, int *);
126static int tilde_find_suffix PARAMS((const char *))(const char *);
127static char *isolate_tilde_prefix PARAMS((const char *, int *))(const char *, int *);
128static char *glue_prefix_and_suffix PARAMS((char *, const char *, int))(char *, const char *, int);
129
130/* Find the start of a tilde expansion in STRING, and return the index of
131 the tilde which starts the expansion. Place the length of the text
132 which identified this tilde starter in LEN, excluding the tilde itself. */
133static int
134tilde_find_prefix (string, len)
135 const char *string;
136 int *len;
137{
138 register int i, j, string_len;
139 register char **prefixes;
140
141 prefixes = tilde_additional_prefixes;
142
143 string_len = strlen (string);
144 *len = 0;
145
146 if (*string == '\0' || *string == '~')
147 return (0);
148
149 if (prefixes)
150 {
151 for (i = 0; i < string_len; i++)
152 {
153 for (j = 0; prefixes[j]; j++)
154 {
155 if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
156 {
157 *len = strlen (prefixes[j]) - 1;
158 return (i + *len);
159 }
160 }
161 }
162 }
163 return (string_len);
164}
165
166/* Find the end of a tilde expansion in STRING, and return the index of
167 the character which ends the tilde definition. */
168static int
169tilde_find_suffix (string)
170 const char *string;
171{
172 register int i, j, string_len;
173 register char **suffixes;
174
175 suffixes = tilde_additional_suffixes;
176 string_len = strlen (string);
177
178 for (i = 0; i < string_len; i++)
179 {
180#if defined (__MSDOS__)
181 if (string[i] == '/' || string[i] == '\\' /* || !string[i] */)
182#else
183 if (string[i] == '/' /* || !string[i] */)
184#endif
185 break;
186
187 for (j = 0; suffixes && suffixes[j]; j++)
188 {
189 if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
190 return (i);
191 }
192 }
193 return (i);
194}
195
196/* Return a new string which is the result of tilde expanding STRING. */
197char *
198tilde_expand (string)
199 const char *string;
200{
201 char *result;
202 int result_size, result_index;
203
204 result_index = result_size = 0;
Although the value stored to 'result_size' is used in the enclosing expression, the value is never actually read from 'result_size'
205 if ((result = strchr (string, '~')))
206 result = (char *)xmalloc (result_size = (strlen (string) + 16));
207 else
208 result = (char *)xmalloc (result_size = (strlen (string) + 1));
209
210 /* Scan through STRING expanding tildes as we come to them. */
211 while (1)
212 {
213 register int start, end;
214 char *tilde_word, *expansion;
215 int len;
216
217 /* Make START point to the tilde which starts the expansion. */
218 start = tilde_find_prefix (string, &len);
219
220 /* Copy the skipped text into the result. */
221 if ((result_index + start + 1) > result_size)
222 result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
223
224 strncpy (result + result_index, string, start);
225 result_index += start;
226
227 /* Advance STRING to the starting tilde. */
228 string += start;
229
230 /* Make END be the index of one after the last character of the
231 username. */
232 end = tilde_find_suffix (string);
233
234 /* If both START and END are zero, we are all done. */
235 if (!start && !end)
236 break;
237
238 /* Expand the entire tilde word, and copy it into RESULT. */
239 tilde_word = (char *)xmalloc (1 + end);
240 strncpy (tilde_word, string, end);
241 tilde_word[end] = '\0';
242 string += end;
243
244 expansion = tilde_expand_word (tilde_word);
245 free (tilde_word);
246
247 len = strlen (expansion);
248#ifdef __CYGWIN__
249 /* Fix for Cygwin to prevent ~user/xxx from expanding to //xxx when
250 $HOME for `user' is /. On cygwin, // denotes a network drive. */
251 if (len > 1 || *expansion != '/' || *string != '/')
252#endif
253 {
254 if ((result_index + len + 1) > result_size)
255 result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
256
257 strlcpy (result + result_index, expansion,
258 result_size - result_index);
259 result_index += len;
260 }
261 free (expansion);
262 }
263
264 result[result_index] = '\0';
265
266 return (result);
267}
268
269/* Take FNAME and return the tilde prefix we want expanded. If LENP is
270 non-null, the index of the end of the prefix into FNAME is returned in
271 the location it points to. */
272static char *
273isolate_tilde_prefix (fname, lenp)
274 const char *fname;
275 int *lenp;
276{
277 char *ret;
278 int i;
279
280 ret = (char *)xmalloc (strlen (fname));
281#if defined (__MSDOS__)
282 for (i = 1; fname[i] && fname[i] != '/' && fname[i] != '\\'; i++)
283#else
284 for (i = 1; fname[i] && fname[i] != '/'; i++)
285#endif
286 ret[i - 1] = fname[i];
287 ret[i - 1] = '\0';
288 if (lenp)
289 *lenp = i;
290 return ret;
291}
292
293/* Return a string that is PREFIX concatenated with SUFFIX starting at
294 SUFFIND. */
295static char *
296glue_prefix_and_suffix (prefix, suffix, suffind)
297 char *prefix;
298 const char *suffix;
299 int suffind;
300{
301 char *ret;
302 int plen, slen;
303
304 plen = (prefix && *prefix) ? strlen (prefix) : 0;
305 slen = strlen (suffix + suffind);
306 ret = (char *)xmalloc (plen + slen + 1);
307 if (plen)
308 strlcpy (ret, prefix, plen + slen + 1);
309 strlcat (ret, suffix + suffind, plen + slen + 1);
310 return ret;
311}
312
313/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
314 tilde. If there is no expansion, call tilde_expansion_failure_hook.
315 This always returns a newly-allocated string, never static storage. */
316char *
317tilde_expand_word (filename)
318 const char *filename;
319{
320 char *dirname, *expansion, *username;
321 int user_len;
322 struct passwd *user_entry;
323
324 if (filename == 0)
325 return ((char *)NULL((void *)0));
326
327 if (*filename != '~')
328 return (savestring (filename)xstrdup(filename));
329
330 /* A leading `~/' or a bare `~' is *always* translated to the value of
331 $HOME or the home directory of the current user, regardless of any
332 preexpansion hook. */
333 if (filename[1] == '\0' || filename[1] == '/')
334 {
335 /* Prefix $HOME to the rest of the string. */
336 expansion = sh_get_env_value ("HOME");
337
338 /* If there is no HOME variable, look up the directory in
339 the password database. */
340 if (expansion == 0 || *expansion == '\0')
341 expansion = sh_get_home_dir ();
342
343 return (glue_prefix_and_suffix (expansion, filename, 1));
344 }
345
346 username = isolate_tilde_prefix (filename, &user_len);
347
348 if (tilde_expansion_preexpansion_hook)
349 {
350 expansion = (*tilde_expansion_preexpansion_hook) (username);
351 if (expansion)
352 {
353 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
354 free (username);
355 free (expansion);
356 return (dirname);
357 }
358 }
359
360 /* No preexpansion hook, or the preexpansion hook failed. Look in the
361 password database. */
362 dirname = (char *)NULL((void *)0);
363 user_entry = getpwnam (username);
364 if (user_entry == 0)
365 {
366 /* If the calling program has a special syntax for expanding tildes,
367 and we couldn't find a standard expansion, then let them try. */
368 if (tilde_expansion_failure_hook)
369 {
370 expansion = (*tilde_expansion_failure_hook) (username);
371 if (expansion)
372 {
373 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
374 free (expansion);
375 }
376 }
377 free (username);
378 /* If we don't have a failure hook, or if the failure hook did not
379 expand the tilde, return a copy of what we were passed. */
380 if (dirname == 0)
381 dirname = savestring (filename)xstrdup(filename);
382 }
383 else
384 {
385 free (username);
386 dirname = glue_prefix_and_suffix (user_entry->pw_dir, filename, user_len);
387 }
388
389 endpwent ();
390 return (dirname);
391}
392
393
394#if defined (TEST)
395#undef NULL((void *)0)
396#include <stdio.h>
397
398main (argc, argv)
399 int argc;
400 char **argv;
401{
402 char *result, line[512];
403 int done = 0;
404
405 while (!done)
406 {
407 printf ("~expand: ");
408 fflush (stdout(&__sF[1]));
409
410 if (!fgets (line, sizeof(line), stdin(&__sF[0])))
411 strlcpy (line, "done", sizeof(line));
412 else if (line[strlen(line) - 1] == '\n')
413 line[strlen(line) - 1] = '\0';
414 if ((strcmp (line, "done") == 0) ||
415 (strcmp (line, "quit") == 0) ||
416 (strcmp (line, "exit") == 0))
417 {
418 done = 1;
419 break;
420 }
421
422 result = tilde_expand (line);
423 printf (" --> %s\n", result);
424 free (result);
425 }
426 exit (0);
427}
428
429static void memory_error_and_abort ();
430
431static void *
432xmalloc (bytes)
433 size_t bytes;
434{
435 void *temp = (char *)malloc (bytes);
436
437 if (!temp)
438 memory_error_and_abort ();
439 return (temp);
440}
441
442static void *
443xrealloc (pointer, bytes)
444 void *pointer;
445 int bytes;
446{
447 void *temp;
448
449 if (!pointer)
450 temp = malloc (bytes);
451 else
452 temp = realloc (pointer, bytes);
453
454 if (!temp)
455 memory_error_and_abort ();
456
457 return (temp);
458}
459
460static void
461memory_error_and_abort ()
462{
463 fprintf (stderr(&__sF[2]), "readline: out of virtual memory\n");
464 abort ();
465}
466
467/*
468 * Local variables:
469 * compile-command: "gcc -g -DTEST -o tilde tilde.c"
470 * end:
471 */
472#endif /* TEST */