LCOV - code coverage report
Current view: top level - src/backend/utils/mmgr - alignedalloc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18beta1 Lines: 5 26 19.2 %
Date: 2025-06-07 12:18:21 Functions: 1 4 25.0 %
Legend: Lines: hit not hit

          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-2025, 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      332024 : AlignedAllocFree(void *pointer)
      30             : {
      31      332024 :     MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
      32             :     void       *unaligned;
      33             : 
      34             :     VALGRIND_MAKE_MEM_DEFINED(chunk, sizeof(MemoryChunk));
      35             : 
      36             :     Assert(!MemoryChunkIsExternal(chunk));
      37             : 
      38             :     /* obtain the original (unaligned) allocated pointer */
      39      332024 :     unaligned = MemoryChunkGetBlock(chunk);
      40             : 
      41             : #ifdef MEMORY_CONTEXT_CHECKING
      42             :     /* Test for someone scribbling on unused space in chunk */
      43             :     if (!sentinel_ok(pointer, chunk->requested_size))
      44             :         elog(WARNING, "detected write past chunk end in %s %p",
      45             :              GetMemoryChunkContext(unaligned)->name, chunk);
      46             : #endif
      47             : 
      48             :     /* Recursively pfree the unaligned chunk */
      49      332024 :     pfree(unaligned);
      50      332024 : }
      51             : 
      52             : /*
      53             :  * AlignedAllocRealloc
      54             :  *      Change the allocated size of a chunk and return possibly a different
      55             :  *      pointer to a memory address aligned to the same boundary as the
      56             :  *      originally requested alignment.  The contents of 'pointer' will be
      57             :  *      copied into the returned pointer up until 'size'.  Any additional
      58             :  *      memory will be uninitialized.
      59             :  */
      60             : void *
      61           0 : AlignedAllocRealloc(void *pointer, Size size, int flags)
      62             : {
      63           0 :     MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
      64             :     Size        alignto;
      65             :     void       *unaligned;
      66             :     MemoryContext ctx;
      67             :     Size        old_size;
      68             :     void       *newptr;
      69             : 
      70             :     VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
      71             : 
      72           0 :     alignto = MemoryChunkGetValue(redirchunk);
      73           0 :     unaligned = MemoryChunkGetBlock(redirchunk);
      74             : 
      75             :     /* sanity check this is a power of 2 value */
      76             :     Assert((alignto & (alignto - 1)) == 0);
      77             : 
      78             :     /*
      79             :      * Determine the size of the original allocation.  We can't determine this
      80             :      * exactly as GetMemoryChunkSpace() returns the total space used for the
      81             :      * allocation, which for contexts like aset includes rounding up to the
      82             :      * next power of 2.  However, this value is just used to memcpy() the old
      83             :      * data into the new allocation, so we only need to concern ourselves with
      84             :      * not reading beyond the end of the original allocation's memory.  The
      85             :      * drawback here is that we may copy more bytes than we need to, which
      86             :      * only amounts to wasted effort.  We can safely subtract the extra bytes
      87             :      * that we requested to allow us to align the pointer.  We must also
      88             :      * subtract the space for the unaligned pointer's MemoryChunk since
      89             :      * GetMemoryChunkSpace should have included that.  This does assume that
      90             :      * all context types use MemoryChunk as a chunk header.
      91             :      */
      92           0 :     old_size = GetMemoryChunkSpace(unaligned) -
      93             :         PallocAlignedExtraBytes(alignto) - sizeof(MemoryChunk);
      94             : 
      95             : #ifdef MEMORY_CONTEXT_CHECKING
      96             :     /* check that GetMemoryChunkSpace returned something realistic */
      97             :     Assert(old_size >= redirchunk->requested_size);
      98             : #endif
      99             : 
     100             :     /*
     101             :      * To keep things simple, we always allocate a new aligned chunk and copy
     102             :      * data into it.  Because of the above inaccuracy, this may end in copying
     103             :      * more data than was in the original allocation request size, but that
     104             :      * should be OK.
     105             :      */
     106           0 :     ctx = GetMemoryChunkContext(unaligned);
     107           0 :     newptr = MemoryContextAllocAligned(ctx, size, alignto, flags);
     108             : 
     109             :     /* Cope cleanly with OOM */
     110           0 :     if (unlikely(newptr == NULL))
     111             :     {
     112             :         VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
     113           0 :         return MemoryContextAllocationFailure(ctx, size, flags);
     114             :     }
     115             : 
     116             :     /*
     117             :      * We may memcpy more than the original allocation request size, which
     118             :      * would result in trying to copy trailing bytes that the original
     119             :      * MemoryContextAllocAligned call marked NOACCESS.  So we must mark the
     120             :      * entire old_size as defined.  That's slightly annoying, but probably not
     121             :      * worth improving.
     122             :      */
     123             :     VALGRIND_MAKE_MEM_DEFINED(pointer, old_size);
     124           0 :     memcpy(newptr, pointer, Min(size, old_size));
     125             : 
     126           0 :     pfree(unaligned);
     127             : 
     128           0 :     return newptr;
     129             : }
     130             : 
     131             : /*
     132             :  * AlignedAllocGetChunkContext
     133             :  *      Return the MemoryContext that 'pointer' belongs to.
     134             :  */
     135             : MemoryContext
     136           0 : AlignedAllocGetChunkContext(void *pointer)
     137             : {
     138           0 :     MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
     139             :     MemoryContext cxt;
     140             : 
     141             :     VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
     142             : 
     143             :     Assert(!MemoryChunkIsExternal(redirchunk));
     144             : 
     145           0 :     cxt = GetMemoryChunkContext(MemoryChunkGetBlock(redirchunk));
     146             : 
     147             :     VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
     148             : 
     149           0 :     return cxt;
     150             : }
     151             : 
     152             : /*
     153             :  * AlignedAllocGetChunkSpace
     154             :  *      Given a currently-allocated chunk, determine the total space
     155             :  *      it occupies (including all memory-allocation overhead).
     156             :  */
     157             : Size
     158           0 : AlignedAllocGetChunkSpace(void *pointer)
     159             : {
     160           0 :     MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
     161             :     void       *unaligned;
     162             :     Size        space;
     163             : 
     164             :     VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
     165             : 
     166           0 :     unaligned = MemoryChunkGetBlock(redirchunk);
     167           0 :     space = GetMemoryChunkSpace(unaligned);
     168             : 
     169             :     VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
     170             : 
     171           0 :     return space;
     172             : }

Generated by: LCOV version 1.16