PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pqexpbuffer.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pqexpbuffer.c
4  *
5  * PQExpBuffer provides an indefinitely-extensible string data type.
6  * It can be used to buffer either ordinary C strings (null-terminated text)
7  * or arbitrary binary data. All storage is allocated with malloc().
8  *
9  * This module is essentially the same as the backend's StringInfo data type,
10  * but it is intended for use in frontend libpq and client applications.
11  * Thus, it does not rely on palloc() nor elog(), nor psprintf.c which
12  * will exit() on error.
13  *
14  * It does rely on vsnprintf(); if configure finds that libc doesn't provide
15  * a usable vsnprintf(), then a copy of our own implementation of it will
16  * be linked into libpq.
17  *
18  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
19  * Portions Copyright (c) 1994, Regents of the University of California
20  *
21  * src/interfaces/libpq/pqexpbuffer.c
22  *
23  *-------------------------------------------------------------------------
24  */
25 
26 #include "postgres_fe.h"
27 
28 #include <limits.h>
29 
30 #include "pqexpbuffer.h"
31 
32 #ifdef WIN32
33 #include "win32.h"
34 #endif
35 
36 
37 /* All "broken" PQExpBuffers point to this string. */
38 static const char oom_buffer[1] = "";
39 
40 static bool appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) pg_attribute_printf(2, 0);
41 
42 
43 /*
44  * markPQExpBufferBroken
45  *
46  * Put a PQExpBuffer in "broken" state if it isn't already.
47  */
48 static void
50 {
51  if (str->data != oom_buffer)
52  free(str->data);
53 
54  /*
55  * Casting away const here is a bit ugly, but it seems preferable to not
56  * marking oom_buffer const. We want to do that to encourage the compiler
57  * to put oom_buffer in read-only storage, so that anyone who tries to
58  * scribble on a broken PQExpBuffer will get a failure.
59  */
60  str->data = (char *) oom_buffer;
61  str->len = 0;
62  str->maxlen = 0;
63 }
64 
65 /*
66  * createPQExpBuffer
67  *
68  * Create an empty 'PQExpBufferData' & return a pointer to it.
69  */
72 {
73  PQExpBuffer res;
74 
75  res = (PQExpBuffer) malloc(sizeof(PQExpBufferData));
76  if (res != NULL)
77  initPQExpBuffer(res);
78 
79  return res;
80 }
81 
82 /*
83  * initPQExpBuffer
84  *
85  * Initialize a PQExpBufferData struct (with previously undefined contents)
86  * to describe an empty string.
87  */
88 void
90 {
91  str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
92  if (str->data == NULL)
93  {
94  str->data = (char *) oom_buffer; /* see comment above */
95  str->maxlen = 0;
96  str->len = 0;
97  }
98  else
99  {
101  str->len = 0;
102  str->data[0] = '\0';
103  }
104 }
105 
106 /*
107  * destroyPQExpBuffer(str);
108  *
109  * free()s both the data buffer and the PQExpBufferData.
110  * This is the inverse of createPQExpBuffer().
111  */
112 void
114 {
115  if (str)
116  {
117  termPQExpBuffer(str);
118  free(str);
119  }
120 }
121 
122 /*
123  * termPQExpBuffer(str)
124  * free()s the data buffer but not the PQExpBufferData itself.
125  * This is the inverse of initPQExpBuffer().
126  */
127 void
129 {
130  if (str->data != oom_buffer)
131  free(str->data);
132  /* just for luck, make the buffer validly empty. */
133  str->data = (char *) oom_buffer; /* see comment above */
134  str->maxlen = 0;
135  str->len = 0;
136 }
137 
138 /*
139  * resetPQExpBuffer
140  * Reset a PQExpBuffer to empty
141  *
142  * Note: if possible, a "broken" PQExpBuffer is returned to normal.
143  */
144 void
146 {
147  if (str)
148  {
149  if (str->data != oom_buffer)
150  {
151  str->len = 0;
152  str->data[0] = '\0';
153  }
154  else
155  {
156  /* try to reinitialize to valid state */
157  initPQExpBuffer(str);
158  }
159  }
160 }
161 
162 /*
163  * enlargePQExpBuffer
164  * Make sure there is enough space for 'needed' more bytes in the buffer
165  * ('needed' does not include the terminating null).
166  *
167  * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case
168  * the buffer is left in "broken" state.)
169  */
170 int
171 enlargePQExpBuffer(PQExpBuffer str, size_t needed)
172 {
173  size_t newlen;
174  char *newdata;
175 
176  if (PQExpBufferBroken(str))
177  return 0; /* already failed */
178 
179  /*
180  * Guard against ridiculous "needed" values, which can occur if we're fed
181  * bogus data. Without this, we can get an overflow or infinite loop in
182  * the following.
183  */
184  if (needed >= ((size_t) INT_MAX - str->len))
185  {
187  return 0;
188  }
189 
190  needed += str->len + 1; /* total space required now */
191 
192  /* Because of the above test, we now have needed <= INT_MAX */
193 
194  if (needed <= str->maxlen)
195  return 1; /* got enough space already */
196 
197  /*
198  * We don't want to allocate just a little more space with each append;
199  * for efficiency, double the buffer size each time it overflows.
200  * Actually, we might need to more than double it if 'needed' is big...
201  */
202  newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64;
203  while (needed > newlen)
204  newlen = 2 * newlen;
205 
206  /*
207  * Clamp to INT_MAX in case we went past it. Note we are assuming here
208  * that INT_MAX <= UINT_MAX/2, else the above loop could overflow. We
209  * will still have newlen >= needed.
210  */
211  if (newlen > (size_t) INT_MAX)
212  newlen = (size_t) INT_MAX;
213 
214  newdata = (char *) realloc(str->data, newlen);
215  if (newdata != NULL)
216  {
217  str->data = newdata;
218  str->maxlen = newlen;
219  return 1;
220  }
221 
223  return 0;
224 }
225 
226 /*
227  * printfPQExpBuffer
228  * Format text data under the control of fmt (an sprintf-like format string)
229  * and insert it into str. More space is allocated to str if necessary.
230  * This is a convenience routine that does the same thing as
231  * resetPQExpBuffer() followed by appendPQExpBuffer().
232  */
233 void
234 printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
235 {
236  va_list args;
237  bool done;
238 
239  resetPQExpBuffer(str);
240 
241  if (PQExpBufferBroken(str))
242  return; /* already failed */
243 
244  /* Loop in case we have to retry after enlarging the buffer. */
245  do
246  {
247  va_start(args, fmt);
248  done = appendPQExpBufferVA(str, fmt, args);
249  va_end(args);
250  } while (!done);
251 }
252 
253 /*
254  * appendPQExpBuffer
255  *
256  * Format text data under the control of fmt (an sprintf-like format string)
257  * and append it to whatever is already in str. More space is allocated
258  * to str if necessary. This is sort of like a combination of sprintf and
259  * strcat.
260  */
261 void
262 appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
263 {
264  va_list args;
265  bool done;
266 
267  if (PQExpBufferBroken(str))
268  return; /* already failed */
269 
270  /* Loop in case we have to retry after enlarging the buffer. */
271  do
272  {
273  va_start(args, fmt);
274  done = appendPQExpBufferVA(str, fmt, args);
275  va_end(args);
276  } while (!done);
277 }
278 
279 /*
280  * appendPQExpBufferVA
281  * Shared guts of printfPQExpBuffer/appendPQExpBuffer.
282  * Attempt to format data and append it to str. Returns true if done
283  * (either successful or hard failure), false if need to retry.
284  */
285 static bool
286 appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args)
287 {
288  size_t avail;
289  size_t needed;
290  int nprinted;
291 
292  /*
293  * Try to format the given string into the available space; but if there's
294  * hardly any space, don't bother trying, just enlarge the buffer first.
295  */
296  if (str->maxlen > str->len + 16)
297  {
298  /*
299  * Note: we intentionally leave one byte unused, as a guard against
300  * old broken versions of vsnprintf.
301  */
302  avail = str->maxlen - str->len - 1;
303 
304  errno = 0;
305 
306  nprinted = vsnprintf(str->data + str->len, avail, fmt, args);
307 
308  /*
309  * If vsnprintf reports an error other than ENOMEM, fail.
310  */
311  if (nprinted < 0 && errno != 0 && errno != ENOMEM)
312  {
314  return true;
315  }
316 
317  /*
318  * Note: some versions of vsnprintf return the number of chars
319  * actually stored, not the total space needed as C99 specifies. And
320  * at least one returns -1 on failure. Be conservative about
321  * believing whether the print worked.
322  */
323  if (nprinted >= 0 && (size_t) nprinted < avail - 1)
324  {
325  /* Success. Note nprinted does not include trailing null. */
326  str->len += nprinted;
327  return true;
328  }
329 
330  if (nprinted >= 0 && (size_t) nprinted > avail)
331  {
332  /*
333  * This appears to be a C99-compliant vsnprintf, so believe its
334  * estimate of the required space. (If it's wrong, the logic will
335  * still work, but we may loop multiple times.) Note that the
336  * space needed should be only nprinted+1 bytes, but we'd better
337  * allocate one more than that so that the test above will succeed
338  * next time.
339  *
340  * In the corner case where the required space just barely
341  * overflows, fail.
342  */
343  if (nprinted > INT_MAX - 2)
344  {
346  return true;
347  }
348  needed = nprinted + 2;
349  }
350  else
351  {
352  /*
353  * Buffer overrun, and we don't know how much space is needed.
354  * Estimate twice the previous buffer size, but not more than
355  * INT_MAX.
356  */
357  if (avail >= INT_MAX / 2)
358  needed = INT_MAX;
359  else
360  needed = avail * 2;
361  }
362  }
363  else
364  {
365  /*
366  * We have to guess at how much to enlarge, since we're skipping the
367  * formatting work.
368  */
369  needed = 32;
370  }
371 
372  /* Increase the buffer size and try again. */
373  if (!enlargePQExpBuffer(str, needed))
374  return true; /* oops, out of memory */
375 
376  return false;
377 }
378 
379 /*
380  * appendPQExpBufferStr
381  * Append the given string to a PQExpBuffer, allocating more space
382  * if necessary.
383  */
384 void
385 appendPQExpBufferStr(PQExpBuffer str, const char *data)
386 {
387  appendBinaryPQExpBuffer(str, data, strlen(data));
388 }
389 
390 /*
391  * appendPQExpBufferChar
392  * Append a single byte to str.
393  * Like appendPQExpBuffer(str, "%c", ch) but much faster.
394  */
395 void
397 {
398  /* Make more room if needed */
399  if (!enlargePQExpBuffer(str, 1))
400  return;
401 
402  /* OK, append the character */
403  str->data[str->len] = ch;
404  str->len++;
405  str->data[str->len] = '\0';
406 }
407 
408 /*
409  * appendBinaryPQExpBuffer
410  *
411  * Append arbitrary binary data to a PQExpBuffer, allocating more space
412  * if necessary.
413  */
414 void
415 appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
416 {
417  /* Make more room if needed */
418  if (!enlargePQExpBuffer(str, datalen))
419  return;
420 
421  /* OK, append the data */
422  memcpy(str->data + str->len, data, datalen);
423  str->len += datalen;
424 
425  /*
426  * Keep a trailing null in place, even though it's probably useless for
427  * binary data...
428  */
429  str->data[str->len] = '\0';
430 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:234
static bool static void markPQExpBufferBroken(PQExpBuffer str)
Definition: pqexpbuffer.c:49
PQExpBufferData * PQExpBuffer
Definition: pqexpbuffer.h:51
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:128
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:385
#define pg_attribute_printf(f, a)
Definition: c.h:638
#define malloc(a)
Definition: header.h:50
int int vsnprintf(char *str, size_t count, const char *fmt, va_list args)
void destroyPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:113
static const char oom_buffer[1]
Definition: pqexpbuffer.c:38
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:262
PQExpBuffer createPQExpBuffer(void)
Definition: pqexpbuffer.c:71
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:396
#define free(a)
Definition: header.h:65
#define NULL
Definition: c.h:229
#define PQExpBufferBroken(str)
Definition: pqexpbuffer.h:59
#define realloc(a, b)
Definition: header.h:60
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:145
void appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
Definition: pqexpbuffer.c:415
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:89
static bool appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) pg_attribute_printf(2
Definition: pqexpbuffer.c:286
#define INITIAL_EXPBUFFER_SIZE
Definition: pqexpbuffer.h:76
int enlargePQExpBuffer(PQExpBuffer str, size_t needed)
Definition: pqexpbuffer.c:171