Bug Summary

File:src/lib/libelf/libelf_ar_util.c
Warning:line 55, column 18
Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c'

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 libelf_ar_util.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/libelf/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/lib/libelf -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libelf/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/libelf/libelf_ar_util.c
1/*-
2 * Copyright (c) 2006,2009,2010 Joseph Koshy
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <assert.h>
28#include <libelf.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include "_libelf.h"
33#include "_libelf_ar.h"
34
35ELFTC_VCSID("$Id: libelf_ar_util.c,v 1.1 2019/02/01 05:27:38 jsg Exp $")__asm__(".ident\t\"" "$Id: libelf_ar_util.c,v 1.1 2019/02/01 05:27:38 jsg Exp $"
"\"")
;
36
37/*
38 * Convert a string bounded by `start' and `start+sz' (exclusive) to a
39 * number in the specified base.
40 */
41int
42_libelf_ar_get_number(const char *src, size_t sz, unsigned int base,
43 size_t *ret)
44{
45 size_t r;
46 unsigned int c, v;
47 const unsigned char *e, *s;
48
49 assert(base <= 10)((base <= 10) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c"
, 49, __func__, "base <= 10"))
;
50
51 s = (const unsigned char *) src;
52 e = s + sz;
53
54 /* skip leading blanks */
55 for (;s < e && (c = *s) == ' '; s++)
Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c'
56 ;
57
58 r = 0L;
59 for (;s < e; s++) {
60 if ((c = *s) == ' ')
61 break;
62 if (c < '0' || c > '9')
63 return (0);
64 v = c - '0';
65 if (v >= base) /* Illegal digit. */
66 break;
67 r *= base;
68 r += v;
69 }
70
71 *ret = r;
72
73 return (1);
74}
75
76/*
77 * Return the translated name for an archive member.
78 */
79char *
80_libelf_ar_get_translated_name(const struct ar_hdr *arh, Elf *ar)
81{
82 char *s;
83 unsigned char c;
84 size_t len, offset;
85 const unsigned char *buf, *p, *q, *r;
86 const size_t bufsize = sizeof(arh->ar_name);
87
88 assert(arh != NULL)((arh != ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c"
, 88, __func__, "arh != NULL"))
;
89 assert(ar->e_kind == ELF_K_AR)((ar->e_kind == ELF_K_AR) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c"
, 89, __func__, "ar->e_kind == ELF_K_AR"))
;
90 assert((const unsigned char *) arh >= ar->e_rawfile &&(((const unsigned char *) arh >= ar->e_rawfile &&
(const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize
) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c"
, 91, __func__, "(const unsigned char *) arh >= ar->e_rawfile && (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize"
))
91 (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize)(((const unsigned char *) arh >= ar->e_rawfile &&
(const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize
) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c"
, 91, __func__, "(const unsigned char *) arh >= ar->e_rawfile && (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize"
))
;
92
93 buf = (const unsigned char *) arh->ar_name;
94
95 /*
96 * Check for extended naming.
97 *
98 * If the name matches the pattern "^/[0-9]+", it is an
99 * SVR4-style extended name. If the name matches the pattern
100 * "#1/[0-9]+", the entry uses BSD style extended naming.
101 */
102 if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') {
103 /*
104 * The value in field ar_name is a decimal offset into
105 * the archive string table where the actual name
106 * resides.
107 */
108 if (_libelf_ar_get_number((const char *) (buf + 1),
109 bufsize - 1, 10, &offset) == 0) {
110 LIBELF_SET_ERROR(ARCHIVE, 0)do { (_libelf.libelf_error) = (((ELF_E_ARCHIVE) & 0xFF) |
(((0)) << 8)); } while (0)
;
111 return (NULL((void *)0));
112 }
113
114 if (offset > ar->e_u.e_ar.e_rawstrtabsz) {
115 LIBELF_SET_ERROR(ARCHIVE, 0)do { (_libelf.libelf_error) = (((ELF_E_ARCHIVE) & 0xFF) |
(((0)) << 8)); } while (0)
;
116 return (NULL((void *)0));
117 }
118
119 p = q = ar->e_u.e_ar.e_rawstrtab + offset;
120 r = ar->e_u.e_ar.e_rawstrtab + ar->e_u.e_ar.e_rawstrtabsz;
121
122 for (; p < r && *p != '/'; p++)
123 ;
124 len = (size_t) (p - q + 1); /* space for the trailing NUL */
125
126 if ((s = malloc(len)) == NULL((void *)0)) {
127 LIBELF_SET_ERROR(RESOURCE, 0)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) |
(((0)) << 8)); } while (0)
;
128 return (NULL((void *)0));
129 }
130
131 (void) strncpy(s, (const char *) q, len - 1);
132 s[len - 1] = '\0';
133
134 return (s);
135 } else if (IS_EXTENDED_BSD_NAME(buf)(strncmp((const char *) (buf), "#1/", (sizeof("#1/") - 1)) ==
0)
) {
136 r = buf + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE(sizeof("#1/") - 1);
137
138 if (_libelf_ar_get_number((const char *) r, bufsize -
139 LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE(sizeof("#1/") - 1), 10,
140 &len) == 0) {
141 LIBELF_SET_ERROR(ARCHIVE, 0)do { (_libelf.libelf_error) = (((ELF_E_ARCHIVE) & 0xFF) |
(((0)) << 8)); } while (0)
;
142 return (NULL((void *)0));
143 }
144
145 /*
146 * Allocate space for the file name plus a
147 * trailing NUL.
148 */
149 if ((s = malloc(len + 1)) == NULL((void *)0)) {
150 LIBELF_SET_ERROR(RESOURCE, 0)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) |
(((0)) << 8)); } while (0)
;
151 return (NULL((void *)0));
152 }
153
154 /*
155 * The file name follows the archive header.
156 */
157 q = (const unsigned char *) (arh + 1);
158
159 (void) strncpy(s, (const char *) q, len);
160 s[len] = '\0';
161
162 return (s);
163 }
164
165 /*
166 * A 'normal' name.
167 *
168 * Skip back over trailing blanks from the end of the field.
169 * In the SVR4 format, a '/' is used as a terminator for
170 * non-special names.
171 */
172 for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q)
173 ;
174
175 if (q >= buf) {
176 if (*q == '/') {
177 /*
178 * SVR4 style names: ignore the trailing
179 * character '/', but only if the name is not
180 * one of the special names "/" and "//".
181 */
182 if (q > buf + 1 ||
183 (q == (buf + 1) && *buf != '/'))
184 q--;
185 }
186
187 len = (size_t) (q - buf + 2); /* Space for a trailing NUL. */
188 } else {
189 /* The buffer only had blanks. */
190 buf = (const unsigned char *) "";
191 len = 1;
192 }
193
194 if ((s = malloc(len)) == NULL((void *)0)) {
195 LIBELF_SET_ERROR(RESOURCE, 0)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) |
(((0)) << 8)); } while (0)
;
196 return (NULL((void *)0));
197 }
198
199 (void) strncpy(s, (const char *) buf, len - 1);
200 s[len - 1] = '\0';
201
202 return (s);
203}
204
205/*
206 * Return the raw name for an archive member, inclusive of any
207 * formatting characters.
208 */
209char *
210_libelf_ar_get_raw_name(const struct ar_hdr *arh)
211{
212 char *rawname;
213 const size_t namesz = sizeof(arh->ar_name);
214
215 if ((rawname = malloc(namesz + 1)) == NULL((void *)0)) {
216 LIBELF_SET_ERROR(RESOURCE, 0)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) |
(((0)) << 8)); } while (0)
;
217 return (NULL((void *)0));
218 }
219
220 (void) strncpy(rawname, arh->ar_name, namesz);
221 rawname[namesz] = '\0';
222 return (rawname);
223}
224
225/*
226 * Open an 'ar' archive.
227 */
228Elf *
229_libelf_ar_open(Elf *e, int reporterror)
230{
231 size_t sz;
232 int scanahead;
233 struct ar_hdr arh;
234 unsigned char *s, *end;
235
236 _libelf_init_elf(e, ELF_K_AR);
237
238 e->e_u.e_ar.e_nchildren = 0;
239 e->e_u.e_ar.e_next = (off_t) -1;
240
241 /*
242 * Look for special members.
243 */
244
245 s = e->e_rawfile + SARMAG8;
246 end = e->e_rawfile + e->e_rawsize;
247
248 assert(e->e_rawsize > 0)((e->e_rawsize > 0) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c"
, 248, __func__, "e->e_rawsize > 0"))
;
249
250 /*
251 * We use heuristics to determine the flavor of the archive we
252 * are examining.
253 *
254 * SVR4 flavor archives use the name "/ " and "// " for
255 * special members.
256 *
257 * In BSD flavor archives the symbol table, if present, is the
258 * first archive with name "__.SYMDEF".
259 */
260
261#define READ_AR_HEADER(S, ARH, SZ, END)do { if ((S) + sizeof((ARH)) > (END)) goto error; (void) memcpy
(&(ARH), (S), sizeof((ARH))); if ((ARH).ar_fmag[0] != '`'
|| (ARH).ar_fmag[1] != '\n') goto error; if (_libelf_ar_get_number
((char *) (ARH).ar_size, sizeof((ARH).ar_size), 10, &(SZ)
) == 0) goto error; } while (0)
\
262 do { \
263 if ((S) + sizeof((ARH)) > (END)) \
264 goto error; \
265 (void) memcpy(&(ARH), (S), sizeof((ARH))); \
266 if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \
267 goto error; \
268 if (_libelf_ar_get_number((char *) (ARH).ar_size, \
269 sizeof((ARH).ar_size), 10, &(SZ)) == 0) \
270 goto error; \
271 } while (0)
272
273 READ_AR_HEADER(s, arh, sz, end)do { if ((s) + sizeof((arh)) > (end)) goto error; (void) memcpy
(&(arh), (s), sizeof((arh))); if ((arh).ar_fmag[0] != '`'
|| (arh).ar_fmag[1] != '\n') goto error; if (_libelf_ar_get_number
((char *) (arh).ar_size, sizeof((arh).ar_size), 10, &(sz)
) == 0) goto error; } while (0)
;
274
275 /*
276 * Handle special archive members for the SVR4 format.
277 */
278 if (arh.ar_name[0] == '/') {
279 if (sz == 0)
280 goto error;
281
282 e->e_flags |= LIBELF_F_AR_VARIANT_SVR40x020000U;
283
284 scanahead = 0;
285
286 /*
287 * The symbol table (file name "/ ") always comes before the
288 * string table (file name "// ").
289 */
290 if (arh.ar_name[1] == ' ') {
291 /* "/ " => symbol table. */
292 scanahead = 1; /* The string table to follow. */
293
294 s += sizeof(arh);
295 e->e_u.e_ar.e_rawsymtab = s;
296 e->e_u.e_ar.e_rawsymtabsz = sz;
297
298 sz = LIBELF_ADJUST_AR_SIZE(sz)(((sz) + 1U) & ~1U);
299 s += sz;
300
301 } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') {
302 /* "// " => string table for long file names. */
303 s += sizeof(arh);
304 e->e_u.e_ar.e_rawstrtab = s;
305 e->e_u.e_ar.e_rawstrtabsz = sz;
306
307 sz = LIBELF_ADJUST_AR_SIZE(sz)(((sz) + 1U) & ~1U);
308 s += sz;
309 }
310
311 /*
312 * If the string table hasn't been seen yet, look for
313 * it in the next member.
314 */
315 if (scanahead) {
316 READ_AR_HEADER(s, arh, sz, end)do { if ((s) + sizeof((arh)) > (end)) goto error; (void) memcpy
(&(arh), (s), sizeof((arh))); if ((arh).ar_fmag[0] != '`'
|| (arh).ar_fmag[1] != '\n') goto error; if (_libelf_ar_get_number
((char *) (arh).ar_size, sizeof((arh).ar_size), 10, &(sz)
) == 0) goto error; } while (0)
;
317
318 /* "// " => string table for long file names. */
319 if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' &&
320 arh.ar_name[2] == ' ') {
321
322 s += sizeof(arh);
323
324 e->e_u.e_ar.e_rawstrtab = s;
325 e->e_u.e_ar.e_rawstrtabsz = sz;
326
327 sz = LIBELF_ADJUST_AR_SIZE(sz)(((sz) + 1U) & ~1U);
328 s += sz;
329 }
330 }
331 } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME"__.SYMDEF",
332 sizeof(LIBELF_AR_BSD_SYMTAB_NAME"__.SYMDEF") - 1) == 0) {
333 /*
334 * BSD style archive symbol table.
335 */
336 s += sizeof(arh);
337 e->e_u.e_ar.e_rawsymtab = s;
338 e->e_u.e_ar.e_rawsymtabsz = sz;
339
340 sz = LIBELF_ADJUST_AR_SIZE(sz)(((sz) + 1U) & ~1U);
341 s += sz;
342 }
343
344 /*
345 * Update the 'next' offset, so that a subsequent elf_begin()
346 * works as expected.
347 */
348 e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile);
349
350 return (e);
351
352error:
353 if (!reporterror) {
354 e->e_kind = ELF_K_NONE;
355 return (e);
356 }
357
358 LIBELF_SET_ERROR(ARCHIVE, 0)do { (_libelf.libelf_error) = (((ELF_E_ARCHIVE) & 0xFF) |
(((0)) << 8)); } while (0)
;
359 return (NULL((void *)0));
360}