Bug Summary

File:build/gcc/../libgcc/libgcov-driver-system.c
Warning:line 202, column 4
Argument to free() is offset by 1 byte from the start of memory allocated by malloc()

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-suse-linux -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name libgcov-driver.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -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 -analyzer-config-compatibility-mode=true -mrelocation-model static -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/gcc -resource-dir /usr/lib64/clang/15.0.7 -D IN_GCC -D HAVE_CONFIG_H -I . -I . -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/. -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../include -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcpp/include -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcody -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber/bid -I ../libdecnumber -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libbacktrace -I . -I . -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/. -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../include -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcpp/include -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcody -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber/bid -I ../libdecnumber -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libbacktrace -D IN_GCOV_TOOL=1 -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../include/c++/13/x86_64-suse-linux -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../include/c++/13/backward -internal-isystem /usr/lib64/clang/15.0.7/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../x86_64-suse-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-narrowing -Wwrite-strings -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -Wno-error -fdeprecated-macro -fdebug-compilation-dir=/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/gcc -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=plist-html -analyzer-config silence-checkers=core.NullDereference -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /buildworker/marxinbox-gcc-clang-static-analyzer/objdir/clang-static-analyzer/2023-03-27-141847-20772-1/report-mD1uYx.plist -x c++ /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-driver.c

/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-driver.c

