|
32 | 32 | #include "utils/memutils_internal.h"
|
33 | 33 |
|
34 | 34 |
|
| 35 | +static void BogusFree(void *pointer); |
| 36 | +static void *BogusRealloc(void *pointer, Size size); |
| 37 | +static MemoryContext BogusGetChunkContext(void *pointer); |
| 38 | +static Size BogusGetChunkSpace(void *pointer); |
| 39 | + |
35 | 40 | /*****************************************************************************
|
36 | 41 | * GLOBAL MEMORY *
|
37 | 42 | *****************************************************************************/
|
@@ -74,10 +79,42 @@ static const MemoryContextMethods mcxt_methods[] = {
|
74 | 79 | [MCTX_SLAB_ID].get_chunk_context = SlabGetChunkContext,
|
75 | 80 | [MCTX_SLAB_ID].get_chunk_space = SlabGetChunkSpace,
|
76 | 81 | [MCTX_SLAB_ID].is_empty = SlabIsEmpty,
|
77 |
| - [MCTX_SLAB_ID].stats = SlabStats |
| 82 | + [MCTX_SLAB_ID].stats = SlabStats, |
78 | 83 | #ifdef MEMORY_CONTEXT_CHECKING
|
79 |
| - ,[MCTX_SLAB_ID].check = SlabCheck |
| 84 | + [MCTX_SLAB_ID].check = SlabCheck, |
80 | 85 | #endif
|
| 86 | + |
| 87 | + /* |
| 88 | + * Unused (as yet) IDs should have dummy entries here. This allows us to |
| 89 | + * fail cleanly if a bogus pointer is passed to pfree or the like. It |
| 90 | + * seems sufficient to provide routines for the methods that might get |
| 91 | + * invoked from inspection of a chunk (see MCXT_METHOD calls below). |
| 92 | + */ |
| 93 | + |
| 94 | + [MCTX_UNUSED1_ID].free_p = BogusFree, |
| 95 | + [MCTX_UNUSED1_ID].realloc = BogusRealloc, |
| 96 | + [MCTX_UNUSED1_ID].get_chunk_context = BogusGetChunkContext, |
| 97 | + [MCTX_UNUSED1_ID].get_chunk_space = BogusGetChunkSpace, |
| 98 | + |
| 99 | + [MCTX_UNUSED2_ID].free_p = BogusFree, |
| 100 | + [MCTX_UNUSED2_ID].realloc = BogusRealloc, |
| 101 | + [MCTX_UNUSED2_ID].get_chunk_context = BogusGetChunkContext, |
| 102 | + [MCTX_UNUSED2_ID].get_chunk_space = BogusGetChunkSpace, |
| 103 | + |
| 104 | + [MCTX_UNUSED3_ID].free_p = BogusFree, |
| 105 | + [MCTX_UNUSED3_ID].realloc = BogusRealloc, |
| 106 | + [MCTX_UNUSED3_ID].get_chunk_context = BogusGetChunkContext, |
| 107 | + [MCTX_UNUSED3_ID].get_chunk_space = BogusGetChunkSpace, |
| 108 | + |
| 109 | + [MCTX_UNUSED4_ID].free_p = BogusFree, |
| 110 | + [MCTX_UNUSED4_ID].realloc = BogusRealloc, |
| 111 | + [MCTX_UNUSED4_ID].get_chunk_context = BogusGetChunkContext, |
| 112 | + [MCTX_UNUSED4_ID].get_chunk_space = BogusGetChunkSpace, |
| 113 | + |
| 114 | + [MCTX_UNUSED5_ID].free_p = BogusFree, |
| 115 | + [MCTX_UNUSED5_ID].realloc = BogusRealloc, |
| 116 | + [MCTX_UNUSED5_ID].get_chunk_context = BogusGetChunkContext, |
| 117 | + [MCTX_UNUSED5_ID].get_chunk_space = BogusGetChunkSpace, |
81 | 118 | };
|
82 | 119 |
|
83 | 120 | /*
|
@@ -125,6 +162,77 @@ static void MemoryContextStatsPrint(MemoryContext context, void *passthru,
|
125 | 162 | #define MCXT_METHOD(pointer, method) \
|
126 | 163 | mcxt_methods[GetMemoryChunkMethodID(pointer)].method
|
127 | 164 |
|
| 165 | +/* |
| 166 | + * GetMemoryChunkMethodID |
| 167 | + * Return the MemoryContextMethodID from the uint64 chunk header which |
| 168 | + * directly precedes 'pointer'. |
| 169 | + */ |
| 170 | +static inline MemoryContextMethodID |
| 171 | +GetMemoryChunkMethodID(const void *pointer) |
| 172 | +{ |
| 173 | + uint64 header; |
| 174 | + |
| 175 | + /* |
| 176 | + * Try to detect bogus pointers handed to us, poorly though we can. |
| 177 | + * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an |
| 178 | + * allocated chunk. |
| 179 | + */ |
| 180 | + Assert(pointer == (const void *) MAXALIGN(pointer)); |
| 181 | + |
| 182 | + header = *((const uint64 *) ((const char *) pointer - sizeof(uint64))); |
| 183 | + |
| 184 | + return (MemoryContextMethodID) (header & MEMORY_CONTEXT_METHODID_MASK); |
| 185 | +} |
| 186 | + |
| 187 | +/* |
| 188 | + * GetMemoryChunkHeader |
| 189 | + * Return the uint64 chunk header which directly precedes 'pointer'. |
| 190 | + * |
| 191 | + * This is only used after GetMemoryChunkMethodID, so no need for error checks. |
| 192 | + */ |
| 193 | +static inline uint64 |
| 194 | +GetMemoryChunkHeader(const void *pointer) |
| 195 | +{ |
| 196 | + return *((const uint64 *) ((const char *) pointer - sizeof(uint64))); |
| 197 | +} |
| 198 | + |
| 199 | +/* |
| 200 | + * Support routines to trap use of invalid memory context method IDs |
| 201 | + * (from calling pfree or the like on a bogus pointer). As a possible |
| 202 | + * aid in debugging, we report the header word along with the pointer |
| 203 | + * address (if we got here, there must be an accessible header word). |
| 204 | + */ |
| 205 | +static void |
| 206 | +BogusFree(void *pointer) |
| 207 | +{ |
| 208 | + elog(ERROR, "pfree called with invalid pointer %p (header 0x%016llx)", |
| 209 | + pointer, (long long) GetMemoryChunkHeader(pointer)); |
| 210 | +} |
| 211 | + |
| 212 | +static void * |
| 213 | +BogusRealloc(void *pointer, Size size) |
| 214 | +{ |
| 215 | + elog(ERROR, "repalloc called with invalid pointer %p (header 0x%016llx)", |
| 216 | + pointer, (long long) GetMemoryChunkHeader(pointer)); |
| 217 | + return NULL; /* keep compiler quiet */ |
| 218 | +} |
| 219 | + |
| 220 | +static MemoryContext |
| 221 | +BogusGetChunkContext(void *pointer) |
| 222 | +{ |
| 223 | + elog(ERROR, "GetMemoryChunkContext called with invalid pointer %p (header 0x%016llx)", |
| 224 | + pointer, (long long) GetMemoryChunkHeader(pointer)); |
| 225 | + return NULL; /* keep compiler quiet */ |
| 226 | +} |
| 227 | + |
| 228 | +static Size |
| 229 | +BogusGetChunkSpace(void *pointer) |
| 230 | +{ |
| 231 | + elog(ERROR, "GetMemoryChunkSpace called with invalid pointer %p (header 0x%016llx)", |
| 232 | + pointer, (long long) GetMemoryChunkHeader(pointer)); |
| 233 | + return 0; /* keep compiler quiet */ |
| 234 | +} |
| 235 | + |
128 | 236 |
|
129 | 237 | /*****************************************************************************
|
130 | 238 | * EXPORTED ROUTINES *
|
|
0 commit comments