Coverage Report

Created: 2026-03-10 08:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/libiberty/vprintf-support.c
Line
Count
Source
1
/* Estimate the length of the string generated by a vprintf-like
2
   function.  Used by vasprintf and xvasprintf.
3
   Copyright (C) 1994-2026 Free Software Foundation, Inc.
4
5
This file is part of the libiberty library.
6
Libiberty is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public
8
License as published by the Free Software Foundation; either
9
version 2 of the License, or (at your option) any later version.
10
11
Libiberty is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
Library General Public License for more details.
15
16
You should have received a copy of the GNU Library General Public
17
License along with libiberty; see the file COPYING.LIB.  If not, write
18
to the Free Software Foundation, Inc., 51 Franklin Street - Fifth
19
Floor, Boston, MA 02110-1301, USA.  */
20
21
#ifdef HAVE_CONFIG_H
22
#include "config.h"
23
#endif
24
#include <ansidecl.h>
25
#include <stdarg.h>
26
#if !defined (va_copy) && defined (__va_copy)
27
# define va_copy(d,s)  __va_copy((d),(s))
28
#endif
29
#include <stdio.h>
30
#include <errno.h>
31
#ifdef HAVE_STRING_H
32
#include <string.h>
33
#endif
34
#ifdef HAVE_STDLIB_H
35
#include <stdlib.h>
36
#else
37
extern unsigned long strtoul ();
38
#endif
39
#include "libiberty.h"
40
41
static inline unsigned long
42
do_strtoul (const char *str, char **endptr, int base)
43
66.4k
  {
44
#ifdef _WIN32
45
    /* The MSVCRT `strtoul()` function resets `errno` to zero upon success.
46
       We must preserve it across this call.  */
47
    int saved_errno = errno;
48
#endif
49
66.4k
    long value = strtoul (str, endptr, base);
50
#ifdef _WIN32
51
    errno = saved_errno;
52
#endif
53
66.4k
    return value;
54
66.4k
  }
55
56
int
57
libiberty_vprintf_buffer_size (const char *format, va_list args)
58
66.1k
{
59
66.1k
  const char *p = format;
60
  /* Add one to make sure that it is never zero, which might cause malloc
61
     to return NULL.  */
62
66.1k
  int total_width = strlen (format) + 1;
63
66.1k
  va_list ap;
64
65
66.1k
#ifdef va_copy
66
66.1k
  va_copy (ap, args);
67
#else
68
  memcpy ((void *) &ap, (void *) &args, sizeof (va_list));
69
#endif
70
71
136k
  while (*p != '\0')
72
70.4k
    {
73
70.4k
      if (*p++ == '%')
74
66.4k
  {
75
66.4k
    int prec = 0;
76
66.4k
    while (strchr ("-+ #0", *p))
77
0
      ++p;
78
66.4k
    if (*p == '*')
79
0
      {
80
0
        ++p;
81
0
        total_width += abs (va_arg (ap, int));
82
0
      }
83
66.4k
    else
84
66.4k
      total_width += do_strtoul (p, (char **) &p, 10);
85
66.4k
    if (*p == '.')
86
0
      {
87
0
        ++p;
88
0
        if (*p == '*')
89
0
    {
90
0
      ++p;
91
0
      total_width += abs (va_arg (ap, int));
92
0
    }
93
0
        else
94
0
    total_width += do_strtoul (p, (char **) &p, 10);
95
0
      }
96
66.4k
    do
97
66.4k
      {
98
66.4k
        switch (*p)
99
66.4k
    {
100
0
    case 'h':
101
0
      ++p;
102
0
      continue;
103
0
    case 'l':
104
0
    case 'L':
105
0
      ++prec;
106
0
      ++p;
107
0
      continue;
108
0
    case 'z':
109
0
      prec = 3;
110
0
      ++p;
111
0
      continue;
112
0
    case 't':
113
0
      prec = 4;
114
0
      ++p;
115
0
      continue;
116
#ifdef _WIN32
117
    case 'I':
118
      if (p[1] == '6' && p[2] == '4')
119
        {
120
          prec = 2;
121
          p += 3;
122
          continue;
123
        }
124
      break;
125
#endif
126
66.4k
    default:
127
66.4k
      break;
128
66.4k
    }
129
66.4k
        break;
130
66.4k
      }
131
66.4k
    while (1);
132
133
    /* Should be big enough for any format specifier except %s and floats.  */
134
66.4k
    total_width += 30;
135
66.4k
    switch (*p)
136
66.4k
      {
137
0
      case 'd':
138
0
      case 'i':
139
0
      case 'o':
140
152
      case 'u':
141
152
      case 'x':
142
152
      case 'X':
143
152
        switch (prec)
144
152
    {
145
152
    case 0: (void) va_arg (ap, int); break;
146
0
    case 1: (void) va_arg (ap, long int); break;
147
0
    case 2: (void) va_arg (ap, long long int); break;
148
0
    case 3: (void) va_arg (ap, size_t); break;
149
0
    case 4: (void) va_arg (ap, ptrdiff_t); break;
150
152
    }
151
152
        break;
152
152
      case 'c':
153
0
        (void) va_arg (ap, int);
154
0
        break;
155
0
      case 'f':
156
0
      case 'e':
157
0
      case 'E':
158
0
      case 'g':
159
0
      case 'G':
160
0
        if (!prec)
161
0
    {
162
0
      (void) va_arg (ap, double);
163
      /* Since an ieee double can have an exponent of 308, we'll
164
         make the buffer wide enough to cover the gross case. */
165
0
      total_width += 308;
166
0
    }
167
0
        else
168
0
    {
169
0
      (void) va_arg (ap, long double);
170
0
      total_width += 4932;
171
0
    }
172
0
        break;
173
66.2k
      case 's':
174
66.2k
        total_width += strlen (va_arg (ap, char *));
175
66.2k
        break;
176
0
      case 'p':
177
0
      case 'n':
178
0
        (void) va_arg (ap, char *);
179
0
        break;
180
66.4k
      }
181
66.4k
    p++;
182
66.4k
  }
183
70.4k
    }
184
66.1k
#ifdef va_copy
185
66.1k
  va_end (ap);
186
66.1k
#endif
187
66.1k
  return total_width;
188
66.1k
}