| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * psprintf.c |
| 4 | * sprintf into an allocated-on-demand buffer |
| 5 | * |
| 6 | * |
| 7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 8 | * Portions Copyright (c) 1994, Regents of the University of California |
| 9 | * |
| 10 | * |
| 11 | * IDENTIFICATION |
| 12 | * src/common/psprintf.c |
| 13 | * |
| 14 | *------------------------------------------------------------------------- |
| 15 | */ |
| 16 | |
| 17 | #ifndef FRONTEND |
| 18 | |
| 19 | #include "postgres.h" |
| 20 | |
| 21 | #include "utils/memutils.h" |
| 22 | |
| 23 | #else |
| 24 | |
| 25 | #include "postgres_fe.h" |
| 26 | |
| 27 | /* It's possible we could use a different value for this in frontend code */ |
| 28 | #define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */ |
| 29 | |
| 30 | #endif |
| 31 | |
| 32 | |
| 33 | /* |
| 34 | * psprintf |
| 35 | * |
| 36 | * Format text data under the control of fmt (an sprintf-style format string) |
| 37 | * and return it in an allocated-on-demand buffer. The buffer is allocated |
| 38 | * with palloc in the backend, or malloc in frontend builds. Caller is |
| 39 | * responsible to free the buffer when no longer needed, if appropriate. |
| 40 | * |
| 41 | * Errors are not returned to the caller, but are reported via elog(ERROR) |
| 42 | * in the backend, or printf-to-stderr-and-exit() in frontend builds. |
| 43 | * One should therefore think twice about using this in libpq. |
| 44 | */ |
| 45 | char * |
| 46 | psprintf(const char *fmt,...) |
| 47 | { |
| 48 | int save_errno = errno; |
| 49 | size_t len = 128; /* initial assumption about buffer size */ |
| 50 | |
| 51 | for (;;) |
| 52 | { |
| 53 | char *result; |
| 54 | va_list args; |
| 55 | size_t newlen; |
| 56 | |
| 57 | /* |
| 58 | * Allocate result buffer. Note that in frontend this maps to malloc |
| 59 | * with exit-on-error. |
| 60 | */ |
| 61 | result = (char *) palloc(len); |
| 62 | |
| 63 | /* Try to format the data. */ |
| 64 | errno = save_errno; |
| 65 | va_start(args, fmt); |
| 66 | newlen = pvsnprintf(result, len, fmt, args); |
| 67 | va_end(args); |
| 68 | |
| 69 | if (newlen < len) |
| 70 | return result; /* success */ |
| 71 | |
| 72 | /* Release buffer and loop around to try again with larger len. */ |
| 73 | pfree(result); |
| 74 | len = newlen; |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | /* |
| 79 | * pvsnprintf |
| 80 | * |
| 81 | * Attempt to format text data under the control of fmt (an sprintf-style |
| 82 | * format string) and insert it into buf (which has length len). |
| 83 | * |
| 84 | * If successful, return the number of bytes emitted, not counting the |
| 85 | * trailing zero byte. This will always be strictly less than len. |
| 86 | * |
| 87 | * If there's not enough space in buf, return an estimate of the buffer size |
| 88 | * needed to succeed (this *must* be more than the given len, else callers |
| 89 | * might loop infinitely). |
| 90 | * |
| 91 | * Other error cases do not return, but exit via elog(ERROR) or exit(). |
| 92 | * Hence, this shouldn't be used inside libpq. |
| 93 | * |
| 94 | * Caution: callers must be sure to preserve their entry-time errno |
| 95 | * when looping, in case the fmt contains "%m". |
| 96 | * |
| 97 | * Note that the semantics of the return value are not exactly C99's. |
| 98 | * First, we don't promise that the estimated buffer size is exactly right; |
| 99 | * callers must be prepared to loop multiple times to get the right size. |
| 100 | * (Given a C99-compliant vsnprintf, that won't happen, but it is rumored |
| 101 | * that some implementations don't always return the same value ...) |
| 102 | * Second, we return the recommended buffer size, not one less than that; |
| 103 | * this lets overflow concerns be handled here rather than in the callers. |
| 104 | */ |
| 105 | size_t |
| 106 | pvsnprintf(char *buf, size_t len, const char *fmt, va_list args) |
| 107 | { |
| 108 | int nprinted; |
| 109 | |
| 110 | nprinted = vsnprintf(buf, len, fmt, args); |
| 111 | |
| 112 | /* We assume failure means the fmt is bogus, hence hard failure is OK */ |
| 113 | if (unlikely(nprinted < 0)) |
| 114 | { |
| 115 | #ifndef FRONTEND |
| 116 | elog(ERROR, "vsnprintf failed: %m with format string \"%s\"" , fmt); |
| 117 | #else |
| 118 | fprintf(stderr, "vsnprintf failed: %s with format string \"%s\"\n" , |
| 119 | strerror(errno), fmt); |
| 120 | exit(EXIT_FAILURE); |
| 121 | #endif |
| 122 | } |
| 123 | |
| 124 | if ((size_t) nprinted < len) |
| 125 | { |
| 126 | /* Success. Note nprinted does not include trailing null. */ |
| 127 | return (size_t) nprinted; |
| 128 | } |
| 129 | |
| 130 | /* |
| 131 | * We assume a C99-compliant vsnprintf, so believe its estimate of the |
| 132 | * required space, and add one for the trailing null. (If it's wrong, the |
| 133 | * logic will still work, but we may loop multiple times.) |
| 134 | * |
| 135 | * Choke if the required space would exceed MaxAllocSize. Note we use |
| 136 | * this palloc-oriented overflow limit even when in frontend. |
| 137 | */ |
| 138 | if (unlikely((size_t) nprinted > MaxAllocSize - 1)) |
| 139 | { |
| 140 | #ifndef FRONTEND |
| 141 | ereport(ERROR, |
| 142 | (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
| 143 | errmsg("out of memory" ))); |
| 144 | #else |
| 145 | fprintf(stderr, _("out of memory\n" )); |
| 146 | exit(EXIT_FAILURE); |
| 147 | #endif |
| 148 | } |
| 149 | |
| 150 | return nprinted + 1; |
| 151 | } |
| 152 | |