Skip to content

Commit 88177f7

Browse files
committed
Code review for palloc0 patch --- avoid dangerous and unnecessary
practice of evaluating MemSet's arguments multiple times, except for the special case of newNode(), where we can assume the argument is a constant sizeof() operator. Also, add GetMemoryChunkContext() to mcxt.c's API, in preparation for fixing recent GEQO breakage.
1 parent e64c7fe commit 88177f7

File tree

6 files changed

+160
-52
lines changed

6 files changed

+160
-52
lines changed

src/backend/nodes/nodes.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,19 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.18 2002/11/10 02:17:25 momjian Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.19 2002/12/16 16:22:46 tgl Exp $
1313
*
1414
* HISTORY
1515
* Andrew Yu Oct 20, 1994 file creation
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
1919
#include "postgres.h"
20+
2021
#include "nodes/nodes.h"
2122

2223
/*
23-
* newNode -
24-
* create a new node of the specified size and tag the node with the
25-
* specified tag.
26-
*
27-
* !WARNING!: Avoid using newNode directly. You should be using the
28-
* macro makeNode. eg. to create a Resdom node, use makeNode(Resdom)
29-
*
24+
* Support for newNode() macro
3025
*/
31-
Node *newNodeMacroHolder;
3226

27+
Node *newNodeMacroHolder;

src/backend/utils/mmgr/mcxt.c

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
*
1616
* IDENTIFICATION
17-
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.37 2002/12/15 21:01:34 tgl Exp $
17+
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.38 2002/12/16 16:22:46 tgl Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -257,6 +257,35 @@ GetMemoryChunkSpace(void *pointer)
257257
pointer);
258258
}
259259