1/* Routines required for instrumenting a program. */
2/* Compile this one with gcc. */
3/* Copyright (C) 1989-2023 Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24<http://www.gnu.org/licenses/>. */
25
26#include "libgcov.h"
27#include "gcov-io.h"
28
29/* Return 1, if all counter values are zero, otherwise 0. */
30
31static inline int
32are_all_counters_zero (const struct gcov_ctr_info *ci_ptr)
33{
34 for (unsigned i = 0; i < ci_ptr->num; i++)
35 if (ci_ptr->values[i] != 0)
36 return 0;
37
38 return 1;
39}
40
41#if defined(inhibit_libc)
42/* If libc and its header files are not available, provide dummy functions. */
43
44#if defined(L_gcov1)
45void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
46#endif
47
48#else /* inhibit_libc */
49
50#if GCOV_LOCKED1
51#include <fcntl.h>
52#include <errno(*__errno_location ()).h>
53#include <sys/stat.h>
54#elif GCOV_LOCKED_WITH_LOCKING0
55#include <fcntl.h>
56#include <sys/locking.h>
57#include <sys/stat.h>
58#endif
59
60#if HAVE_SYS_MMAN_H1
61#include <sys/mman.h>
62#endif
63
64#endif /* inhibit_libc */
65
66#if defined(L_gcov1) && !defined(inhibit_libc)
67#define NEED_L_GCOV
68#endif
69
70#if defined(L_gcov_info_to_gcda) && !IN_GCOV_TOOL1
71#define NEED_L_GCOV_INFO_TO_GCDA
72#endif
73
74#ifdef NEED_L_GCOV
75/* A utility function for outputting errors. */
76static int gcov_error (const char *, ...);
77
78#if !IN_GCOV_TOOL1
79static void gcov_error_exit (void);
80#endif
81
82#include "gcov-io.cc"
83
84#define GCOV_PROF_PREFIX"libgcov profiling error:%s:" "libgcov profiling error:%s:"
85
86struct gcov_fn_buffer
87{
88 struct gcov_fn_buffer *next;
89 unsigned fn_ix;
90 struct gcov_fn_info info;
91 /* note gcov_fn_info ends in a trailing array. */
92};
93
94struct gcov_summary_buffer
95{
96 struct gcov_summary_buffer *next;
97 struct gcov_summary summary;
98};
99
100/* A struct that bundles all the related information about the
101 gcda filename. */
102
103struct gcov_filename
104{
105 char *filename; /* filename buffer */
106 int strip; /* leading chars to strip from filename */
107 char *prefix; /* prefix string */
108};
109
110static struct gcov_fn_buffer *
111free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
112 unsigned limit)
113{
114 struct gcov_fn_buffer *next;
115 unsigned ix, n_ctr = 0;
116
117 if (!buffer)
118 return 0;
119 next = buffer->next;
120
121 for (ix = 0; ix != limit; ix++)
122 if (gi_ptr->merge[ix])
123 free (buffer->info.ctrs[n_ctr++].values);
124 free (buffer);
125 return next;
126}
127
128static struct gcov_fn_buffer **
129buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
130 struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
131{
132 unsigned n_ctrs = 0, ix = 0;
133 struct gcov_fn_buffer *fn_buffer;
134 unsigned len;
135
136 for (ix = GCOV_COUNTERS; ix--;)
137 if (gi_ptr->merge[ix])
138 n_ctrs++;
139
140 len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
141 fn_buffer = (struct gcov_fn_buffer *) xmallocmalloc (len);
142
143 if (!fn_buffer)
144 goto fail;
145
146 fn_buffer->next = 0;
147 fn_buffer->fn_ix = fn_ix;
148 fn_buffer->info.ident = gcov_read_unsigned ();
149 fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
150 fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
151
152 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
153 {
154 gcov_unsigned_t length;
155 gcov_type *values;
156
157 if (!gi_ptr->merge[ix])
158 continue;
159
160 if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix)(((gcov_unsigned_t)0x01a10000) + ((gcov_unsigned_t)(ix) <<
17))
)
161 {
162 len = 0;
163 goto fail;
164 }
165
166 length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ())((gcov_read_unsigned () / 4) / 2);
167 len = length * sizeof (gcov_type);
168 values = (gcov_type *) xmallocmalloc (len);
169 if (!values)
170 goto fail;
171
172 fn_buffer->info.ctrs[n_ctrs].num = length;
173 fn_buffer->info.ctrs[n_ctrs].values = values;
174
175 while (length--)
176 *values++ = gcov_read_counter ();
177 n_ctrs++;
178 }
179
180 *end_ptr = fn_buffer;
181 return &fn_buffer->next;
182
183fail:
184 gcov_error (GCOV_PROF_PREFIX"libgcov profiling error:%s:" "Function %u %s %u \n", filename, fn_ix,
185 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
186
187 return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
188}
189
190/* Convert VERSION into a string description and return the it.
191 BUFFER is used for storage of the string. The code should be
192 aligned wit gcov-iov.c. */
193
194static char *
195gcov_version_string (char *buffer, char version[4])
196{
197 if (version[0] < 'A' || version[0] > 'Z'
198 || version[1] < '0' || version[1] > '9'
199 || version[2] < '0' || version[2] > '9')
200 sprintf (buffer, "(unknown)");
201 else
202 {
203 unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
204 unsigned minor = version[2] - '0';
205 sprintf (buffer, "%u.%u (%s)", major, minor,
206 version[3] == '*' ? "release" : "experimental");
207 }
208 return buffer;
209}
210
211/* Check if VERSION of the info block PTR matches libgcov one.
212 Return 1 on success, or zero in case of versions mismatch.
213 If FILENAME is not NULL, its value used for reporting purposes
214 instead of value from the info block. */
215
216static int
217gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
218 const char *filename)
219{
220 if (version != GCOV_VERSION((gcov_unsigned_t)0x42333020))
221 {
222 char v[4], e[4];
223 char ver_string[128], expected_string[128];
224
225 GCOV_UNSIGNED2STRING (v, version)((v)[0] = (char)((version) >> 24), (v)[1] = (char)((version
) >> 16), (v)[2] = (char)((version) >> 8), (v)[3]
= (char)((version) >> 0))
;
226 GCOV_UNSIGNED2STRING (e, GCOV_VERSION)((e)[0] = (char)((((gcov_unsigned_t)0x42333020)) >> 24)
, (e)[1] = (char)((((gcov_unsigned_t)0x42333020)) >> 16
), (e)[2] = (char)((((gcov_unsigned_t)0x42333020)) >> 8
), (e)[3] = (char)((((gcov_unsigned_t)0x42333020)) >> 0
))
;
227
228 gcov_error (GCOV_PROF_PREFIX"libgcov profiling error:%s:" "Version mismatch - expected %s (%.4s) "
229 "got %s (%.4s)\n",
230 filename? filename : ptr->filename,
231 gcov_version_string (expected_string, e), e,
232 gcov_version_string (ver_string, v), v);
233 return 0;
234 }
235 return 1;
236}
237
238/* buffer for the fn_data from another program. */
239static struct gcov_fn_buffer *fn_buffer;
240
241/* Including system dependent components. */
242#include "libgcov-driver-system.c"
243
244/* This function merges counters in GI_PTR to an existing gcda file.
245 Return 0 on success.
246 Return -1 on error. In this case, caller will goto read_fatal. */
247
248static int
249merge_one_data (const char *filename,
250 struct gcov_info *gi_ptr,
251 struct gcov_summary *summary)
252{
253 gcov_unsigned_t tag, length;
254 unsigned t_ix;
255 int f_ix = -1;
256 int error = 0;
257 struct gcov_fn_buffer **fn_tail = &fn_buffer;
258
259 length = gcov_read_unsigned ();
260 if (!gcov_version (gi_ptr, length, filename))
261 return -1;
262
263 /* Skip timestamp. */
264 gcov_read_unsigned ();
265
266 length = gcov_read_unsigned ();
267 if (length != gi_ptr->checksum)
268 {
269 /* Read from a different compilation. Overwrite the file. */
270 gcov_error (GCOV_PROF_PREFIX"libgcov profiling error:%s:" "overwriting an existing profile data "
271 "with a different checksum\n", filename);
272 return 0;
273 }
274
275 tag = gcov_read_unsigned ();
276 if (tag != GCOV_TAG_OBJECT_SUMMARY((gcov_unsigned_t)0xa1000000))
277 goto read_mismatch;
278 length = gcov_read_unsigned ();
279 gcc_assert (length > 0)((void)(!(length > 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-driver.c"
, 279, __FUNCTION__), 0 : 0))
;
280 gcov_read_summary (summary);
281
282 tag = gcov_read_unsigned ();
283 /* Merge execution counts for each function. */
284 for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
285 f_ix++, tag = gcov_read_unsigned ())
286 {
287 const struct gcov_ctr_info *ci_ptr;
288 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
289
290 if (tag != GCOV_TAG_FUNCTION((gcov_unsigned_t)0x01000000))
291 goto read_mismatch;
292
293 length = gcov_read_unsigned ();
294 if (!length)
295 /* This function did not appear in the other program.
296 We have nothing to merge. */
297 continue;
298
299 if (length != GCOV_TAG_FUNCTION_LENGTH(3 * 4))
300 goto read_mismatch;
301
302 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
303 {
304 /* This function appears in the other program. We
305 need to buffer the information in order to write
306 it back out -- we'll be inserting data before
307 this point, so cannot simply keep the data in the
308 file. */
309 fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
310 if (!fn_tail)
311 goto read_mismatch;
312 continue;
313 }
314
315 length = gcov_read_unsigned ();
316 if (length != gfi_ptr->ident)
317 goto read_mismatch;
318
319 length = gcov_read_unsigned ();
320 if (length != gfi_ptr->lineno_checksum)
321 goto read_mismatch;
322
323 length = gcov_read_unsigned ();
324 if (length != gfi_ptr->cfg_checksum)
325 goto read_mismatch;
326
327 ci_ptr = gfi_ptr->ctrs;
328 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
329 {
330 gcov_merge_fn merge = gi_ptr->merge[t_ix];
331
332 if (!merge)
333 continue;
334
335 tag = gcov_read_unsigned ();
336 int read_length = (int)gcov_read_unsigned ();
337 length = abs (read_length);
338 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)(((gcov_unsigned_t)0x01a10000) + ((gcov_unsigned_t)(t_ix) <<
17))
339 || (length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num)((ci_ptr->num) * 2 * 4)
340 && t_ix != GCOV_COUNTER_V_TOPN
341 && t_ix != GCOV_COUNTER_V_INDIR))
342 goto read_mismatch;
343 /* Merging with all zero counters does not make sense. */
344 if (read_length > 0)
345 (*merge) (ci_ptr->values, ci_ptr->num);
346 ci_ptr++;
347 }
348 if ((error = gcov_is_error ()))
349 goto read_error;
350 }
351
352 if (tag)
353 {
354 read_mismatch:;
355 gcov_error (GCOV_PROF_PREFIX"libgcov profiling error:%s:" "Merge mismatch for %s %u\n",
356 filename, f_ix >= 0 ? "function" : "summary",
357 f_ix < 0 ? -1 - f_ix : f_ix);
358 return -1;
359 }
360 return 0;
361
362read_error:
363 gcov_error (GCOV_PROF_PREFIX"libgcov profiling error:%s:" "%s merging\n", filename,
364 error < 0 ? "Overflow": "Error");
365 return -1;
366}
367
368/* Write the DATA of LENGTH characters to the gcov file. */
369
370static void
371gcov_dump_handler (const void *data,
372 unsigned length,
373 void *arg ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
374{
375 gcov_write (data, length);
376}
377
378/* Allocate SIZE characters and return the address of the allocated memory. */
379
380static void *
381gcov_allocate_handler (unsigned size, void *arg ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
382{
383 return xmallocmalloc (size);
384}
385#endif /* NEED_L_GCOV */
386
387#if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA)
388/* Dump the WORD using the DUMP handler called with ARG. */
389
390static inline void
391dump_unsigned (gcov_unsigned_t word,
392 void (*dump_fn) (const void *, unsigned, void *),
393 void *arg)
394{
395 (*dump_fn) (&word, sizeof (word), arg);
396}
397
398/* Dump the COUNTER using the DUMP handler called with ARG. */
399
400static inline void
401dump_counter (gcov_type counter,
402 void (*dump_fn) (const void *, unsigned, void *),
403 void *arg)
404{
405 dump_unsigned ((gcov_unsigned_t)counter, dump_fn, arg);
406
407 if (sizeof (counter) > sizeof (gcov_unsigned_t))
408 dump_unsigned ((gcov_unsigned_t)(counter >> 32), dump_fn, arg);
409 else
410 dump_unsigned (0, dump_fn, arg);
411}
412
413/* Dump the STRING using the DUMP handler called with ARG. */
414
415static inline void
416ATTRIBUTE_UNUSED__attribute__ ((__unused__))
417dump_string (const char *string,
418 void (*dump_fn) (const void *, unsigned, void *),
419 void *arg)
420{
421 unsigned length = 0;
422
423 if (string)
424 length = strlen (string) + 1;
425
426 dump_unsigned (length, dump_fn, arg);
427 if (string)
428 (*dump_fn) (string, length, arg);
429}
430
431#define MAX(X,Y)((X) > (Y) ? (X) : (Y)) ((X) > (Y) ? (X) : (Y))
432
433/* Store all TOP N counters where each has a dynamic length. */
434
435static void
436write_topn_counters (const struct gcov_ctr_info *ci_ptr,
437 unsigned t_ix,
438 gcov_unsigned_t n_counts,
439 void (*dump_fn) (const void *, unsigned, void *),
440 void *(*allocate_fn)(unsigned, void *),
441 void *arg)
442{
443 unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS3;
444 gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0)((void)(!(n_counts % 3 == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-driver.c"
, 444, __FUNCTION__), 0 : 0))
;
445
446 /* It can happen in a multi-threaded environment that number of counters is
447 different from the size of the corresponding linked lists. */
448#define LIST_SIZE_MIN_LENGTH4 * 1024 4 * 1024
449
450 static unsigned *list_sizes = NULLnullptr;
451 static unsigned list_size_length = 0;
452
453 if (list_sizes == NULLnullptr || counters > list_size_length)
454 {
455 list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters)((4 * 1024) > (2 * counters) ? (4 * 1024) : (2 * counters)
)
;
456#if !defined(inhibit_libc) && HAVE_SYS_MMAN_H1
457 list_sizes
458 = (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
459#endif
460
461 /* Malloc fallback. */
462 if (list_sizes == NULLnullptr)
463 list_sizes =
464 (unsigned *)(*allocate_fn) (list_size_length * sizeof (unsigned),
465 arg);
466 }
467
468 unsigned pair_total = 0;
469
470 for (unsigned i = 0; i < counters; i++)
471 {
472 gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS3 * i + 2];
473 unsigned sizes = 0;
474
475 for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__long int)start;
476 node != NULLnullptr; node = node->next)
477 ++sizes;
478
479 pair_total += sizes;
480 list_sizes[i] = sizes;
481 }
482
483 unsigned disk_size = GCOV_TOPN_DISK_COUNTERS2 * counters + 2 * pair_total;
484 dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix)(((gcov_unsigned_t)0x01a10000) + ((gcov_unsigned_t)(t_ix) <<
17))
, dump_fn, arg),
485 dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size)((disk_size) * 2 * 4), dump_fn, arg);
486
487 for (unsigned i = 0; i < counters; i++)
488 {
489 dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS3 * i], dump_fn, arg);
490 dump_counter (list_sizes[i], dump_fn, arg);
491 gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS3 * i + 2];
492
493 unsigned j = 0;
494 for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__long int)start;
495 j < list_sizes[i]; node = node->next, j++)
496 {
497 dump_counter (node->value, dump_fn, arg);
498 dump_counter (node->count, dump_fn, arg);
499 }
500 }
501}
502
503/* Write counters in GI_PTR and the summary in PRG to a gcda file. In
504 the case of appending to an existing file, SUMMARY_POS will be non-zero.
505 We will write the file starting from SUMMAY_POS. */
506
507static void
508write_one_data (const struct gcov_info *gi_ptr,
509 const struct gcov_summary *prg_p ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
510 void (*dump_fn) (const void *, unsigned, void *),
511 void *(*allocate_fn) (unsigned, void *),
512 void *arg)
513{
514 unsigned f_ix;
515
516 dump_unsigned (GCOV_DATA_MAGIC((gcov_unsigned_t)0x67636461), dump_fn, arg);
517 dump_unsigned (GCOV_VERSION((gcov_unsigned_t)0x42333020), dump_fn, arg);
518 dump_unsigned (gi_ptr->stamp, dump_fn, arg);
519 dump_unsigned (gi_ptr->checksum, dump_fn, arg);
520
521#ifdef NEED_L_GCOV
522 /* Generate whole program statistics. */
523 gcov_write_object_summary (prg_p);
524#endif
525
526 /* Write execution counts for each function. */
527 for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
528 {
529#ifdef NEED_L_GCOV
530 unsigned buffered = 0;
531#endif
532 const struct gcov_fn_info *gfi_ptr;
533 const struct gcov_ctr_info *ci_ptr;
534 gcov_unsigned_t length;
535 unsigned t_ix;
536
537#ifdef NEED_L_GCOV
538 if (fn_buffer && fn_buffer->fn_ix == f_ix)
539 {
540 /* Buffered data from another program. */
541 buffered = 1;
542 gfi_ptr = &fn_buffer->info;
543 length = GCOV_TAG_FUNCTION_LENGTH(3 * 4);
544 }
545 else
546#endif
547 {
548 gfi_ptr = gi_ptr->functions[f_ix];
549 if (gfi_ptr && gfi_ptr->key == gi_ptr)
550 length = GCOV_TAG_FUNCTION_LENGTH(3 * 4);
551 else
552 length = 0;
553 }
554
555 dump_unsigned (GCOV_TAG_FUNCTION((gcov_unsigned_t)0x01000000), dump_fn, arg);
556 dump_unsigned (length, dump_fn, arg);
557 if (!length)
558 continue;
559
560 dump_unsigned (gfi_ptr->ident, dump_fn, arg);
561 dump_unsigned (gfi_ptr->lineno_checksum, dump_fn, arg);
562 dump_unsigned (gfi_ptr->cfg_checksum, dump_fn, arg);
563
564 ci_ptr = gfi_ptr->ctrs;
565 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
566 {
567 gcov_position_t n_counts;
568
569 if (!gi_ptr->merge[t_ix])
570 continue;
571
572 n_counts = ci_ptr->num;
573
574 if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR)
575 write_topn_counters (ci_ptr, t_ix, n_counts, dump_fn, allocate_fn,
576 arg);
577 else
578 {
579 dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix)(((gcov_unsigned_t)0x01a10000) + ((gcov_unsigned_t)(t_ix) <<
17))
, dump_fn, arg);
580 if (are_all_counters_zero (ci_ptr))
581 /* Do not stream when all counters are zero. */
582 dump_unsigned (GCOV_TAG_COUNTER_LENGTH (-n_counts)((-n_counts) * 2 * 4),
583 dump_fn, arg);
584 else
585 {
586 dump_unsigned (GCOV_TAG_COUNTER_LENGTH (n_counts)((n_counts) * 2 * 4),
587 dump_fn, arg);
588 for (unsigned i = 0; i < n_counts; i++)
589 dump_counter (ci_ptr->values[i], dump_fn, arg);
590 }
591 }
592
593 ci_ptr++;
594 }
595#ifdef NEED_L_GCOV
596 if (buffered)
597 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
598#endif
599 }
600
601 dump_unsigned (0, dump_fn, arg);
602}
603#endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */
604
605#ifdef NEED_L_GCOV
606/* Dump the coverage counts for one gcov_info object. We merge with existing
607 counts when possible, to avoid growing the .da files ad infinitum. We use
608 this program's checksum to make sure we only accumulate whole program
609 statistics to the correct summary. An object file might be embedded
610 in two separate programs, and we must keep the two program
611 summaries separate. */
612
613static void
614dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
615 unsigned run_counted ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
616 gcov_type run_max ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int mode)
617{
618 struct gcov_summary summary = {};
619 int error;
620 gcov_unsigned_t tag;
621 fn_buffer = 0;
622
623 error = gcov_exit_open_gcda_file (gi_ptr, gf, mode);
7
Calling 'gcov_exit_open_gcda_file'
624 if (error == -1)
625 return;
626
627 tag = gcov_read_unsigned ();
628 if (tag)
629 {
630 /* Merge data from file. */
631 if (tag != GCOV_DATA_MAGIC((gcov_unsigned_t)0x67636461))
632 {
633 gcov_error (GCOV_PROF_PREFIX"libgcov profiling error:%s:" "Not a gcov data file\n",
634 gf->filename);
635 goto read_fatal;
636 }
637 error = merge_one_data (gf->filename, gi_ptr, &summary);
638 if (error == -1)
639 goto read_fatal;
640 }
641
642 gcov_rewrite ();
643
644#if !IN_GCOV_TOOL1
645 if (!run_counted)
646 {
647 summary.runs++;
648 summary.sum_max += run_max;
649 }
650#else
651 summary = gi_ptr->summary;
652#endif
653
654 write_one_data (gi_ptr, &summary, gcov_dump_handler, gcov_allocate_handler,
655 NULLnullptr);
656 /* fall through */
657
658read_fatal:;
659 while (fn_buffer)
660 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
661
662 if ((error = gcov_close ()))
663 gcov_error ((error < 0 ? GCOV_PROF_PREFIX"libgcov profiling error:%s:" "Overflow writing\n"
664 : GCOV_PROF_PREFIX"libgcov profiling error:%s:" "Error writing\n"), gf->filename);
665}
666
667
668/* Dump all the coverage counts for the program. It first computes program
669 summary and then traverses gcov_list list and dumps the gcov_info
670 objects one by one. Use MODE to open files. */
671
672#if !IN_GCOV_TOOL1
673static
674#endif
675void
676gcov_do_dump (struct gcov_info *list, int run_counted, int mode)
677{
678 struct gcov_info *gi_ptr;
679 struct gcov_filename gf;
680
681 /* Compute run_max of this program run. */
682 gcov_type run_max = 0;
683 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
1
Loop condition is true. Entering loop body
4
Loop condition is false. Execution continues on line 694
684 for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
2
Assuming 'f_ix' is equal to field 'n_functions'
3
Loop condition is false. Execution continues on line 683
685 {
686 const struct gcov_ctr_info *cinfo
687 = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
688
689 for (unsigned i = 0; i < cinfo->num; i++)
690 if (run_max < cinfo->values[i])
691 run_max = cinfo->values[i];
692 }
693
694 allocate_filename_struct (&gf);
695
696 /* Now merge each file. */
697 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
5
Loop condition is true. Entering loop body
698 {
699 dump_one_gcov (gi_ptr, &gf, run_counted, run_max, mode);
6
Calling 'dump_one_gcov'
700 free (gf.filename);
701 }
702
703 free (gf.prefix);
704}
705
706#if IN_GCOV_TOOL1
707const char *
708__attribute__ ((unused))
709gcov_get_filename (struct gcov_info *list)
710{
711 return list->filename;
712}
713#endif
714
715#if !IN_GCOV_TOOL1
716void
717__gcov_dump_one (struct gcov_root *root)
718{
719 if (root->dumped)
720 return;
721
722 gcov_do_dump (root->list, root->run_counted, 0);
723
724 root->dumped = 1;
725 root->run_counted = 1;
726}
727
728/* Per-dynamic-object gcov state. */
729struct gcov_root __gcov_root;
730
731/* Exactly one of these will be live in the process image. */
732struct gcov_master __gcov_master =
733 {GCOV_VERSION((gcov_unsigned_t)0x42333020), 0};
734
735/* Dynamic pool for gcov_kvp structures. */
736struct gcov_kvp *__gcov_kvp_dynamic_pool;
737
738/* Index into __gcov_kvp_dynamic_pool array. */
739unsigned __gcov_kvp_dynamic_pool_index;
740
741/* Size of _gcov_kvp_dynamic_pool array. */
742unsigned __gcov_kvp_dynamic_pool_size;
743
744void
745__gcov_exit (void)
746{
747 __gcov_dump_one (&__gcov_root);
748 if (__gcov_root.next)
749 __gcov_root.next->prev = __gcov_root.prev;
750 if (__gcov_root.prev)
751 __gcov_root.prev->next = __gcov_root.next;
752 else
753 __gcov_master.root = __gcov_root.next;
754
755 gcov_error_exit ();
756}
757
758/* Add a new object file onto the bb chain. Invoked automatically
759 when running an object file's global ctors. */
760
761void
762__gcov_init (struct gcov_info *info)
763{
764 if (!info->version || !info->n_functions)
765 return;
766 if (gcov_version (info, info->version, 0))
767 {
768 if (!__gcov_root.list)
769 {
770 /* Add to master list and at exit function. */
771 if (gcov_version (NULLnullptr, __gcov_master.version, "<master>"))
772 {
773 __gcov_root.next = __gcov_master.root;
774 if (__gcov_master.root)
775 __gcov_master.root->prev = &__gcov_root;
776 __gcov_master.root = &__gcov_root;
777 }
778 }
779
780 info->next = __gcov_root.list;
781 __gcov_root.list = info;
782 }
783}
784#endif /* !IN_GCOV_TOOL */
785#endif /* NEED_L_GCOV */
786
787#ifdef NEED_L_GCOV_INFO_TO_GCDA
788/* Convert the gcov info to a gcda data stream. It is intended for
789 freestanding environments which do not support the C library file I/O. */
790
791void
792__gcov_info_to_gcda (const struct gcov_info *gi_ptr,
793 void (*filename_fn) (const char *, void *),
794 void (*dump_fn) (const void *, unsigned, void *),
795 void *(*allocate_fn) (unsigned, void *),
796 void *arg)
797{
798 (*filename_fn) (gi_ptr->filename, arg);
799 write_one_data (gi_ptr, NULLnullptr, dump_fn, allocate_fn, arg);
800}
801
802/* Convert the filename to a gcfn data stream. It is intended for
803 freestanding environments which do not support the C library file I/O. */
804
805void
806__gcov_filename_to_gcfn (const char *filename,
807 void (*dump_fn) (const void *, unsigned, void *),
808 void *arg)
809{
810 dump_unsigned (GCOV_FILENAME_MAGIC((gcov_unsigned_t)0x6763666e), dump_fn, arg);
811 dump_unsigned (GCOV_VERSION((gcov_unsigned_t)0x42333020), dump_fn, arg);
812 dump_string (filename, dump_fn, arg);
813}
814#endif /* NEED_L_GCOV_INFO_TO_GCDA */

