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-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" 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 323324 : AlignedAllocFree(void *pointer) 30 : { 31 323324 : 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 323324 : 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 323324 : pfree(unaligned); 49 323324 : } 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 0 : AlignedAllocRealloc(void *pointer, Size size, int flags) 61 : { 62 0 : 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 0 : alignto = MemoryChunkGetValue(redirchunk); 72 0 : 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 0 : 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 0 : ctx = GetMemoryChunkContext(unaligned); 100 0 : 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 0 : if (likely(newptr != NULL)) 107 : { 108 : VALGRIND_MAKE_MEM_DEFINED(pointer, old_size); 109 0 : memcpy(newptr, pointer, Min(size, old_size)); 110 : } 111 0 : pfree(unaligned); 112 : 113 0 : return newptr; 114 : } 115 : 116 : /* 117 : * AlignedAllocGetChunkContext 118 : * Return the MemoryContext that 'pointer' belongs to. 119 : */ 120 : MemoryContext 121 0 : AlignedAllocGetChunkContext(void *pointer) 122 : { 123 0 : MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer); 124 : MemoryContext cxt; 125 : 126 : VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk)); 127 : 128 : Assert(!MemoryChunkIsExternal(redirchunk)); 129 : 130 0 : cxt = GetMemoryChunkContext(MemoryChunkGetBlock(redirchunk)); 131 : 132 : VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk)); 133 : 134 0 : 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 143 0 : AlignedAllocGetChunkSpace(void *pointer) 144 : { 145 0 : MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer); 146 : void *unaligned; 147 : Size space; 148 : 149 : VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk)); 150 : 151 0 : unaligned = MemoryChunkGetBlock(redirchunk); 152 0 : space = GetMemoryChunkSpace(unaligned); 153 : 154 : VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk)); 155 : 156 0 : return space; 157 : }