260+
/*
261+
* GetMemoryChunkContext
262+
* Given a currently-allocated chunk, determine the context
263+
* it belongs to.
264+
*/
265+
MemoryContext
266+
GetMemoryChunkContext(void *pointer)
267+
{
268+
StandardChunkHeader *header;
269+
270+
/*
271+
* Try to detect bogus pointers handed to us, poorly though we can.
272+
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
273+
* allocated chunk.
274+
*/
275+
Assert(pointer != NULL);
276+
Assert(pointer == (void *) MAXALIGN(pointer));
277+
278+
/*
279+
* OK, it's probably safe to look at the chunk header.
280+
*/
281+
header = (StandardChunkHeader *)
282+
((char *) pointer - STANDARDCHUNKHEADERSIZE);
283+
284+
AssertArg(MemoryContextIsValid(header->context));
285+
286+
return header->context;
287+
}
288+
260289
/*
261290
* MemoryContextStats
262291
* Print statistics about the named context and all its descendants.
@@ -453,25 +482,52 @@ MemoryContextAlloc(MemoryContext context, Size size)
453482
}
454483

455484
/*
456-
* MemoryContextAllocPalloc0
485+
* MemoryContextAllocZero
457486
* Like MemoryContextAlloc, but clears allocated memory
458487
*
459488
* We could just call MemoryContextAlloc then clear the memory, but this
460-
* function is called too many times, so we have a separate version.
489+
* is a very common combination, so we provide the combined operation.
461490
*/
462491
void *
463-
MemoryContextAllocPalloc0(MemoryContext context, Size size)
492+
MemoryContextAllocZero(MemoryContext context, Size size)
464493
{
465494
void *ret;
466495

467496
AssertArg(MemoryContextIsValid(context));
468497

469498
if (!AllocSizeIsValid(size))
470-
elog(ERROR, "MemoryContextAllocZero: invalid request size %lu",
499+
elog(ERROR, "MemoryContextAlloc: invalid request size %lu",
471500
(unsigned long) size);
472501

473502
ret = (*context->methods->alloc) (context, size);
503+
504+
MemSetAligned(ret, 0, size);
505+
506+
return ret;
507+
}
508+
509+
/*
510+
* MemoryContextAllocZeroAligned
511+
* MemoryContextAllocZero where length is suitable for MemSetLoop
512+
*
513+
* This might seem overly specialized, but it's not because newNode()
514+
* is so often called with compile-time-constant sizes.
515+
*/
516+
void *
517+
MemoryContextAllocZeroAligned(MemoryContext context, Size size)
518+
{
519+
void *ret;
520+
521+
AssertArg(MemoryContextIsValid(context));
522+
523+
if (!AllocSizeIsValid(size))
524+
elog(ERROR, "MemoryContextAlloc: invalid request size %lu",
525+
(unsigned long) size);
526+
527+
ret = (*context->methods->alloc) (context, size);
528+
474529
MemSetLoop(ret, 0, size);
530+
475531
return ret;
476532
}
477533

src/include/c.h

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
15-
* $Id: c.h,v 1.133 2002/12/05 04:04:48 momjian Exp $
15+
* $Id: c.h,v 1.134 2002/12/16 16:22:46 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -579,38 +579,78 @@ typedef NameData *Name;
579579
* memset() functions. More research needs to be done, perhaps with
580580
* platform-specific MEMSET_LOOP_LIMIT values or tests in configure.
581581
*
582-
* MemSet has been split into two parts so MemSetTest can be optimized
583-
* away for constant 'val' and 'len'. This is used by palloc0().
584-
*
585-
* Note, arguments are evaluated more than once.
586-
*
587582
* bjm 2002-10-08
588583
*/
584+
#define MemSet(start, val, len) \
585+
do \
586+
{ \
587+
int32 * _start = (int32 *) (start); \
588+
int _val = (val); \
589+
Size _len = (len); \
590+
\
591+
if ((((long) _start) & INT_ALIGN_MASK) == 0 && \
592+
(_len & INT_ALIGN_MASK) == 0 && \
593+
_val == 0 && \
594+
_len <= MEMSET_LOOP_LIMIT) \
595+
{ \
596+
int32 * _stop = (int32 *) ((char *) _start + _len); \
597+
while (_start < _stop) \
598+
*_start++ = 0; \
599+
} \
600+
else \
601+
memset((char *) _start, _val, _len); \
602+
} while (0)
603+
604+
#define MEMSET_LOOP_LIMIT 1024
605+
606+
/*
607+
* MemSetAligned is the same as MemSet except it omits the test to see if
608+
* "start" is word-aligned. This is okay to use if the caller knows a-priori
609+
* that the pointer is suitably aligned (typically, because he just got it
610+
* from palloc(), which always delivers a max-aligned pointer).
611+
*/
612+
#define MemSetAligned(start, val, len) \
613+
do \
614+
{ \
615+
int32 * _start = (int32 *) (start); \
616+
int _val = (val); \
617+
Size _len = (len); \
618+
\
619+
if ((_len & INT_ALIGN_MASK) == 0 && \
620+
_val == 0 && \
621+
_len <= MEMSET_LOOP_LIMIT) \
622+
{ \
623+
int32 * _stop = (int32 *) ((char *) _start + _len); \
624+
while (_start < _stop) \
625+
*_start++ = 0; \
626+
} \
627+
else \
628+
memset((char *) _start, _val, _len); \
629+
} while (0)
630+
631+
632+
/*
633+
* MemSetTest/MemSetLoop are a variant version that allow all the tests in
634+
* MemSet to be done at compile time in cases where "val" and "len" are
635+
* constants *and* we know the "start" pointer must be word-aligned.
636+
* If MemSetTest succeeds, then it is okay to use MemSetLoop, otherwise use
637+
* MemSetAligned. Beware of multiple evaluations of the arguments when using
638+
* this approach.
639+
*/
589640
#define MemSetTest(val, len) \
590641
( ((len) & INT_ALIGN_MASK) == 0 && \
591642
(len) <= MEMSET_LOOP_LIMIT && \
592643
(val) == 0 )
593644

594645
#define MemSetLoop(start, val, len) \
595-
do \
596-
{ \
597-
int32 * _start = (int32 *) (start); \
598-
int32 * _stop = (int32 *) ((char *) _start + (len)); \
599-
\
600-
while (_start < _stop) \
601-
*_start++ = 0; \
602-
} while (0)
603-
604-
#define MemSet(start, val, len) \
605-
do \
606-
{ \
607-
if (MemSetTest(val, len) && ((long)(start) & INT_ALIGN_MASK) == 0 ) \
608-
MemSetLoop(start, val, len); \
609-
else \
610-
memset((char *)(start), (val), (len)); \
611-
} while (0)
612-
613-
#define MEMSET_LOOP_LIMIT 1024
646+
do \
647+
{ \
648+
int32 * _start = (int32 *) (start); \
649+
int32 * _stop = (int32 *) ((char *) _start + (Size) (len)); \
650+
\
651+
while (_start < _stop) \
652+
*_start++ = 0; \
653+
} while (0)
614654

615655

616656
/* ----------------------------------------------------------------

src/include/nodes/nodes.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: nodes.h,v 1.133 2002/12/14 00:17:59 tgl Exp $
10+
* $Id: nodes.h,v 1.134 2002/12/16 16:22:46 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -293,18 +293,24 @@ typedef struct Node
293293
#define nodeTag(nodeptr) (((Node*)(nodeptr))->type)
294294

295295
/*
296+
* newNode -
297+
* create a new node of the specified size and tag the node with the
298+
* specified tag.
299+
*
300+
* !WARNING!: Avoid using newNode directly. You should be using the
301+
* macro makeNode. eg. to create a Query node, use makeNode(Query)
302+
*
296303
* There is no way to dereference the palloc'ed pointer to assign the
297-
* tag, and return the pointer itself, so we need a holder variable.
298-
* Fortunately, this function isn't recursive so we just define
304+
* tag, and also return the pointer itself, so we need a holder variable.
305+
* Fortunately, this macro isn't recursive so we just define
299306
* a global variable for this purpose.
300307
*/
301308
extern Node *newNodeMacroHolder;
302309

303310
#define newNode(size, tag) \
304311
( \
305312
AssertMacro((size) >= sizeof(Node)), /* need the tag, at least */ \
306-
\
307-
newNodeMacroHolder = (Node *) palloc0(size), \
313+
newNodeMacroHolder = (Node *) palloc0fast(size), \
308314
newNodeMacroHolder->type = (tag), \
309315
newNodeMacroHolder \
310316
)

src/include/utils/memutils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
1111
* Portions Copyright (c) 1994, Regents of the University of California
1212
*
13-
* $Id: memutils.h,v 1.49 2002/12/15 21:01:34 tgl Exp $
13+
* $Id: memutils.h,v 1.50 2002/12/16 16:22:46 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -83,6 +83,7 @@ extern void MemoryContextResetChildren(MemoryContext context);
8383
extern void MemoryContextDeleteChildren(MemoryContext context);
8484
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
8585
extern Size GetMemoryChunkSpace(void *pointer);
86+
extern MemoryContext GetMemoryChunkContext(void *pointer);
8687
extern void MemoryContextStats(MemoryContext context);
8788

8889
#ifdef MEMORY_CONTEXT_CHECKING

src/include/utils/palloc.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
2222
* Portions Copyright (c) 1994, Regents of the University of California
2323
*
24-
* $Id: palloc.h,v 1.23 2002/11/13 00:37:06 momjian Exp $
24+
* $Id: palloc.h,v 1.24 2002/12/16 16:22:46 tgl Exp $
2525
*
2626
*-------------------------------------------------------------------------
2727
*/
@@ -46,15 +46,25 @@ extern DLLIMPORT MemoryContext CurrentMemoryContext;
4646
* Fundamental memory-allocation operations (more are in utils/memutils.h)
4747
*/
4848
extern void *MemoryContextAlloc(MemoryContext context, Size size);
49-
extern void *MemoryContextAllocPalloc0(MemoryContext context, Size size);
49+
extern void *MemoryContextAllocZero(MemoryContext context, Size size);
50+
extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size);
5051

5152
#define palloc(sz) MemoryContextAlloc(CurrentMemoryContext, (sz))
5253

53-
/* We assume palloc() is already int-aligned */
54-
#define palloc0(sz) \
55-
( MemSetTest(0, (sz)) ? \
56-
MemoryContextAllocPalloc0(CurrentMemoryContext, (sz)) : \
57-
memset(palloc(sz), 0, (sz)))
54+
#define palloc0(sz) MemoryContextAllocZero(CurrentMemoryContext, (sz))
55+
56+
/*
57+
* The result of palloc() is always word-aligned, so we can skip testing
58+
* alignment of the pointer when deciding which MemSet variant to use.
59+
* Note that this variant does not offer any advantage, and should not be
60+
* used, unless its "sz" argument is a compile-time constant; therefore, the
61+
* issue that it evaluates the argument multiple times isn't a problem in
62+
* practice.
63+
*/
64+
#define palloc0fast(sz) \
65+
( MemSetTest(0, sz) ? \
66+
MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) : \
67+
MemoryContextAllocZero(CurrentMemoryContext, sz) )
5868

5969
extern void pfree(void *pointer);
6070

0 commit comments

Comments
 (0)