/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-driver-system.c

1/* Routines required for instrumenting a program. */
2/* Compile this one with gcc. */
3/* Copyright (C) 1989-2023 Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24<http://www.gnu.org/licenses/>. */
25
26#if !IN_GCOV_TOOL1
27/* Configured via the GCOV_ERROR_FILE environment variable;
28 it will either be stderr, or a file of the user's choosing.
29 Non-static to prevent multiple gcov-aware shared objects from
30 instantiating their own copies. */
31FILE *__gcov_error_file = NULLnullptr;
32#endif
33
34/* A utility function to populate the __gcov_error_file pointer.
35 This should NOT be called outside of the gcov system driver code. */
36
37static FILE *
38get_gcov_error_file (void)
39{
40#if IN_GCOV_TOOL1
41 return stderrstderr;
42#else
43 if (!__gcov_error_file)
44 {
45 const char *gcov_error_filename = getenv ("GCOV_ERROR_FILE");
46
47 if (gcov_error_filename)
48 __gcov_error_file = fopen (gcov_error_filename, "a");
49 if (!__gcov_error_file)
50 __gcov_error_file = stderrstderr;
51 }
52 return __gcov_error_file;
53#endif
54}
55
56/* A utility function for outputting errors. */
57
58static int __attribute__((format(printf, 1, 2)))
59gcov_error (const char *fmt, ...)
60{
61 int ret;
62 va_list argp;
63
64 va_start (argp, fmt)__builtin_va_start(argp, fmt);
65 FILE *f = get_gcov_error_file ();
66 ret = vfprintf (f, fmt, argp);
67 va_end (argp)__builtin_va_end(argp);
68
69 if (getenv ("GCOV_EXIT_AT_ERROR"))
70 {
71 fprintf (f, "profiling:exiting after an error\n");
72 exit (1);
73 }
74
75 return ret;
76}
77
78#if !IN_GCOV_TOOL1
79static void
80gcov_error_exit (void)
81{
82 if (__gcov_error_file && __gcov_error_file != stderrstderr)
83 {
84 fclose (__gcov_error_file);
85 __gcov_error_file = NULLnullptr;
86 }
87}
88#endif
89
90/* Make sure path component of the given FILENAME exists, create
91 missing directories. FILENAME must be writable.
92 Returns zero on success, or -1 if an error occurred. */
93
94static int
95create_file_directory (char *filename)
96{
97#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
98 (void) filename;
99 return -1;
100#else
101 char *s;
102
103 s = filename;
104
105 if (HAS_DRIVE_SPEC(s)(0))
106 s += 2;
107 if (IS_DIR_SEPARATOR(*s)(((*s) == '/') || (((*s) == '\\') && (0))))
108 ++s;
109 for (; *s != '\0'; s++)
110 if (IS_DIR_SEPARATOR(*s)(((*s) == '/') || (((*s) == '\\') && (0))))
111 {
112 char sep = *s;
113 *s = '\0';
114
115 /* Try to make directory if it doesn't already exist. */
116 if (access (filename, F_OK0) == -1
117#ifdef TARGET_POSIX_IO
118 && mkdir (filename, 0777) == -1
119#else
120#ifdef mkdir
121#undef mkdir
122#endif
123 && mkdir (filename) == -1
124#endif
125 /* The directory might have been made by another process. */
126 && errno(*__errno_location ()) != EEXIST17)
127 {
128 gcov_error ("profiling:%s:Cannot create directory\n", filename);
129 *s = sep;
130 return -1;
131 };
132
133 *s = sep;
134 };
135 return 0;
136#endif
137}
138
139/* Replace filename variables in FILENAME. We currently support expansion:
140
141 %p - process ID
142 %q{ENV} - value of environment variable ENV
143 */
144
145static char *
146replace_filename_variables (char *filename)
147{
148 char buffer[16];
149 char empty[] = "";
150 for (char *p = filename; *p != '\0'; p++)
19
Assuming the condition is true
20
Loop condition is true. Entering loop body
151 {
152 unsigned length = strlen (filename);
153 if (*p == '%' && *(p + 1) != '\0')
21
Assuming the condition is true
22
Assuming the condition is true
23
Taking true branch
154 {
155 unsigned start = p - filename;
156 p++;
157 char *replacement = NULLnullptr;
158 switch (*p)
24
Control jumps to 'case 112:' at line 160
159 {
160 case 'p':
161 sprintf (buffer, "%d", getpid ());
162 replacement = buffer;
163 p++;
164 break;
25
Execution continues on line 188
165 case 'q':
166 if (*(p + 1) == '{')
167 {
168 p += 2;
169 char *e = strchr (p, '}');
170 if (e)
171 {
172 *e = '\0';
173 replacement = getenv (p);
174 if (replacement == NULLnullptr)
175 replacement = empty;
176 p = e + 1;
177 }
178 else
179 return filename;
180 }
181 break;
182 default:
183 return filename;
184 }
185
186 /* Concat beginning of the path, replacement and
187 ending of the path. */
188 unsigned end = length - (p - filename);
189 unsigned repl_length = replacement != NULLnullptr ? strlen (replacement) : 0;
26
'?' condition is true
190
191 char *buffer = (char *)xmallocmalloc (start + end + repl_length + 1);
192 char *buffer_ptr = buffer;
193 buffer_ptr = (char *)memcpy (buffer_ptr, filename, start);
194 buffer_ptr += start;
195 if (replacement != NULLnullptr)
27
Taking true branch
196 buffer_ptr = (char *)memcpy (buffer_ptr, replacement, repl_length);
197 buffer_ptr += repl_length;
198 buffer_ptr = (char *)memcpy (buffer_ptr, p, end);
199 buffer_ptr += end;
200 *buffer_ptr = '\0';
201
202 free (filename);
28
Argument to free() is offset by 1 byte from the start of memory allocated by malloc()
203 filename = buffer;
204 p = buffer + start + repl_length;
205 }
206 }
207
208 return filename;
209}
210
211static void
212allocate_filename_struct (struct gcov_filename *gf)
213{
214 const char *gcov_prefix;
215 size_t prefix_length;
216 int strip = 0;
217 gf->filename = NULLnullptr;
218
219 {
220 /* Check if the level of dirs to strip off specified. */
221 char *tmp = getenv("GCOV_PREFIX_STRIP");
222 if (tmp)
223 {
224 strip = atoi (tmp);
225 /* Do not consider negative values. */
226 if (strip < 0)
227 strip = 0;
228 }
229 }
230 gf->strip = strip;
231
232 /* Get file name relocation prefix. Non-absolute values are ignored. */
233 gcov_prefix = getenv("GCOV_PREFIX");
234 prefix_length = gcov_prefix ? strlen (gcov_prefix) : 0;
235
236 /* Remove an unnecessary trailing '/' */
237 if (prefix_length && IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1])(((gcov_prefix[prefix_length - 1]) == '/') || (((gcov_prefix[
prefix_length - 1]) == '\\') && (0)))
)
238 prefix_length--;
239
240 /* If no prefix was specified and a prefix stip, then we assume
241 relative. */
242 if (!prefix_length && gf->strip)
243 {
244 gcov_prefix = ".";
245 prefix_length = 1;
246 }
247
248 /* Allocate and initialize the filename scratch space. */
249 if (prefix_length)
250 {
251 gf->prefix = (char *) xmallocmalloc (prefix_length + 1);
252 char *p = (char *) memcpy (gf->prefix, gcov_prefix, prefix_length);
253 *(p + prefix_length) = '\0';
254 }
255 else
256 gf->prefix = NULLnullptr;
257}
258
259/* Open a gcda file specified by GI_FILENAME.
260 Return -1 on error. Return 0 on success. */
261
262static int
263gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
264 struct gcov_filename *gf,
265 int mode)
266{
267 int append_slash = 0;
268 const char *fname = gi_ptr->filename;
269
270 /* Build relocated filename, stripping off leading
271 directories from the initial filename if requested. */
272 if (gf->strip
7.1
Field 'strip' is <= 0
7.1
Field 'strip' is <= 0
> 0)
8
Taking false branch
273 {
274 const char *probe = fname;
275 int level;
276
277 /* Remove a leading separator, without counting it. */
278 if (IS_DIR_SEPARATOR (*probe)(((*probe) == '/') || (((*probe) == '\\') && (0))))
279 probe++;
280
281 /* Skip selected directory levels. If we fall off the end, we
282 keep the final part. */
283 for (level = gf->strip; *probe && level; probe++)
284 if (IS_DIR_SEPARATOR (*probe)(((*probe) == '/') || (((*probe) == '\\') && (0))))
285 {
286 fname = probe;
287 level--;
288 }
289 }
290
291 /* Update complete filename with stripped original. */
292 if (gf->prefix
8.1
Field 'prefix' is non-null
8.1
Field 'prefix' is non-null
)
9
Taking true branch
293 {
294 /* Avoid to add multiple drive letters into combined path. */
295 if (HAS_DRIVE_SPEC(fname)(0))
296 fname += 2;
297
298 if (!IS_DIR_SEPARATOR (*fname)(((*fname) == '/') || (((*fname) == '\\') && (0))))
10
Taking false branch
11
Assuming the condition is false
12
Assuming the condition is false
13
Taking true branch
299 append_slash = 1;
300 }
301
302 size_t prefix_length = gf->prefix
13.1
Field 'prefix' is non-null
13.1
Field 'prefix' is non-null
? strlen (gf->prefix) : 0;
14
'?' condition is true
303 gf->filename = (char *) xmallocmalloc (prefix_length + strlen (fname) + 2);
304 *gf->filename = '\0';
305 if (prefix_length)
15
Assuming 'prefix_length' is 0
16
Taking false branch
306 strcat (gf->filename, gf->prefix);
307 if (append_slash
16.1
'append_slash' is 1
16.1
'append_slash' is 1
)
17
Taking true branch
308 *gf->filename++ = '/';
309 strcat (gf->filename, fname);
310
311 gf->filename = replace_filename_variables (gf->filename);
18
Calling 'replace_filename_variables'
312
313 if (!gcov_open (gf->filename, mode))
314 {
315 /* Open failed likely due to missed directory.
316 Create directory and retry to open file. */
317 if (create_file_directory (gf->filename))
318 {
319 fprintf (stderrstderr, "profiling:%s:Skip\n", gf->filename);
320 return -1;
321 }
322 if (!gcov_open (gf->filename, mode))
323 {
324 fprintf (stderrstderr, "profiling:%s:Cannot open\n", gf->filename);
325 return -1;
326 }
327 }
328
329 return 0;
330}