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-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"
23
24/*
25 * AlignedAllocFree
26* Frees allocated memory; memory is removed from its owning context.
27*/
28void
29AlignedAllocFree(void *pointer)
30{
31 MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
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 */
59void *
60AlignedAllocRealloc(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
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 */
142Size
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:961
#define likely(x)
Definition: c.h:332
#define Assert(condition)
Definition: c.h:815
size_t Size
Definition: c.h:562
#define WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:225
void pfree(void *pointer)
Definition: mcxt.c:1521
Size GetMemoryChunkSpace(void *pointer)
Definition: mcxt.c:721
void * MemoryContextAllocAligned(MemoryContext context, Size size, Size alignto, int flags)
Definition: mcxt.c:1409
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)
static void * MemoryChunkGetBlock(MemoryChunk *chunk)
struct MemoryChunk MemoryChunk
#define PointerGetMemoryChunk(p)
static pg_noinline void Size size
Definition: slab.c:607
const char * name