LCOV - code coverage report
Current view: top level - src/common - fe_memutils.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 54.1 % 111 60
Test Date: 2026-05-21 11:16:33 Functions: 69.2 % 26 18
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * fe_memutils.c
       4              :  *    memory management support for frontend code
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/common/fe_memutils.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : 
      16              : #ifndef FRONTEND
      17              : #error "This file is not expected to be compiled for backend code"
      18              : #endif
      19              : 
      20              : #include "postgres_fe.h"
      21              : 
      22              : #include "common/int.h"
      23              : 
      24              : pg_noreturn static pg_noinline void add_size_error(Size s1, Size s2);
      25              : pg_noreturn static pg_noinline void mul_size_error(Size s1, Size s2);
      26              : 
      27              : 
      28              : static inline void *
      29      5203772 : pg_malloc_internal(size_t size, int flags)
      30              : {
      31              :     void       *tmp;
      32              : 
      33              :     /* Avoid unportable behavior of malloc(0) */
      34      5203772 :     if (size == 0)
      35         4445 :         size = 1;
      36      5203772 :     tmp = malloc(size);
      37      5203772 :     if (tmp == NULL)
      38              :     {
      39            0 :         if ((flags & MCXT_ALLOC_NO_OOM) == 0)
      40              :         {
      41            0 :             fprintf(stderr, _("out of memory\n"));
      42            0 :             exit(EXIT_FAILURE);
      43              :         }
      44            0 :         return NULL;
      45              :     }
      46              : 
      47      5203772 :     if ((flags & MCXT_ALLOC_ZERO) != 0)
      48      6456854 :         MemSet(tmp, 0, size);
      49      5203772 :     return tmp;
      50              : }
      51              : 
      52              : void *
      53      2229453 : pg_malloc(size_t size)
      54              : {
      55      2229453 :     return pg_malloc_internal(size, 0);
      56              : }
      57              : 
      58              : void *
      59      1677337 : pg_malloc0(size_t size)
      60              : {
      61      1677337 :     return pg_malloc_internal(size, MCXT_ALLOC_ZERO);
      62              : }
      63              : 
      64              : void *
      65       245740 : pg_malloc_extended(size_t size, int flags)
      66              : {
      67       245740 :     return pg_malloc_internal(size, flags);
      68              : }
      69              : 
      70              : void *
      71        95559 : pg_realloc(void *ptr, size_t size)
      72              : {
      73              :     void       *tmp;
      74              : 
      75              :     /* Avoid unportable behavior of realloc(NULL, 0) */
      76        95559 :     if (ptr == NULL && size == 0)
      77            0 :         size = 1;
      78        95559 :     tmp = realloc(ptr, size);
      79        95559 :     if (!tmp)
      80              :     {
      81            0 :         fprintf(stderr, _("out of memory\n"));
      82            0 :         exit(EXIT_FAILURE);
      83              :     }
      84        95559 :     return tmp;
      85              : }
      86              : 
      87              : /*
      88              :  * "Safe" wrapper around strdup().
      89              :  */
      90              : char *
      91      8596081 : pg_strdup(const char *in)
      92              : {
      93              :     char       *tmp;
      94              : 
      95      8596081 :     if (!in)
      96              :     {
      97            0 :         fprintf(stderr,
      98            0 :                 _("cannot duplicate null pointer (internal error)\n"));
      99            0 :         exit(EXIT_FAILURE);
     100              :     }
     101      8596081 :     tmp = strdup(in);
     102      8596081 :     if (!tmp)
     103              :     {
     104            0 :         fprintf(stderr, _("out of memory\n"));
     105            0 :         exit(EXIT_FAILURE);
     106              :     }
     107      8596081 :     return tmp;
     108              : }
     109              : 
     110              : void
     111      5465319 : pg_free(void *ptr)
     112              : {
     113      5465319 :     free(ptr);
     114      5465319 : }
     115              : 
     116              : /*
     117              :  * Frontend emulation of backend memory management functions.  Useful for
     118              :  * programs that compile backend files.
     119              :  */
     120              : void *
     121      1047648 : palloc(Size size)
     122              : {
     123      1047648 :     return pg_malloc_internal(size, 0);
     124              : }
     125              : 
     126              : void *
     127         3099 : palloc0(Size size)
     128              : {
     129         3099 :     return pg_malloc_internal(size, MCXT_ALLOC_ZERO);
     130              : }
     131              : 
     132              : void *
     133          495 : palloc_extended(Size size, int flags)
     134              : {
     135          495 :     return pg_malloc_internal(size, flags);
     136              : }
     137              : 
     138              : void
     139      2601925 : pfree(void *pointer)
     140              : {
     141      2601925 :     pg_free(pointer);
     142      2601925 : }
     143              : 
     144              : char *
     145      1260813 : pstrdup(const char *in)
     146              : {
     147      1260813 :     return pg_strdup(in);
     148              : }
     149              : 
     150              : char *
     151          317 : pnstrdup(const char *in, Size size)
     152              : {
     153              :     char       *tmp;
     154              :     int         len;
     155              : 
     156          317 :     if (!in)
     157              :     {
     158            0 :         fprintf(stderr,
     159            0 :                 _("cannot duplicate null pointer (internal error)\n"));
     160            0 :         exit(EXIT_FAILURE);
     161              :     }
     162              : 
     163          317 :     len = strnlen(in, size);
     164          317 :     tmp = malloc(len + 1);
     165          317 :     if (tmp == NULL)
     166              :     {
     167            0 :         fprintf(stderr, _("out of memory\n"));
     168            0 :         exit(EXIT_FAILURE);
     169              :     }
     170              : 
     171          317 :     memcpy(tmp, in, len);
     172          317 :     tmp[len] = '\0';
     173              : 
     174          317 :     return tmp;
     175              : }
     176              : 
     177              : void *
     178        58948 : repalloc(void *pointer, Size size)
     179              : {
     180        58948 :     return pg_realloc(pointer, size);
     181              : }
     182              : 
     183              : /*
     184              :  * Support for safe calculation of memory request sizes
     185              :  *
     186              :  * These functions perform the requested calculation, but throw error if the
     187              :  * result overflows.
     188              :  *
     189              :  * An important property of these functions is that if an argument was a
     190              :  * negative signed int before promotion (implying overflow in calculating it)
     191              :  * we will detect that as an error.  That happens because we reject results
     192              :  * larger than SIZE_MAX / 2.  In the backend we rely on later checks to do
     193              :  * that, but in frontend we must do it here.
     194              :  */
     195              : Size
     196            0 : add_size(Size s1, Size s2)
     197              : {
     198              :     Size        result;
     199              : 
     200            0 :     if (unlikely(pg_add_size_overflow(s1, s2, &result) ||
     201              :                  result > (SIZE_MAX / 2)))
     202            0 :         add_size_error(s1, s2);
     203            0 :     return result;
     204              : }
     205              : 
     206              : pg_noreturn static pg_noinline void
     207            0 : add_size_error(Size s1, Size s2)
     208              : {
     209            0 :     fprintf(stderr, _("invalid memory allocation request size %zu + %zu\n"),
     210              :             s1, s2);
     211            0 :     exit(EXIT_FAILURE);
     212              : }
     213              : 
     214              : Size
     215            0 : mul_size(Size s1, Size s2)
     216              : {
     217              :     Size        result;
     218              : 
     219            0 :     if (unlikely(pg_mul_size_overflow(s1, s2, &result) ||
     220              :                  result > (SIZE_MAX / 2)))
     221            0 :         mul_size_error(s1, s2);
     222            0 :     return result;
     223              : }
     224              : 
     225              : pg_noreturn static pg_noinline void
     226            0 : mul_size_error(Size s1, Size s2)
     227              : {
     228            0 :     fprintf(stderr, _("invalid memory allocation request size %zu * %zu\n"),
     229              :             s1, s2);
     230            0 :     exit(EXIT_FAILURE);
     231              : }
     232              : 
     233              : /*
     234              :  * pg_malloc_mul
     235              :  *      Equivalent to pg_malloc(mul_size(s1, s2)).
     236              :  */
     237              : void *
     238      1264169 : pg_malloc_mul(Size s1, Size s2)
     239              : {
     240              :     /* inline mul_size() for efficiency */
     241              :     Size        req;
     242              : 
     243      1264169 :     if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
     244              :                  req > (SIZE_MAX / 2)))
     245            0 :         mul_size_error(s1, s2);
     246      1264169 :     return pg_malloc(req);
     247              : }
     248              : 
     249              : /*
     250              :  * pg_malloc0_mul
     251              :  *      Equivalent to pg_malloc0(mul_size(s1, s2)).
     252              :  *
     253              :  * This is comparable to standard calloc's behavior.
     254              :  */
     255              : void *
     256      1549747 : pg_malloc0_mul(Size s1, Size s2)
     257              : {
     258              :     /* inline mul_size() for efficiency */
     259              :     Size        req;
     260              : 
     261      1549747 :     if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
     262              :                  req > (SIZE_MAX / 2)))
     263            0 :         mul_size_error(s1, s2);
     264      1549747 :     return pg_malloc0(req);
     265              : }
     266              : 
     267              : /*
     268              :  * pg_malloc_mul_extended
     269              :  *      Equivalent to pg_malloc_extended(mul_size(s1, s2), flags).
     270              :  */
     271              : void *
     272            0 : pg_malloc_mul_extended(Size s1, Size s2, int flags)
     273              : {
     274              :     /* inline mul_size() for efficiency */
     275              :     Size        req;
     276              : 
     277            0 :     if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
     278              :                  req > (SIZE_MAX / 2)))
     279            0 :         mul_size_error(s1, s2);
     280            0 :     return pg_malloc_extended(req, flags);
     281              : }
     282              : 
     283              : /*
     284              :  * pg_realloc_mul
     285              :  *      Equivalent to pg_realloc(p, mul_size(s1, s2)).
     286              :  */
     287              : void *
     288        35249 : pg_realloc_mul(void *p, Size s1, Size s2)
     289              : {
     290              :     /* inline mul_size() for efficiency */
     291              :     Size        req;
     292              : 
     293        35249 :     if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
     294              :                  req > (SIZE_MAX / 2)))
     295            0 :         mul_size_error(s1, s2);
     296        35249 :     return pg_realloc(p, req);
     297              : }
     298              : 
     299              : /*
     300              :  * palloc_mul
     301              :  *      Equivalent to palloc(mul_size(s1, s2)).
     302              :  */
     303              : void *
     304         3780 : palloc_mul(Size s1, Size s2)
     305              : {
     306              :     /* inline mul_size() for efficiency */
     307              :     Size        req;
     308              : 
     309         3780 :     if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
     310              :                  req > (SIZE_MAX / 2)))
     311            0 :         mul_size_error(s1, s2);
     312         3780 :     return palloc(req);
     313              : }
     314              : 
     315              : /*
     316              :  * palloc0_mul
     317              :  *      Equivalent to palloc0(mul_size(s1, s2)).
     318              :  *
     319              :  * This is comparable to standard calloc's behavior.
     320              :  */
     321              : void *
     322            0 : palloc0_mul(Size s1, Size s2)
     323              : {
     324              :     /* inline mul_size() for efficiency */
     325              :     Size        req;
     326              : 
     327            0 :     if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
     328              :                  req > (SIZE_MAX / 2)))
     329            0 :         mul_size_error(s1, s2);
     330            0 :     return palloc0(req);
     331              : }
     332              : 
     333              : /*
     334              :  * palloc_mul_extended
     335              :  *      Equivalent to palloc_extended(mul_size(s1, s2), flags).
     336              :  */
     337              : void *
     338            0 : palloc_mul_extended(Size s1, Size s2, int flags)
     339              : {
     340              :     /* inline mul_size() for efficiency */
     341              :     Size        req;
     342              : 
     343            0 :     if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
     344              :                  req > (SIZE_MAX / 2)))
     345            0 :         mul_size_error(s1, s2);
     346            0 :     return palloc_extended(req, flags);
     347              : }
     348              : 
     349              : /*
     350              :  * repalloc_mul
     351              :  *      Equivalent to repalloc(p, mul_size(s1, s2)).
     352              :  */
     353              : void *
     354            0 : repalloc_mul(void *p, Size s1, Size s2)
     355              : {
     356              :     /* inline mul_size() for efficiency */
     357              :     Size        req;
     358              : 
     359            0 :     if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
     360              :                  req > (SIZE_MAX / 2)))
     361            0 :         mul_size_error(s1, s2);
     362            0 :     return repalloc(p, req);
     363              : }
        

Generated by: LCOV version 2.0-1