Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gettext-0.26/gettext-tools/libgettextpo/xvasprintf.c
Line
Count
Source
1
/* vasprintf and asprintf with out-of-memory checking.
2
   Copyright (C) 1999, 2002-2004, 2006-2025 Free Software Foundation, Inc.
3
4
   This program is free software: you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation, either version 3 of the License, or
7
   (at your option) any later version.
8
9
   This program is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
16
17
#include <config.h>
18
19
/* Specification.  */
20
#include "xvasprintf.h"
21
22
#include <errno.h>
23
#include <limits.h>
24
#include <stdio.h>
25
#include <stdlib.h>
26
#include <string.h>
27
28
#include "xalloc.h"
29
30
/* Checked size_t computations.  */
31
#include "xsize.h"
32
33
static char *
34
xstrcat (size_t argcount, va_list args)
35
0
{
36
0
  char *result;
37
0
  va_list ap;
38
0
  size_t totalsize;
39
0
  size_t i;
40
0
  char *p;
41
42
  /* Determine the total size.  */
43
0
  totalsize = 0;
44
0
  va_copy (ap, args);
45
0
  for (i = argcount; i > 0; i--)
46
0
    {
47
0
      const char *next = va_arg (ap, const char *);
48
0
      totalsize = xsum (totalsize, strlen (next));
49
0
    }
50
0
  va_end (ap);
51
52
  /* Test for overflow in the summing pass above or in (totalsize + 1)
53
     below.  */
54
0
  if (totalsize == SIZE_MAX)
55
0
    xalloc_die ();
56
57
  /* Allocate and fill the result string.  */
58
0
  result = XNMALLOC (totalsize + 1, char);
59
0
  p = result;
60
0
  for (i = argcount; i > 0; i--)
61
0
    {
62
0
      const char *next = va_arg (args, const char *);
63
0
      size_t len = strlen (next);
64
0
      memcpy (p, next, len);
65
0
      p += len;
66
0
    }
67
0
  *p = '\0';
68
69
0
  return result;
70
0
}
71
72
char *
73
xvasprintf (const char *format, va_list args)
74
11.0k
{
75
11.0k
  char *result;
76
77
  /* Recognize the special case format = "%s...%s".  It is a frequently used
78
     idiom for string concatenation and needs to be fast.  We don't want to
79
     have a separate function xstrcat() for this purpose.  */
80
11.0k
  {
81
11.0k
    size_t argcount = 0;
82
11.0k
    const char *f;
83
84
11.0k
    for (f = format;;)
85
11.0k
      {
86
11.0k
        if (*f == '\0')
87
          /* Recognized the special case of string concatenation.  */
88
0
          return xstrcat (argcount, args);
89
11.0k
        if (*f != '%')
90
11.0k
          break;
91
0
        f++;
92
0
        if (*f != 's')
93
0
          break;
94
0
        f++;
95
0
        argcount++;
96
0
      }
97
11.0k
  }
98
99
11.0k
  if (vaszprintf (&result, format, args) < 0)
100
0
    {
101
0
      if (errno == ENOMEM)
102
0
        xalloc_die ();
103
0
      else
104
0
        {
105
          /* The programmer ought to have ensured that none of the other errors
106
             can occur.  */
107
0
          int err = errno;
108
0
          char errbuf[20];
109
0
          const char *errname;
110
#if HAVE_WORKING_STRERRORNAME_NP
111
          errname = strerrorname_np (err);
112
          if (errname == NULL)
113
#else
114
0
          if (err == EINVAL)
115
0
            errname = "EINVAL";
116
0
          else if (err == EILSEQ)
117
0
            errname = "EILSEQ";
118
0
          else if (err == EOVERFLOW)
119
0
            errname = "EOVERFLOW";
120
0
          else
121
0
#endif
122
0
            {
123
0
              sprintf (errbuf, "%d", err);
124
0
              errname = errbuf;
125
0
            }
126
0
          fprintf (stderr, "vasprintf failed! format=\"%s\", errno=%s\n",
127
0
                   format, errname);
128
0
          fflush (stderr);
129
0
          abort ();
130
0
        }
131
0
    }
132
133
11.0k
  return result;
134
11.0k
}