PostgreSQL Source Code  git master
alignedalloc.c
Go to the documentation of this file.
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-2024, 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"
23 
24 /*
25  * AlignedAllocFree
26 * Frees allocated memory; memory is removed from its owning context.
27 */
28 void
29 AlignedAllocFree(void *pointer)
30 {
32  void *unaligned;
33 
35 
37 
38  /* obtain the original (unaligned) allocated pointer */
39  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  pfree(unaligned);
49 }
50 
51 /*
52  * AlignedAllocRealloc
53  * Change the allocated size of a chunk and return possibly a different
54  * pointer to a memory address aligned to the same boundary as the
55  * originally requested alignment. The contents of 'pointer' will be
56  * copied into the returned pointer up until 'size'. Any additional
57  * memory will be uninitialized.
58  */
59 void *
60 AlignedAllocRealloc(void *pointer, Size size, int flags)
61 {
62  MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
63  Size alignto;
64  void *unaligned;
65  MemoryContext ctx;
66  Size old_size;
67  void *newptr;
68 
69  VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
70 
71  alignto = MemoryChunkGetValue(redirchunk);
72  unaligned = MemoryChunkGetBlock(redirchunk);
73 
74  /* sanity check this is a power of 2 value */
75  Assert((alignto & (alignto - 1)) == 0);
76 
77  /*
78  * Determine the size of the original allocation. We can't determine this
79  * exactly as GetMemoryChunkSpace() returns the total space used for the
80  * allocation, which for contexts like aset includes rounding up to the
81  * next power of 2. However, this value is just used to memcpy() the old
82  * data into the new allocation, so we only need to concern ourselves with
83  * not reading beyond the end of the original allocation's memory. The
84  * drawback here is that we may copy more bytes than we need to, which
85  * only amounts to wasted effort. We can safely subtract the extra bytes
86  * that we requested to allow us to align the pointer. We must also
87  * subtract the space for the unaligned pointer's MemoryChunk since
88  * GetMemoryChunkSpace should have included that. This does assume that
89  * all context types use MemoryChunk as a chunk header.
90  */
91  old_size = GetMemoryChunkSpace(unaligned) -
92  PallocAlignedExtraBytes(alignto) - sizeof(MemoryChunk);
93 
94 #ifdef MEMORY_CONTEXT_CHECKING
95  /* check that GetMemoryChunkSpace returned something realistic */
96  Assert(old_size >= redirchunk->requested_size);
97 #endif
98 
99  ctx = GetMemoryChunkContext(unaligned);
100  newptr = MemoryContextAllocAligned(ctx, size, alignto, flags);
101 
102  /*
103  * We may memcpy beyond the end of the original allocation request size,
104  * so we must mark the entire allocation as defined.
105  */
106  if (likely(newptr != NULL))
107  {
108  VALGRIND_MAKE_MEM_DEFINED(pointer, old_size);
109  memcpy(newptr, pointer, Min(size, old_size));
110  }
111  pfree(unaligned);
112 
113  return newptr;
114 }
115 
116 /*
117  * AlignedAllocGetChunkContext
118  * Return the MemoryContext that 'pointer' belongs to.
119  */
122 {
123  MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
124  MemoryContext cxt;
125 
126  VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
127 
128  Assert(!MemoryChunkIsExternal(redirchunk));
129 
130  cxt = GetMemoryChunkContext(MemoryChunkGetBlock(redirchunk));
131 
132  VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
133 
134  return cxt;
135 }
136 
137 /*
138  * AlignedAllocGetChunkSpace
139  * Given a currently-allocated chunk, determine the total space
140  * it occupies (including all memory-allocation overhead).
141  */
142 Size
144 {
145  MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
146  void *unaligned;
147  Size space;
148 
149  VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
150 
151  unaligned = MemoryChunkGetBlock(redirchunk);
152  space = GetMemoryChunkSpace(unaligned);
153 
154  VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
155 
156  return space;
157 }
MemoryContext AlignedAllocGetChunkContext(void *pointer)
Definition: alignedalloc.c:121
void * AlignedAllocRealloc(void *pointer, Size size, int flags)
Definition: alignedalloc.c:60
Size AlignedAllocGetChunkSpace(void *pointer)
Definition: alignedalloc.c:143
void AlignedAllocFree(void *pointer)
Definition: alignedalloc.c:29
#define Min(x, y)
Definition: c.h:1004
#define likely(x)
Definition: c.h:310
#define Assert(condition)
Definition: c.h:858
size_t Size
Definition: c.h:605
#define WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:224
uint64 chunk
void * MemoryContextAllocAligned(MemoryContext context, Size size, Size alignto, int flags)
Definition: mcxt.c:1408
void pfree(void *pointer)
Definition: mcxt.c:1520
Size GetMemoryChunkSpace(void *pointer)
Definition: mcxt.c:721
MemoryContext GetMemoryChunkContext(void *pointer)
Definition: mcxt.c:707
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
#define PallocAlignedExtraBytes(alignto)
static Size MemoryChunkGetValue(MemoryChunk *chunk)
static bool MemoryChunkIsExternal(MemoryChunk *chunk)
struct MemoryChunk MemoryChunk
static void * MemoryChunkGetBlock(MemoryChunk *chunk)
#define PointerGetMemoryChunk(p)
static pg_noinline void Size size
Definition: slab.c:607
const char * name