LCOV - code coverage report
Current view: top level - src/common - psprintf.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 76.9 % 26 20
Test Date: 2026-03-12 06:14:44 Functions: 100.0 % 2 2
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1