LCOV - code coverage report
Current view: top level - src/backend/utils/mmgr - alignedalloc.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 18.2 % 55 10
Test Date: 2026-01-26 10:56:24 Functions: 25.0 % 4 1
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 11.1 % 18 2

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * alignedalloc.c
       4                 :             :  *        Allocator functions to implement palloc_aligned
       5                 :             :  *
       6                 :             :  * This is not a fully-fledged MemoryContext type as there is no means to
       7                 :             :  * create a MemoryContext of this type.  The code here only serves to allow
       8                 :             :  * operations such as pfree() and repalloc() to work correctly on a memory
       9                 :             :  * chunk that was allocated by palloc_aligned().
      10                 :             :  *
      11                 :             :  * Portions Copyright (c) 2022-2026, PostgreSQL Global Development Group
      12                 :             :  *
      13                 :             :  * IDENTIFICATION
      14                 :             :  *        src/backend/utils/mmgr/alignedalloc.c
      15                 :             :  *
      16                 :             :  *-------------------------------------------------------------------------
      17                 :             :  */
      18                 :             : 
      19                 :             : #include "postgres.h"
      20                 :             : 
      21                 :             : #include "utils/memdebug.h"
      22                 :             : #include "utils/memutils_memorychunk.h"
      23                 :             : 
      24                 :             : /*
      25                 :             :  * AlignedAllocFree
      26                 :             :  *              Frees allocated memory; memory is removed from its owning context.
      27                 :             :  */
      28                 :             : void
      29                 :        9723 : AlignedAllocFree(void *pointer)
      30                 :             : {
      31                 :        9723 :         MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
      32                 :        9723 :         void       *unaligned;
      33                 :             : 
      34                 :        9723 :         VALGRIND_MAKE_MEM_DEFINED(chunk, sizeof(MemoryChunk));
      35                 :             : 
      36         [ +  - ]:        9723 :         Assert(!MemoryChunkIsExternal(chunk));
      37                 :             : 
      38                 :             :         /* obtain the original (unaligned) allocated pointer */
      39                 :        9723 :         unaligned = MemoryChunkGetBlock(chunk);
      40                 :             : 
      41                 :             : #ifdef MEMORY_CONTEXT_CHECKING
      42                 :             :         /* Test for someone scribbling on unused space in chunk */
      43         [ +  - ]:        9723 :         if (!sentinel_ok(pointer, chunk->requested_size))
      44   [ #  #  #  # ]:           0 :                 elog(WARNING, "detected write past chunk end in %s %p",
      45                 :             :                          GetMemoryChunkContext(unaligned)->name, chunk);
      46                 :             : #endif
      47                 :             : 
      48                 :             :         /*
      49                 :             :          * Create a dummy vchunk covering the start of the unaligned chunk, but
      50                 :             :          * not overlapping the aligned chunk.  This will be freed while pfree'ing
      51                 :             :          * the unaligned chunk, keeping Valgrind happy.  Then when we return to
      52                 :             :          * the outer pfree, that will clean up the vchunk for the aligned chunk.
      53                 :             :          */
      54                 :        9723 :         VALGRIND_MEMPOOL_ALLOC(GetMemoryChunkContext(unaligned), unaligned,
      55                 :             :                                                    (char *) pointer - (char *) unaligned);
      56                 :             : 
      57                 :             :         /* Recursively pfree the unaligned chunk */
      58                 :        9723 :         pfree(unaligned);
      59                 :        9723 : }
      60                 :             : 
      61                 :             : /*
      62                 :             :  * AlignedAllocRealloc
      63                 :             :  *              Change the allocated size of a chunk and return possibly a different
      64                 :             :  *              pointer to a memory address aligned to the same boundary as the
      65                 :             :  *              originally requested alignment.  The contents of 'pointer' will be
      66                 :             :  *              copied into the returned pointer up until 'size'.  Any additional
      67                 :             :  *              memory will be uninitialized.
      68                 :             :  */
      69                 :             : void *
      70                 :           0 : AlignedAllocRealloc(void *pointer, Size size, int flags)
      71                 :             : {
      72                 :           0 :         MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
      73                 :           0 :         Size            alignto;
      74                 :           0 :         void       *unaligned;
      75                 :           0 :         MemoryContext ctx;
      76                 :           0 :         Size            old_size;
      77                 :           0 :         void       *newptr;
      78                 :             : 
      79                 :           0 :         VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
      80                 :             : 
      81                 :           0 :         alignto = MemoryChunkGetValue(redirchunk);
      82                 :           0 :         unaligned = MemoryChunkGetBlock(redirchunk);
      83                 :             : 
      84                 :             :         /* sanity check this is a power of 2 value */
      85         [ #  # ]:           0 :         Assert((alignto & (alignto - 1)) == 0);
      86                 :             : 
      87                 :             :         /*
      88                 :             :          * Determine the size of the original allocation.  We can't determine this
      89                 :             :          * exactly as GetMemoryChunkSpace() returns the total space used for the
      90                 :             :          * allocation, which for contexts like aset includes rounding up to the
      91                 :             :          * next power of 2.  However, this value is just used to memcpy() the old
      92                 :             :          * data into the new allocation, so we only need to concern ourselves with
      93                 :             :          * not reading beyond the end of the original allocation's memory.  The
      94                 :             :          * drawback here is that we may copy more bytes than we need to, which
      95                 :             :          * only amounts to wasted effort.  We can safely subtract the extra bytes
      96                 :             :          * that we requested to allow us to align the pointer.  We must also
      97                 :             :          * subtract the space for the unaligned pointer's MemoryChunk since
      98                 :             :          * GetMemoryChunkSpace should have included that.  This does assume that
      99                 :             :          * all context types use MemoryChunk as a chunk header.
     100                 :             :          */
     101                 :           0 :         old_size = GetMemoryChunkSpace(unaligned) -
     102                 :           0 :                 PallocAlignedExtraBytes(alignto) - sizeof(MemoryChunk);
     103                 :             : 
     104                 :             : #ifdef MEMORY_CONTEXT_CHECKING
     105                 :             :         /* check that GetMemoryChunkSpace returned something realistic */
     106         [ #  # ]:           0 :         Assert(old_size >= redirchunk->requested_size);
     107                 :             : #endif
     108                 :             : 
     109                 :             :         /*
     110                 :             :          * To keep things simple, we always allocate a new aligned chunk and copy
     111                 :             :          * data into it.  Because of the above inaccuracy, this may end in copying
     112                 :             :          * more data than was in the original allocation request size, but that
     113                 :             :          * should be OK.
     114                 :             :          */
     115                 :           0 :         ctx = GetMemoryChunkContext(unaligned);
     116                 :           0 :         newptr = MemoryContextAllocAligned(ctx, size, alignto, flags);
     117                 :             : 
     118                 :             :         /* Cope cleanly with OOM */
     119         [ #  # ]:           0 :         if (unlikely(newptr == NULL))
     120                 :             :         {
     121                 :           0 :                 VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
     122                 :           0 :                 return MemoryContextAllocationFailure(ctx, size, flags);
     123                 :             :         }
     124                 :             : 
     125                 :             :         /*
     126                 :             :          * We may memcpy more than the original allocation request size, which
     127                 :             :          * would result in trying to copy trailing bytes that the original
     128                 :             :          * MemoryContextAllocAligned call marked NOACCESS.  So we must mark the
     129                 :             :          * entire old_size as defined.  That's slightly annoying, but probably not
     130                 :             :          * worth improving.
     131                 :             :          */
     132                 :           0 :         VALGRIND_MAKE_MEM_DEFINED(pointer, old_size);
     133         [ #  # ]:           0 :         memcpy(newptr, pointer, Min(size, old_size));
     134                 :             : 
     135                 :             :         /*
     136                 :             :          * Create a dummy vchunk covering the start of the old unaligned chunk,
     137                 :             :          * but not overlapping the aligned chunk.  This will be freed while
     138                 :             :          * pfree'ing the old unaligned chunk, keeping Valgrind happy.  Then when
     139                 :             :          * we return to repalloc, it will move the vchunk for the aligned chunk.
     140                 :             :          */
     141                 :           0 :         VALGRIND_MEMPOOL_ALLOC(ctx, unaligned,
     142                 :             :                                                    (char *) pointer - (char *) unaligned);
     143                 :             : 
     144                 :           0 :         pfree(unaligned);
     145                 :             : 
     146                 :           0 :         return newptr;
     147                 :           0 : }
     148                 :             : 
     149                 :             : /*
     150                 :             :  * AlignedAllocGetChunkContext
     151                 :             :  *              Return the MemoryContext that 'pointer' belongs to.
     152                 :             :  */
     153                 :             : MemoryContext
     154                 :           0 : AlignedAllocGetChunkContext(void *pointer)
     155                 :             : {
     156                 :           0 :         MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
     157                 :           0 :         MemoryContext cxt;
     158                 :             : 
     159                 :           0 :         VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
     160                 :             : 
     161         [ #  # ]:           0 :         Assert(!MemoryChunkIsExternal(redirchunk));
     162                 :             : 
     163                 :           0 :         cxt = GetMemoryChunkContext(MemoryChunkGetBlock(redirchunk));
     164                 :             : 
     165                 :           0 :         VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
     166                 :             : 
     167                 :           0 :         return cxt;
     168                 :           0 : }
     169                 :             : 
     170                 :             : /*
     171                 :             :  * AlignedAllocGetChunkSpace
     172                 :             :  *              Given a currently-allocated chunk, determine the total space
     173                 :             :  *              it occupies (including all memory-allocation overhead).
     174                 :             :  */
     175                 :             : Size
     176                 :           0 : AlignedAllocGetChunkSpace(void *pointer)
     177                 :             : {
     178                 :           0 :         MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
     179                 :           0 :         void       *unaligned;
     180                 :           0 :         Size            space;
     181                 :             : 
     182                 :           0 :         VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
     183                 :             : 
     184                 :           0 :         unaligned = MemoryChunkGetBlock(redirchunk);
     185                 :           0 :         space = GetMemoryChunkSpace(unaligned);
     186                 :             : 
     187                 :           0 :         VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
     188                 :             : 
     189                 :           0 :         return space;
     190                 :           0 : }
        

Generated by: LCOV version 2.3.2-1