]> granicus.if.org Git - postgresql/blob - src/backend/utils/mmgr/mcxt.c
Out-of-bounds memory allocation request sizes should be treated as just
[postgresql] / src / backend / utils / mmgr / mcxt.c
1 /*-------------------------------------------------------------------------
2  *
3  * mcxt.c
4  *        POSTGRES memory context management code.
5  *
6  * This module handles context management operations that are independent
7  * of the particular kind of context being operated on.  It calls
8  * context-type-specific operations via the function pointers in a
9  * context's MemoryContextMethods struct.
10  *
11  *
12  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  *
16  * IDENTIFICATION
17  *        $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.27 2001/02/06 01:53:53 tgl Exp $
18  *
19  *-------------------------------------------------------------------------
20  */
21
22 #include "postgres.h"
23
24 #include "nodes/memnodes.h"
25 #include "utils/excid.h"
26 #include "utils/memutils.h"
27
28
29 /*****************************************************************************
30  *        GLOBAL MEMORY                                                                                                                  *
31  *****************************************************************************/
32
33 /*
34  * CurrentMemoryContext
35  *              Default memory context for allocations.
36  */
37 MemoryContext CurrentMemoryContext = NULL;
38
39 /*
40  * Standard top-level contexts
41  */
42 MemoryContext TopMemoryContext = NULL;
43 MemoryContext ErrorContext = NULL;
44 MemoryContext PostmasterContext = NULL;
45 MemoryContext CacheMemoryContext = NULL;
46 MemoryContext QueryContext = NULL;
47 MemoryContext TopTransactionContext = NULL;
48 MemoryContext TransactionCommandContext = NULL;
49
50
51 /*****************************************************************************
52  *        EXPORTED ROUTINES                                                                                                              *
53  *****************************************************************************/
54
55
56 /*
57  * MemoryContextInit
58  *              Start up the memory-context subsystem.
59  *
60  * This must be called before creating contexts or allocating memory in
61  * contexts.  TopMemoryContext and ErrorContext are initialized here;
62  * other contexts must be created afterwards.
63  *
64  * In normal multi-backend operation, this is called once during
65  * postmaster startup, and not at all by individual backend startup
66  * (since the backends inherit an already-initialized context subsystem
67  * by virtue of being forked off the postmaster).
68  *
69  * In a standalone backend this must be called during backend startup.
70  */
71 void
72 MemoryContextInit(void)
73 {
74         AssertState(TopMemoryContext == NULL);
75         /*
76          * Initialize TopMemoryContext as an AllocSetContext with slow
77          * growth rate --- we don't really expect much to be allocated in it.
78          *
79          * (There is special-case code in MemoryContextCreate() for this call.)
80          */
81         TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
82                                                                                          "TopMemoryContext",
83                                                                                          8 * 1024,
84                                                                                          8 * 1024,
85                                                                                          8 * 1024);
86         /*
87          * Not having any other place to point CurrentMemoryContext,
88          * make it point to TopMemoryContext.  Caller should change this soon!
89          */
90         CurrentMemoryContext = TopMemoryContext;
91         /*
92          * Initialize ErrorContext as an AllocSetContext with slow
93          * growth rate --- we don't really expect much to be allocated in it.
94          * More to the point, require it to contain at least 8K at all times.
95          * This is the only case where retained memory in a context is
96          * *essential* --- we want to be sure ErrorContext still has some
97          * memory even if we've run out elsewhere!
98          */
99         ErrorContext = AllocSetContextCreate(TopMemoryContext,
100                                                                                  "ErrorContext",
101                                                                                  8 * 1024,
102                                                                                  8 * 1024,
103                                                                                  8 * 1024);
104 }
105
106 /*
107  * MemoryContextReset
108  *              Release all space allocated within a context and its descendants,
109  *              but don't delete the contexts themselves.
110  *
111  * The type-specific reset routine handles the context itself, but we
112  * have to do the recursion for the children.
113  */
114 void
115 MemoryContextReset(MemoryContext context)
116 {
117         AssertArg(MemoryContextIsValid(context));
118
119         MemoryContextResetChildren(context);
120         (*context->methods->reset) (context);
121 }
122
123 /*
124  * MemoryContextResetChildren
125  *              Release all space allocated within a context's descendants,
126  *              but don't delete the contexts themselves.  The named context
127  *              itself is not touched.
128  */
129 void
130 MemoryContextResetChildren(MemoryContext context)
131 {
132         MemoryContext   child;
133
134         AssertArg(MemoryContextIsValid(context));
135
136         for (child = context->firstchild; child != NULL; child = child->nextchild)
137         {
138                 MemoryContextReset(child);
139         }
140 }
141
142 /*
143  * MemoryContextDelete
144  *              Delete a context and its descendants, and release all space
145  *              allocated therein.
146  *
147  * The type-specific delete routine removes all subsidiary storage
148  * for the context, but we have to delete the context node itself,
149  * as well as recurse to get the children.  We must also delink the
150  * node from its parent, if it has one.
151  */
152 void
153 MemoryContextDelete(MemoryContext context)
154 {
155         AssertArg(MemoryContextIsValid(context));
156         /* We had better not be deleting TopMemoryContext ... */
157         Assert(context != TopMemoryContext);
158         /* And not CurrentMemoryContext, either */
159         Assert(context != CurrentMemoryContext);
160
161         MemoryContextDeleteChildren(context);
162         /*
163          * We delink the context from its parent before deleting it,
164          * so that if there's an error we won't have deleted/busted
165          * contexts still attached to the context tree.  Better a leak
166          * than a crash.
167          */
168         if (context->parent)
169         {
170                 MemoryContext   parent = context->parent;
171
172                 if (context == parent->firstchild)
173                 {
174                         parent->firstchild = context->nextchild;
175                 }
176                 else
177                 {
178                         MemoryContext   child;
179
180                         for (child = parent->firstchild; child; child = child->nextchild)
181                         {
182                                 if (context == child->nextchild)
183                                 {
184                                         child->nextchild = context->nextchild;
185                                         break;
186                                 }
187                         }
188                 }
189         }
190         (*context->methods->delete) (context);
191         pfree(context);
192 }
193
194 /*
195  * MemoryContextDeleteChildren
196  *              Delete all the descendants of the named context and release all
197  *              space allocated therein.  The named context itself is not touched.
198  */
199 void
200 MemoryContextDeleteChildren(MemoryContext context)
201 {
202         AssertArg(MemoryContextIsValid(context));
203         /*
204          * MemoryContextDelete will delink the child from me,
205          * so just iterate as long as there is a child.
206          */
207         while (context->firstchild != NULL)
208         {
209                 MemoryContextDelete(context->firstchild);
210         }
211 }
212
213 /*
214  * MemoryContextResetAndDeleteChildren
215  *              Release all space allocated within a context and delete all
216  *              its descendants.
217  *
218  * This is a common combination case where we want to preserve the
219  * specific context but get rid of absolutely everything under it.
220  */
221 void
222 MemoryContextResetAndDeleteChildren(MemoryContext context)
223 {
224         AssertArg(MemoryContextIsValid(context));
225
226         MemoryContextDeleteChildren(context);
227         (*context->methods->reset) (context);
228 }
229
230 /*
231  * MemoryContextStats
232  *              Print statistics about the named context and all its descendants.
233  *
234  * This is just a debugging utility, so it's not fancy.  The statistics
235  * are merely sent to stderr.
236  */
237 void
238 MemoryContextStats(MemoryContext context)
239 {
240         MemoryContext   child;
241
242         AssertArg(MemoryContextIsValid(context));
243
244         (*context->methods->stats) (context);
245         for (child = context->firstchild; child != NULL; child = child->nextchild)
246         {
247                 MemoryContextStats(child);
248         }
249 }
250
251
252 /*
253  * MemoryContextCheck
254  *              Check all chunks in the named context.
255  *
256  * This is just a debugging utility, so it's not fancy.  
257  */
258 #ifdef MEMORY_CONTEXT_CHECKING
259 void
260 MemoryContextCheck(MemoryContext context)
261 {
262         MemoryContext   child;
263
264         AssertArg(MemoryContextIsValid(context));
265
266         (*context->methods->check) (context);
267         for (child = context->firstchild; child != NULL; child = child->nextchild)
268         {
269                 MemoryContextCheck(child);
270         }
271 }
272 #endif
273
274 /*
275  * MemoryContextContains
276  *              Detect whether an allocated chunk of memory belongs to a given
277  *              context or not.
278  *
279  * Caution: this test is reliable as long as 'pointer' does point to
280  * a chunk of memory allocated from *some* context.  If 'pointer' points
281  * at memory obtained in some other way, there is a small chance of a
282  * false-positive result, since the bits right before it might look like
283  * a valid chunk header by chance.
284  */
285 bool
286 MemoryContextContains(MemoryContext context, void *pointer)
287 {
288         StandardChunkHeader        *header;
289
290         /*
291          * Try to detect bogus pointers handed to us, poorly though we can.
292          * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
293          * an allocated chunk.
294          */
295         if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
296                 return false;
297         /*
298          * OK, it's probably safe to look at the chunk header.
299          */
300         header = (StandardChunkHeader *)
301                 ((char *) pointer - STANDARDCHUNKHEADERSIZE);
302         /*
303          * If the context link doesn't match then we certainly have a
304          * non-member chunk.  Also check for a reasonable-looking size
305          * as extra guard against being fooled by bogus pointers.
306          */
307         if (header->context == context && AllocSizeIsValid(header->size))
308                 return true;
309         return false;
310 }
311
312 /*--------------------
313  * MemoryContextCreate
314  *              Context-type-independent part of context creation.
315  *
316  * This is only intended to be called by context-type-specific
317  * context creation routines, not by the unwashed masses.
318  *
319  * The context creation procedure is a little bit tricky because
320  * we want to be sure that we don't leave the context tree invalid
321  * in case of failure (such as insufficient memory to allocate the
322  * context node itself).  The procedure goes like this:
323  *      1.      Context-type-specific routine first calls MemoryContextCreate(),
324  *              passing the appropriate tag/size/methods values (the methods
325  *              pointer will ordinarily point to statically allocated data).
326  *              The parent and name parameters usually come from the caller.
327  *      2.      MemoryContextCreate() attempts to allocate the context node,
328  *              plus space for the name.  If this fails we can elog() with no
329  *              damage done.
330  *      3.      We fill in all of the type-independent MemoryContext fields.
331  *      4.      We call the type-specific init routine (using the methods pointer).
332  *              The init routine is required to make the node minimally valid
333  *              with zero chance of failure --- it can't allocate more memory,
334  *              for example.
335  *      5.      Now we have a minimally valid node that can behave correctly
336  *              when told to reset or delete itself.  We link the node to its
337  *              parent (if any), making the node part of the context tree.
338  *      6.      We return to the context-type-specific routine, which finishes
339  *              up type-specific initialization.  This routine can now do things
340  *              that might fail (like allocate more memory), so long as it's
341  *              sure the node is left in a state that delete will handle.
342  *
343  * This protocol doesn't prevent us from leaking memory if step 6 fails
344  * during creation of a top-level context, since there's no parent link
345  * in that case.  However, if you run out of memory while you're building
346  * a top-level context, you might as well go home anyway...
347  *
348  * Normally, the context node and the name are allocated from
349  * TopMemoryContext (NOT from the parent context, since the node must
350  * survive resets of its parent context!).  However, this routine is itself
351  * used to create TopMemoryContext!  If we see that TopMemoryContext is NULL,
352  * we assume we are creating TopMemoryContext and use malloc() to allocate
353  * the node.
354  *
355  * Note that the name field of a MemoryContext does not point to
356  * separately-allocated storage, so it should not be freed at context
357  * deletion.
358  *--------------------
359  */
360 MemoryContext
361 MemoryContextCreate(NodeTag tag, Size size,
362                                         MemoryContextMethods *methods,
363                                         MemoryContext parent,
364                                         const char *name)
365 {
366         MemoryContext   node;
367         Size                    needed = size + strlen(name) + 1;
368
369         /* Get space for node and name */
370         if (TopMemoryContext != NULL)
371         {
372                 /* Normal case: allocate the node in TopMemoryContext */
373                 node = (MemoryContext) MemoryContextAlloc(TopMemoryContext,
374                                                                                                   needed);
375         }
376         else
377         {
378                 /* Special case for startup: use good ol' malloc */
379                 node = (MemoryContext) malloc(needed);
380                 Assert(node != NULL);
381         }
382
383         /* Initialize the node as best we can */
384         MemSet(node, 0, size);
385         node->type = tag;
386         node->methods = methods;
387         node->parent = NULL;            /* for the moment */
388         node->firstchild = NULL;
389         node->nextchild = NULL;
390         node->name = ((char *) node) + size;
391         strcpy(node->name, name);
392
393         /* Type-specific routine finishes any other essential initialization */
394         (*node->methods->init) (node);
395
396         /* OK to link node to parent (if any) */
397         if (parent)
398         {
399                 node->parent = parent;
400                 node->nextchild = parent->firstchild;
401                 parent->firstchild = node;
402         }
403
404         /* Return to type-specific creation routine to finish up */
405         return node;
406 }
407
408 /*
409  * MemoryContextAlloc
410  *              Allocate space within the specified context.
411  *
412  * This could be turned into a macro, but we'd have to import
413  * nodes/memnodes.h into postgres.h which seems a bad idea.
414  */
415 void *
416 MemoryContextAlloc(MemoryContext context, Size size)
417 {
418         AssertArg(MemoryContextIsValid(context));
419
420         if (!AllocSizeIsValid(size))
421                 elog(ERROR, "MemoryContextAlloc: invalid request size %lu",
422                          (unsigned long) size);
423
424         return (*context->methods->alloc) (context, size);
425 }
426
427 /*
428  * pfree
429  *              Release an allocated chunk.
430  */
431 void
432 pfree(void *pointer)
433 {
434         StandardChunkHeader        *header;
435
436         /*
437          * Try to detect bogus pointers handed to us, poorly though we can.
438          * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
439          * an allocated chunk.
440          */
441         Assert(pointer != NULL);
442         Assert(pointer == (void *) MAXALIGN(pointer));
443         /*
444          * OK, it's probably safe to look at the chunk header.
445          */
446         header = (StandardChunkHeader *)
447                 ((char *) pointer - STANDARDCHUNKHEADERSIZE);
448
449         AssertArg(MemoryContextIsValid(header->context));
450
451     (*header->context->methods->free_p) (header->context, pointer);
452 }
453
454 /*
455  * repalloc
456  *
457  */
458 void *
459 repalloc(void *pointer, Size size)
460 {
461         StandardChunkHeader        *header;
462
463         /*
464          * Try to detect bogus pointers handed to us, poorly though we can.
465          * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
466          * an allocated chunk.
467          */
468         Assert(pointer != NULL);
469         Assert(pointer == (void *) MAXALIGN(pointer));
470         /*
471          * OK, it's probably safe to look at the chunk header.
472          */
473         header = (StandardChunkHeader *)
474                 ((char *) pointer - STANDARDCHUNKHEADERSIZE);
475
476         AssertArg(MemoryContextIsValid(header->context));
477
478         if (!AllocSizeIsValid(size))
479                 elog(ERROR, "repalloc: invalid request size %lu",
480                          (unsigned long) size);
481
482     return (*header->context->methods->realloc) (header->context,
483                                                                                                  pointer, size);
484 }
485
486 /*
487  * MemoryContextSwitchTo
488  *              Returns the current context; installs the given context.
489  */
490 MemoryContext
491 MemoryContextSwitchTo(MemoryContext context)
492 {
493         MemoryContext old;
494
495         AssertArg(MemoryContextIsValid(context));
496
497         old = CurrentMemoryContext;
498         CurrentMemoryContext = context;
499         return old;
500 }
501
502 /*
503  * MemoryContextStrdup
504  *              Like strdup(), but allocate from the specified context
505  */
506 char *
507 MemoryContextStrdup(MemoryContext context, const char *string)
508 {
509         char       *nstr;
510         Size            len = strlen(string) + 1;
511
512         nstr = (char *) MemoryContextAlloc(context, len);
513
514         memcpy(nstr, string, len);
515
516         return nstr;
517 }