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