Bug Summary

File:src/usr.bin/ctfconv/generate.c
Warning:line 220, column 22
Access to field 'it_idx' results in a dereference of a null pointer (loaded from field 'it_refp')

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 generate.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/ctfconv/obj -resource-dir /usr/local/lib/clang/13.0.0 -D ZLIB -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused -Wno-unused-parameter -fdebug-compilation-dir=/usr/src/usr.bin/ctfconv/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/ctfconv/generate.c
1/* $OpenBSD: generate.c,v 1.4 2017/09/26 08:16:18 mpi Exp $ */
2
3/*
4 * Copyright (c) 2017 Martin Pieuchot
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/queue.h>
21#include <sys/tree.h>
22#include <sys/ctf.h>
23
24#include <assert.h>
25#include <err.h>
26#include <fcntl.h>
27#include <string.h>
28#include <stdlib.h>
29#include <stddef.h>
30#include <stdint.h>
31#include <unistd.h>
32
33#ifdef ZLIB1
34#include <zlib.h>
35#endif /* ZLIB */
36
37#include "itype.h"
38#include "xmalloc.h"
39#include "hash.h"
40
41#define ROUNDUP(x, y)((((x) + (y) - 1) / (y)) * (y)) ((((x) + (y) - 1) / (y)) * (y))
42
43/*
44 * Dynamic buffer, used for content & string table.
45 */
46struct dbuf {
47 char *data; /* start data buffer */
48 size_t size; /* size of the buffer */
49
50 char *cptr; /* position in [data, data + size] */
51 size_t coff; /* number of written bytes */
52};
53
54#define DBUF_CHUNKSZ(64 * 1024) (64 * 1024)
55
56/* In-memory representation of a CTF section. */
57struct imcs {
58 struct dbuf body;
59 struct dbuf stab; /* corresponding string table */
60 struct hash *htab; /* hash table of known strings */
61};
62
63struct strentry {
64 struct hash_entry se_key; /* Must be first */
65#define se_strse_key.hkey se_key.hkey
66 size_t se_off;
67};
68
69#ifdef ZLIB1
70char *data_compress(const char *, size_t, off_t, size_t *);
71#endif /* ZLIB */
72
73void
74dbuf_realloc(struct dbuf *dbuf, size_t len)
75{
76 assert(dbuf != NULL)((dbuf != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c"
, 76, __func__, "dbuf != NULL"))
;
77 assert(len != 0)((len != 0) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c"
, 77, __func__, "len != 0"))
;
78
79 dbuf->data = xrealloc(dbuf->data, dbuf->size + len);
80 dbuf->size += len;
81 dbuf->cptr = dbuf->data + dbuf->coff;
82}
83
84void
85dbuf_copy(struct dbuf *dbuf, void const *data, size_t len)
86{
87 off_t left;
88
89 assert(dbuf->cptr != NULL)((dbuf->cptr != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c"
, 89, __func__, "dbuf->cptr != NULL"))
;
90 assert(dbuf->data != NULL)((dbuf->data != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c"
, 90, __func__, "dbuf->data != NULL"))
;
91 assert(dbuf->size != 0)((dbuf->size != 0) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c"
, 91, __func__, "dbuf->size != 0"))
;
92
93 if (len == 0)
94 return;
95
96 left = dbuf->size - dbuf->coff;
97 if (left < (off_t)len)
98 dbuf_realloc(dbuf, ROUNDUP((len - left), DBUF_CHUNKSZ)(((((len - left)) + ((64 * 1024)) - 1) / ((64 * 1024))) * ((64
* 1024)))
);
99
100 memcpy(dbuf->cptr, data, len);
101 dbuf->cptr += len;
102 dbuf->coff += len;
103}
104
105size_t
106dbuf_pad(struct dbuf *dbuf, int align)
107{
108 int i = (align - (dbuf->coff % align)) % align;
109
110 while (i-- > 0)
111 dbuf_copy(dbuf, "", 1);
112
113 return dbuf->coff;
114}
115
116size_t
117imcs_add_string(struct imcs *imcs, const char *str)
118{
119 struct strentry *se;
120 unsigned int slot;
121
122 if (str == NULL((void*)0) || *str == '\0')
123 return 0;
124
125 se = (struct strentry *)hash_find(imcs->htab, str, &slot);
126 if (se == NULL((void*)0)) {
127 se = xmalloc(sizeof(*se));
128 hash_insert(imcs->htab, slot, &se->se_key, str);
129 se->se_off = imcs->stab.coff;
130
131 dbuf_copy(&imcs->stab, str, strlen(str) + 1);
132 }
133
134 return se->se_off;
135}
136
137void
138imcs_add_func(struct imcs *imcs, struct itype *it)
139{
140 uint16_t func, arg;
141 struct imember *im;
142 int kind, root, vlen;
143
144 vlen = it->it_nelems;
145 kind = it->it_type;
146 root = 0;
147
148 func = (kind << 11) | (root << 10) | (vlen & CTF_MAX_VLEN0x03ff);
149 dbuf_copy(&imcs->body, &func, sizeof(func));
150
151 if (kind == CTF_K_UNKNOWN0)
152 return;
153
154 func = it->it_refp->it_idx;
155 dbuf_copy(&imcs->body, &func, sizeof(func));
156
157 TAILQ_FOREACH(im, &it->it_members, im_next)for((im) = ((&it->it_members)->tqh_first); (im) != (
(void*)0); (im) = ((im)->im_next.tqe_next))
{
158 arg = im->im_refp->it_idx;
159 dbuf_copy(&imcs->body, &arg, sizeof(arg));
160 }
161}
162
163void
164imcs_add_obj(struct imcs *imcs, struct itype *it)
165{
166 uint16_t type;
167
168 type = it->it_refp->it_idx;
169 dbuf_copy(&imcs->body, &type, sizeof(type));
170}
171
172void
173imcs_add_type(struct imcs *imcs, struct itype *it)
174{
175 struct imember *im;
176 struct ctf_type ctt;
177 struct ctf_array cta;
178 unsigned int eob;
179 uint32_t size;
180 uint16_t arg;
181 size_t ctsz;
182 int kind, root, vlen;
183
184 assert(it->it_type != CTF_K_UNKNOWN && it->it_type != CTF_K_FORWARD)((it->it_type != 0 && it->it_type != 9) ? (void
)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c", 184, __func__
, "it->it_type != CTF_K_UNKNOWN && it->it_type != CTF_K_FORWARD"
))
;
15
Assuming field 'it_type' is not equal to 0
16
Assuming field 'it_type' is not equal to 9
17
'?' condition is true
185
186 vlen = it->it_nelems;
187 size = it->it_size;
188 kind = it->it_type;
189 root = 0;
190
191 ctt.ctt_name_ctt_stype.cts_name = imcs_add_string(imcs, it_name(it));
18
Value assigned to field 'it_refp'
192 ctt.ctt_info_ctt_stype.cts_info = (kind << 11) | (root << 10) | (vlen & CTF_MAX_VLEN0x03ff);
193
194 /* Base types don't have reference, typedef & pointer don't have size */
195 if (it->it_refp != NULL((void*)0) && kind != CTF_K_ARRAY4) {
19
Assuming field 'it_refp' is equal to NULL
196 ctt.ctt_type_ctt_stype._ST._type = it->it_refp->it_idx;
197 ctsz = sizeof(struct ctf_stype);
198 } else if (size <= CTF_MAX_SIZE0xfffe) {
20
Assuming 'size' is <= CTF_MAX_SIZE
21
Taking true branch
199 ctt.ctt_size_ctt_stype._ST._size = size;
200 ctsz = sizeof(struct ctf_stype);
201 } else {
202 ctt.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size)((uint32_t)((uint64_t)(size) >> 32));
203 ctt.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size)((uint32_t)(size));
204 ctt.ctt_size_ctt_stype._ST._size = CTF_LSIZE_SENT0xfffe +1;
205 ctsz = sizeof(struct ctf_type);
206 }
207
208 dbuf_copy(&imcs->body, &ctt, ctsz);
209
210 switch (kind) {
22
Control jumps to 'case 4:' at line 218
211 assert(1 == 0)((1 == 0) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c"
, 211, __func__, "1 == 0"))
;
212 break;
213 case CTF_K_INTEGER1:
214 case CTF_K_FLOAT2:
215 eob = CTF_INT_DATA(it->it_enc, 0, size)(((it->it_enc) << 24) | ((0) << 16) | (size));
216 dbuf_copy(&imcs->body, &eob, sizeof(eob));
217 break;
218 case CTF_K_ARRAY4:
219 memset(&cta, 0, sizeof(cta));
220 cta.cta_contents = it->it_refp->it_idx;
23
Access to field 'it_idx' results in a dereference of a null pointer (loaded from field 'it_refp')
221 cta.cta_index = long_tidx;
222 cta.cta_nelems = it->it_nelems;
223 dbuf_copy(&imcs->body, &cta, sizeof(cta));
224 break;
225 case CTF_K_STRUCT6:
226 case CTF_K_UNION7:
227 if (size < CTF_LSTRUCT_THRESH8192) {
228 struct ctf_member ctm;
229
230 memset(&ctm, 0, sizeof(ctm));
231 TAILQ_FOREACH(im, &it->it_members, im_next)for((im) = ((&it->it_members)->tqh_first); (im) != (
(void*)0); (im) = ((im)->im_next.tqe_next))
{
232 ctm.ctm_name =
233 imcs_add_string(imcs, im_name(im));
234 ctm.ctm_type = im->im_refp->it_idx;
235 ctm.ctm_offset = im->im_off;
236
237 dbuf_copy(&imcs->body, &ctm, sizeof(ctm));
238 }
239 } else {
240 struct ctf_lmember ctlm;
241
242 memset(&ctlm, 0, sizeof(ctlm));
243 TAILQ_FOREACH(im, &it->it_members, im_next)for((im) = ((&it->it_members)->tqh_first); (im) != (
(void*)0); (im) = ((im)->im_next.tqe_next))
{
244 ctlm.ctlm_name_ctlm_member.ctm_name =
245 imcs_add_string(imcs, im_name(im));
246 ctlm.ctlm_type_ctlm_member.ctm_type = im->im_refp->it_idx;
247 ctlm.ctlm_offsethi =
248 CTF_OFFSET_TO_LMEMHI(im->im_off)((uint32_t)((uint64_t)(im->im_off) >> 32));
249 ctlm.ctlm_offsetlo =
250 CTF_OFFSET_TO_LMEMLO(im->im_off)((uint32_t)(im->im_off));
251
252
253 dbuf_copy(&imcs->body, &ctlm, sizeof(ctlm));
254 }
255 }
256 break;
257 case CTF_K_FUNCTION5:
258 TAILQ_FOREACH(im, &it->it_members, im_next)for((im) = ((&it->it_members)->tqh_first); (im) != (
(void*)0); (im) = ((im)->im_next.tqe_next))
{
259 arg = im->im_refp->it_idx;
260 dbuf_copy(&imcs->body, &arg, sizeof(arg));
261 }
262 if (vlen & 1) {
263 arg = 0;
264 dbuf_copy(&imcs->body, &arg, sizeof(arg));
265 }
266 break;
267 case CTF_K_ENUM8:
268 TAILQ_FOREACH(im, &it->it_members, im_next)for((im) = ((&it->it_members)->tqh_first); (im) != (
(void*)0); (im) = ((im)->im_next.tqe_next))
{
269 struct ctf_enum cte;
270
271 cte.cte_name = imcs_add_string(imcs, im_name(im));
272 cte.cte_value = im->im_ref;
273
274 dbuf_copy(&imcs->body, &cte, sizeof(cte));
275 }
276 break;
277 case CTF_K_POINTER3:
278 case CTF_K_TYPEDEF10:
279 case CTF_K_VOLATILE11:
280 case CTF_K_CONST12:
281 case CTF_K_RESTRICT13:
282 default:
283 break;
284 }
285}
286
287void
288imcs_generate(struct imcs *imcs, struct ctf_header *cth, const char *label)
289{
290 struct itype *it;
291 struct ctf_lblent lbl;
292
293 memset(imcs, 0, sizeof(*imcs));
294
295 dbuf_realloc(&imcs->body, DBUF_CHUNKSZ(64 * 1024));
296 dbuf_realloc(&imcs->stab, DBUF_CHUNKSZ(64 * 1024));
297
298 imcs->htab = hash_init(10);
299 if (imcs->htab == NULL((void*)0))
4
Assuming field 'htab' is not equal to NULL
5
Taking false branch
300 err(1, "hash_init");
301
302 /* Add empty string */
303 dbuf_copy(&imcs->stab, "", 1);
304
305 /* We don't use parent label */
306 cth->cth_parlabel = 0;
307 cth->cth_parname = 0;
308
309 /* Insert a single label for all types. */
310 cth->cth_lbloff = 0;
311 lbl.ctl_label = imcs_add_string(imcs, label);
312 lbl.ctl_typeidx = tidx;
313 dbuf_copy(&imcs->body, &lbl, sizeof(lbl));
314
315 /* Insert objects */
316 cth->cth_objtoff = dbuf_pad(&imcs->body, 2);
317 TAILQ_FOREACH(it, &iobjq, it_symb)for((it) = ((&iobjq)->tqh_first); (it) != ((void*)0); (
it) = ((it)->it_symb.tqe_next))
6
Assuming 'it' is equal to null
7
Loop condition is false. Execution continues on line 321
318 imcs_add_obj(imcs, it);
319
320 /* Insert functions */
321 cth->cth_funcoff = dbuf_pad(&imcs->body, 2);
322 TAILQ_FOREACH(it, &ifuncq, it_symb)for((it) = ((&ifuncq)->tqh_first); (it) != ((void*)0);
(it) = ((it)->it_symb.tqe_next))
8
Assuming 'it' is equal to null
9
Loop condition is false. Execution continues on line 326
323 imcs_add_func(imcs, it);
324
325 /* Insert types */
326 cth->cth_typeoff = dbuf_pad(&imcs->body, 4);
327 TAILQ_FOREACH(it, &itypeq, it_next)for((it) = ((&itypeq)->tqh_first); (it) != ((void*)0);
(it) = ((it)->it_next.tqe_next))
{
10
Assuming 'it' is not equal to null
11
Loop condition is true. Entering loop body
328 if (it->it_flags & (ITF_FUNC0x04|ITF_OBJ0x08))
12
Assuming the condition is false
13
Taking false branch
329 continue;
330
331 imcs_add_type(imcs, it);
14
Calling 'imcs_add_type'
332 }
333
334 /* String table is written from its own buffer. */
335 cth->cth_stroff = imcs->body.coff;
336 cth->cth_strlen = imcs->stab.coff;
337}
338
339/*
340 * Generate a CTF buffer from the internal type representation.
341 */
342int
343generate(const char *path, const char *label, int compress)
344{
345 char *p, *ctfdata = NULL((void*)0);
346 ssize_t ctflen;
347 struct ctf_header cth;
348 struct imcs imcs;
349 int error = 0, fd;
350
351 memset(&cth, 0, sizeof(cth));
352
353 cth.cth_magic = CTF_MAGIC0xcff1;
354 cth.cth_version = CTF_VERSION2;
355
356#ifdef ZLIB1
357 if (compress)
1
Assuming 'compress' is 0
2
Taking false branch
358 cth.cth_flags = CTF_F_COMPRESS(1 << 0);
359#endif /* ZLIB */
360
361 imcs_generate(&imcs, &cth, label);
3
Calling 'imcs_generate'
362
363 ctflen = sizeof(cth) + imcs.body.coff + imcs.stab.coff;
364 p = ctfdata = xmalloc(ctflen);
365
366 memcpy(p, &cth, sizeof(cth));
367 p += sizeof(cth);
368
369 memcpy(p, imcs.body.data, imcs.body.coff);
370 p += imcs.body.coff;
371
372 memcpy(p, imcs.stab.data, imcs.stab.coff);
373 p += imcs.stab.coff;
374
375 assert((p - ctfdata) == ctflen)(((p - ctfdata) == ctflen) ? (void)0 : __assert2("/usr/src/usr.bin/ctfconv/generate.c"
, 375, __func__, "(p - ctfdata) == ctflen"))
;
376
377#ifdef ZLIB1
378 if (compress) {
379 char *cdata;
380 size_t clen;
381
382 cdata = data_compress(ctfdata + sizeof(cth),
383 ctflen - sizeof(cth), ctflen - sizeof(cth), &clen);
384 if (cdata == NULL((void*)0)) {
385 warnx("compressing CTF data");
386 free(ctfdata);
387 return -1;
388 }
389
390 memcpy(ctfdata + sizeof(cth), cdata, clen);
391 ctflen = clen + sizeof(cth);
392
393 free(cdata);
394 }
395#endif /* ZLIB */
396
397 fd = open(path, O_WRONLY0x0001 | O_CREAT0x0200 | O_TRUNC0x0400, 0644);
398 if (fd == -1) {
399 warn("open %s", path);
400 free(ctfdata);
401 return -1;
402 }
403
404 if (write(fd, ctfdata, ctflen) != ctflen) {
405 warn("unable to write %zd bytes for %s", ctflen, path);
406 error = -1;
407 }
408
409 close(fd);
410 free(ctfdata);
411 return error;
412}
413
414#ifdef ZLIB1
415char *
416data_compress(const char *buf, size_t size, off_t len, size_t *pclen)
417{
418 z_stream stream;
419 char *data;
420 int error;
421
422 data = malloc(len);
423 if (data == NULL((void*)0)) {
424 warn(NULL((void*)0));
425 return NULL((void*)0);
426 }
427
428 memset(&stream, 0, sizeof(stream));
429 stream.zalloc = Z_NULL0;
430 stream.zfree = Z_NULL0;
431 stream.opaque = Z_NULL0;
432
433 if ((error = deflateInit(&stream, Z_BEST_COMPRESSION)deflateInit_((&stream), (9), "1.2.11", (int)sizeof(z_stream
))
) != Z_OK0) {
434 warnx("zlib deflateInit failed: %s", zError(error));
435 goto exit;
436 }
437
438 stream.next_in = (void *)buf;
439 stream.avail_in = size;
440 stream.next_out = (unsigned char *)data;
441 stream.avail_out = len;
442
443 if ((error = deflate(&stream, Z_FINISH4)) != Z_STREAM_END1) {
444 warnx("zlib deflate failed: %s", zError(error));
445 deflateEnd(&stream);
446 goto exit;
447 }
448
449 if ((error = deflateEnd(&stream)) != Z_OK0) {
450 warnx("zlib deflateEnd failed: %s", zError(error));
451 goto exit;
452 }
453
454 if (pclen != NULL((void*)0))
455 *pclen = stream.total_out;
456
457 return data;
458
459exit:
460 free(data);
461 return NULL((void*)0);
462}
463#endif /* ZLIB */