Coverage Report

Created: 2025-06-13 06:36

/src/json-c/printbuf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
3
 *
4
 * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
5
 * Michael Clark <michael@metaparadigm.com>
6
 *
7
 * This library is free software; you can redistribute it and/or modify
8
 * it under the terms of the MIT license. See COPYING for details.
9
 *
10
 *
11
 * Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.
12
 * The copyrights to the contents of this file are licensed under the MIT License
13
 * (https://www.opensource.org/licenses/mit-license.php)
14
 */
15
16
#include "config.h"
17
18
#include <errno.h>
19
#include <limits.h>
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <string.h>
23
24
#ifdef HAVE_STDARG_H
25
#include <stdarg.h>
26
#else /* !HAVE_STDARG_H */
27
#error Not enough var arg support!
28
#endif /* HAVE_STDARG_H */
29
30
#include "debug.h"
31
#include "printbuf.h"
32
#include "snprintf_compat.h"
33
#include "vasprintf_compat.h"
34
35
static int printbuf_extend(struct printbuf *p, int min_size);
36
37
struct printbuf *printbuf_new(void)
38
14.1k
{
39
14.1k
  struct printbuf *p;
40
41
14.1k
  p = (struct printbuf *)calloc(1, sizeof(struct printbuf));
42
14.1k
  if (!p)
43
0
    return NULL;
44
14.1k
  p->size = 32;
45
14.1k
  p->bpos = 0;
46
14.1k
  if (!(p->buf = (char *)malloc(p->size)))
47
0
  {
48
0
    free(p);
49
0
    return NULL;
50
0
  }
51
14.1k
  p->buf[0] = '\0';
52
14.1k
  return p;
53
14.1k
}
54
55
/**
56
 * Extend the buffer p so it has a size of at least min_size.
57
 *
58
 * If the current size is large enough, nothing is changed.
59
 *
60
 * If extension failed, errno is set to indicate the error.
61
 *
62
 * Note: this does not check the available space!  The caller
63
 *  is responsible for performing those calculations.
64
 */
65
static int printbuf_extend(struct printbuf *p, int min_size)
66
27.2k
{
67
27.2k
  char *t;
68
27.2k
  int new_size;
69
70
27.2k
  if (p->size >= min_size)
71
4.04k
    return 0;
72
  /* Prevent signed integer overflows with large buffers. */
73
23.2k
  if (min_size > INT_MAX - 8)
74
0
  {
75
0
    errno = EFBIG;
76
0
    return -1;
77
0
  }
78
23.2k
  if (p->size > INT_MAX / 2)
79
0
    new_size = min_size + 8;
80
23.2k
  else {
81
23.2k
    new_size = p->size * 2;
82
23.2k
    if (new_size < min_size + 8)
83
651
      new_size = min_size + 8;
84
23.2k
  }
85
#ifdef PRINTBUF_DEBUG
86
  MC_DEBUG("printbuf_extend: realloc "
87
           "bpos=%d min_size=%d old_size=%d new_size=%d\n",
88
           p->bpos, min_size, p->size, new_size);
89
#endif /* PRINTBUF_DEBUG */
90
23.2k
  if (!(t = (char *)realloc(p->buf, new_size)))
91
0
    return -1;
92
23.2k
  p->size = new_size;
93
23.2k
  p->buf = t;
94
23.2k
  return 0;
95
23.2k
}
96
97
int printbuf_memappend(struct printbuf *p, const char *buf, int size)
98
1.20M
{
99
  /* Prevent signed integer overflows with large buffers. */
100
1.20M
  if (size < 0 || size > INT_MAX - p->bpos - 1)
101
0
  {
102
0
    errno = EFBIG;
103
0
    return -1;
104
0
  }
105
1.20M
  if (p->size <= p->bpos + size + 1)
106
27.2k
  {
107
27.2k
    if (printbuf_extend(p, p->bpos + size + 1) < 0)
108
0
      return -1;
109
27.2k
  }
110
1.20M
  memcpy(p->buf + p->bpos, buf, size);
111
1.20M
  p->bpos += size;
112
1.20M
  p->buf[p->bpos] = '\0';
113
1.20M
  return size;
114
1.20M
}
115
116
int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len)
117
0
{
118
0
  int size_needed;
119
120
0
  if (offset == -1)
121
0
    offset = pb->bpos;
122
  /* Prevent signed integer overflows with large buffers. */
123
0
  if (len < 0 || offset < -1 || len > INT_MAX - offset)
124
0
  {
125
0
    errno = EFBIG;
126
0
    return -1;
127
0
  }
128
0
  size_needed = offset + len;
129
0
  if (pb->size < size_needed)
130
0
  {
131
0
    if (printbuf_extend(pb, size_needed) < 0)
132
0
      return -1;
133
0
  }
134
135
0
  if (pb->bpos < offset)
136
0
    memset(pb->buf + pb->bpos, '\0', offset - pb->bpos);
137
0
  memset(pb->buf + offset, charvalue, len);
138
0
  if (pb->bpos < size_needed)
139
0
    pb->bpos = size_needed;
140
141
0
  return 0;
142
0
}
143
144
int sprintbuf(struct printbuf *p, const char *msg, ...)
145
0
{
146
0
  va_list ap;
147
0
  char *t;
148
0
  int size;
149
0
  char buf[128];
150
151
  /* use stack buffer first */
152
0
  va_start(ap, msg);
153
0
  size = vsnprintf(buf, 128, msg, ap);
154
0
  va_end(ap);
155
  /* if string is greater than stack buffer, then use dynamic string
156
   * with vasprintf.  Note: some implementations of vsnprintf return -1
157
   * if output is truncated whereas some return the number of bytes that
158
   * would have been written - this code handles both cases.
159
   */
160
0
  if (size < 0 || size > 127)
161
0
  {
162
0
    va_start(ap, msg);
163
0
    if ((size = vasprintf(&t, msg, ap)) < 0)
164
0
    {
165
0
      va_end(ap);
166
0
      return -1;
167
0
    }
168
0
    va_end(ap);
169
0
    size = printbuf_memappend(p, t, size);
170
0
    free(t);
171
0
  }
172
0
  else
173
0
  {
174
0
    size = printbuf_memappend(p, buf, size);
175
0
  }
176
0
  return size;
177
0
}
178
179
void printbuf_reset(struct printbuf *p)
180
235k
{
181
235k
  p->buf[0] = '\0';
182
235k
  p->bpos = 0;
183
235k
}
184
185
void printbuf_free(struct printbuf *p)
186
220k
{
187
220k
  if (p)
188
14.1k
  {
189
14.1k
    free(p->buf);
190
14.1k
    free(p);
191
14.1k
  }
192
220k
}