Line data Source code
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
49 0 : markPQExpBufferBroken(PQExpBuffer str)
50 : {
51 0 : if (str->data != oom_buffer)
52 0 : 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 0 : str->data = (char *) oom_buffer;
61 0 : str->len = 0;
62 0 : str->maxlen = 0;
63 0 : }
64 :
65 : /*
66 : * createPQExpBuffer
67 : *
68 : * Create an empty 'PQExpBufferData' & return a pointer to it.
69 : */
70 : PQExpBuffer
71 749 : createPQExpBuffer(void)
72 : {
73 : PQExpBuffer res;
74 :
75 749 : res = (PQExpBuffer) malloc(sizeof(PQExpBufferData));
76 749 : if (res != NULL)
77 749 : initPQExpBuffer(res);
78 :
79 749 : 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
89 13839 : initPQExpBuffer(PQExpBuffer str)
90 : {
91 13839 : str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
92 13839 : if (str->data == NULL)
93 : {
94 0 : str->data = (char *) oom_buffer; /* see comment above */
95 0 : str->maxlen = 0;
96 0 : str->len = 0;
97 : }
98 : else
99 : {
100 13839 : str->maxlen = INITIAL_EXPBUFFER_SIZE;
101 13839 : str->len = 0;
102 13839 : str->data[0] = '\0';
103 : }
104 13839 : }
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
113 567 : destroyPQExpBuffer(PQExpBuffer str)
114 : {
115 567 : if (str)
116 : {
117 567 : termPQExpBuffer(str);
118 567 : free(str);
119 : }
120 567 : }
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
128 11955 : termPQExpBuffer(PQExpBuffer str)
129 : {
130 11955 : if (str->data != oom_buffer)
131 11955 : free(str->data);
132 : /* just for luck, make the buffer validly empty. */
133 11955 : str->data = (char *) oom_buffer; /* see comment above */
134 11955 : str->maxlen = 0;
135 11955 : str->len = 0;
136 11955 : }
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
145 242482 : resetPQExpBuffer(PQExpBuffer str)
146 : {
147 242482 : if (str)
148 : {
149 242482 : if (str->data != oom_buffer)
150 : {
151 242482 : str->len = 0;
152 242482 : str->data[0] = '\0';
153 : }
154 : else
155 : {
156 : /* try to reinitialize to valid state */
157 0 : initPQExpBuffer(str);
158 : }
159 : }
160 242482 : }
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 782673 : enlargePQExpBuffer(PQExpBuffer str, size_t needed)
172 : {
173 : size_t newlen;
174 : char *newdata;
175 :
176 782673 : if (PQExpBufferBroken(str))
177 0 : 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 782673 : if (needed >= ((size_t) INT_MAX - str->len))
185 : {
186 0 : markPQExpBufferBroken(str);
187 0 : return 0;
188 : }
189 :
190 782673 : needed += str->len + 1; /* total space required now */
191 :
192 : /* Because of the above test, we now have needed <= INT_MAX */
193 :
194 782673 : if (needed <= str->maxlen)
195 781915 : 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 758 : newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64;
203 1690 : while (needed > newlen)
204 174 : 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 758 : if (newlen > (size_t) INT_MAX)
212 0 : newlen = (size_t) INT_MAX;
213 :
214 758 : newdata = (char *) realloc(str->data, newlen);
215 758 : if (newdata != NULL)
216 : {
217 758 : str->data = newdata;
218 758 : str->maxlen = newlen;
219 758 : return 1;
220 : }
221 :
222 0 : markPQExpBufferBroken(str);
223 0 : 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 2847 : printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
235 : {
236 : va_list args;
237 : bool done;
238 :
239 2847 : resetPQExpBuffer(str);
240 :
241 2847 : if (PQExpBufferBroken(str))
242 2847 : return; /* already failed */
243 :
244 : /* Loop in case we have to retry after enlarging the buffer. */
245 : do
246 : {
247 3087 : va_start(args, fmt);
248 3087 : done = appendPQExpBufferVA(str, fmt, args);
249 3087 : va_end(args);
250 3087 : } 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 9208 : appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
263 : {
264 : va_list args;
265 : bool done;
266 :
267 9208 : if (PQExpBufferBroken(str))
268 9208 : return; /* already failed */
269 :
270 : /* Loop in case we have to retry after enlarging the buffer. */
271 : do
272 : {
273 9395 : va_start(args, fmt);
274 9395 : done = appendPQExpBufferVA(str, fmt, args);
275 9395 : va_end(args);
276 9395 : } 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 12482 : 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 12482 : 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 12466 : avail = str->maxlen - str->len - 1;
303 :
304 12466 : errno = 0;
305 :
306 12466 : nprinted = vsnprintf(str->data + str->len, avail, fmt, args);
307 :
308 : /*
309 : * If vsnprintf reports an error other than ENOMEM, fail.
310 : */
311 12466 : if (nprinted < 0 && errno != 0 && errno != ENOMEM)
312 : {
313 0 : markPQExpBufferBroken(str);
314 0 : 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 12466 : if (nprinted >= 0 && (size_t) nprinted < avail - 1)
324 : {
325 : /* Success. Note nprinted does not include trailing null. */
326 12055 : str->len += nprinted;
327 12055 : return true;
328 : }
329 :
330 411 : 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 403 : if (nprinted > INT_MAX - 2)
344 : {
345 0 : markPQExpBufferBroken(str);
346 0 : return true;
347 : }
348 403 : 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 8 : if (avail >= INT_MAX / 2)
358 0 : needed = INT_MAX;
359 : else
360 8 : 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 16 : needed = 32;
370 : }
371 :
372 : /* Increase the buffer size and try again. */
373 427 : if (!enlargePQExpBuffer(str, needed))
374 0 : return true; /* oops, out of memory */
375 :
376 427 : 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 98535 : appendPQExpBufferStr(PQExpBuffer str, const char *data)
386 : {
387 98535 : appendBinaryPQExpBuffer(str, data, strlen(data));
388 98535 : }
389 :
390 : /*
391 : * appendPQExpBufferChar
392 : * Append a single byte to str.
393 : * Like appendPQExpBuffer(str, "%c", ch) but much faster.
394 : */
395 : void
396 52726 : appendPQExpBufferChar(PQExpBuffer str, char ch)
397 : {
398 : /* Make more room if needed */
399 52726 : if (!enlargePQExpBuffer(str, 1))
400 52726 : return;
401 :
402 : /* OK, append the character */
403 52726 : str->data[str->len] = ch;
404 52726 : str->len++;
405 52726 : 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 729247 : appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
416 : {
417 : /* Make more room if needed */
418 729247 : if (!enlargePQExpBuffer(str, datalen))
419 729247 : return;
420 :
421 : /* OK, append the data */
422 729247 : memcpy(str->data + str->len, data, datalen);
423 729247 : str->len += datalen;
424 :
425 : /*
426 : * Keep a trailing null in place, even though it's probably useless for
427 : * binary data...
428 : */
429 729247 : str->data[str->len] = '\0';
430 : }
|