mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
Add some debug support code to try to catch future mistakes in the area of
input functions that include garbage bytes in their results. Provide a compile-time option RANDOMIZE_ALLOCATED_MEMORY to make palloc fill returned blocks with variable contents. This option also makes the parser perform conversions of literal constants twice and compare the results, emitting a WARNING if they don't match. (This is the code I used to catch the input function bugs fixed in the previous commit.) For the moment, I've set it to be activated automatically by --enable-cassert.
This commit is contained in:
parent
c846f7ca8a
commit
65c3d05e18
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.94 2008/01/01 19:45:51 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.95 2008/04/11 22:54:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/datum.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
@ -485,13 +486,38 @@ typeTypeRelid(Type typ)
|
|||||||
Datum
|
Datum
|
||||||
stringTypeDatum(Type tp, char *string, int32 atttypmod)
|
stringTypeDatum(Type tp, char *string, int32 atttypmod)
|
||||||
{
|
{
|
||||||
Oid typinput;
|
Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
|
||||||
Oid typioparam;
|
Oid typinput = typform->typinput;
|
||||||
|
Oid typioparam = getTypeIOParam(tp);
|
||||||
|
Datum result;
|
||||||
|
|
||||||
typinput = ((Form_pg_type) GETSTRUCT(tp))->typinput;
|
result = OidInputFunctionCall(typinput, string,
|
||||||
typioparam = getTypeIOParam(tp);
|
typioparam, atttypmod);
|
||||||
return OidInputFunctionCall(typinput, string,
|
|
||||||
typioparam, atttypmod);
|
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
||||||
|
/*
|
||||||
|
* For pass-by-reference data types, repeat the conversion to see if the
|
||||||
|
* input function leaves any uninitialized bytes in the result. We can
|
||||||
|
* only detect that reliably if RANDOMIZE_ALLOCATED_MEMORY is enabled,
|
||||||
|
* so we don't bother testing otherwise. The reason we don't want any
|
||||||
|
* instability in the input function is that comparison of Const nodes
|
||||||
|
* relies on bytewise comparison of the datums, so if the input function
|
||||||
|
* leaves garbage then subexpressions that should be identical may not get
|
||||||
|
* recognized as such. See pgsql-hackers discussion of 2008-04-04.
|
||||||
|
*/
|
||||||
|
if (string && !typform->typbyval)
|
||||||
|
{
|
||||||
|
Datum result2;
|
||||||
|
|
||||||
|
result2 = OidInputFunctionCall(typinput, string,
|
||||||
|
typioparam, atttypmod);
|
||||||
|
if (!datumIsEqual(result, result2, typform->typbyval, typform->typlen))
|
||||||
|
elog(WARNING, "type %s has unstable input conversion for \"%s\"",
|
||||||
|
NameStr(typform->typname), string);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* given a typeid, return the type's typrelid (associated relation, if any) */
|
/* given a typeid, return the type's typrelid (associated relation, if any) */
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/mmgr/aset.c,v 1.76 2008/01/01 19:45:55 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/mmgr/aset.c,v 1.77 2008/04/11 22:54:23 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTE:
|
* NOTE:
|
||||||
* This is a new (Feb. 05, 1999) implementation of the allocation set
|
* This is a new (Feb. 05, 1999) implementation of the allocation set
|
||||||
@ -282,6 +282,32 @@ AllocSetFreeIndex(Size size)
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill a just-allocated piece of memory with "random" data. It's not really
|
||||||
|
* very random, just a repeating sequence with a length that's prime. What
|
||||||
|
* we mainly want out of it is to have a good probability that two palloc's
|
||||||
|
* of the same number of bytes start out containing different data.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
randomize_mem(char *ptr, size_t size)
|
||||||
|
{
|
||||||
|
static int save_ctr = 1;
|
||||||
|
int ctr;
|
||||||
|
|
||||||
|
ctr = save_ctr;
|
||||||
|
while (size-- > 0)
|
||||||
|
{
|
||||||
|
*ptr++ = ctr;
|
||||||
|
if (++ctr > 251)
|
||||||
|
ctr = 1;
|
||||||
|
}
|
||||||
|
save_ctr = ctr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* RANDOMIZE_ALLOCATED_MEMORY */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public routines
|
* Public routines
|
||||||
@ -552,6 +578,10 @@ AllocSetAlloc(MemoryContext context, Size size)
|
|||||||
if (size < chunk_size)
|
if (size < chunk_size)
|
||||||
((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;
|
((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
||||||
|
/* fill the allocated space with junk */
|
||||||
|
randomize_mem((char *) AllocChunkGetPointer(chunk), size);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stick the new block underneath the active allocation block, so that
|
* Stick the new block underneath the active allocation block, so that
|
||||||
@ -596,6 +626,10 @@ AllocSetAlloc(MemoryContext context, Size size)
|
|||||||
if (size < chunk->size)
|
if (size < chunk->size)
|
||||||
((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;
|
((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
||||||
|
/* fill the allocated space with junk */
|
||||||
|
randomize_mem((char *) AllocChunkGetPointer(chunk), size);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* isReset must be false already */
|
/* isReset must be false already */
|
||||||
Assert(!set->isReset);
|
Assert(!set->isReset);
|
||||||
@ -752,6 +786,10 @@ AllocSetAlloc(MemoryContext context, Size size)
|
|||||||
if (size < chunk->size)
|
if (size < chunk->size)
|
||||||
((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;
|
((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
||||||
|
/* fill the allocated space with junk */
|
||||||
|
randomize_mem((char *) AllocChunkGetPointer(chunk), size);
|
||||||
|
#endif
|
||||||
|
|
||||||
set->isReset = false;
|
set->isReset = false;
|
||||||
|
|
||||||
@ -864,6 +902,13 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
|
|||||||
if (oldsize >= size)
|
if (oldsize >= size)
|
||||||
{
|
{
|
||||||
#ifdef MEMORY_CONTEXT_CHECKING
|
#ifdef MEMORY_CONTEXT_CHECKING
|
||||||
|
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
||||||
|
/* We can only fill the extra space if we know the prior request */
|
||||||
|
if (size > chunk->requested_size)
|
||||||
|
randomize_mem((char *) AllocChunkGetPointer(chunk) + chunk->requested_size,
|
||||||
|
size - chunk->requested_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
chunk->requested_size = size;
|
chunk->requested_size = size;
|
||||||
/* set mark to catch clobber of "unused" space */
|
/* set mark to catch clobber of "unused" space */
|
||||||
if (size < oldsize)
|
if (size < oldsize)
|
||||||
@ -921,6 +966,12 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
|
|||||||
chunk->size = chksize;
|
chunk->size = chksize;
|
||||||
|
|
||||||
#ifdef MEMORY_CONTEXT_CHECKING
|
#ifdef MEMORY_CONTEXT_CHECKING
|
||||||
|
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
||||||
|
/* We can only fill the extra space if we know the prior request */
|
||||||
|
randomize_mem((char *) AllocChunkGetPointer(chunk) + chunk->requested_size,
|
||||||
|
size - chunk->requested_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
chunk->requested_size = size;
|
chunk->requested_size = size;
|
||||||
/* set mark to catch clobber of "unused" space */
|
/* set mark to catch clobber of "unused" space */
|
||||||
if (size < chunk->size)
|
if (size < chunk->size)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* for developers. If you edit any of these, be sure to do a *full*
|
* for developers. If you edit any of these, be sure to do a *full*
|
||||||
* rebuild (and an initdb if noted).
|
* rebuild (and an initdb if noted).
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/pg_config_manual.h,v 1.30 2008/03/27 03:57:34 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/pg_config_manual.h,v 1.31 2008/04/11 22:54:23 tgl Exp $
|
||||||
*------------------------------------------------------------------------
|
*------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -214,11 +214,19 @@
|
|||||||
*------------------------------------------------------------------------
|
*------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define this to cause palloc()'d memory to be filled with random data, to
|
||||||
|
* facilitate catching code that depends on the contents of uninitialized
|
||||||
|
* memory. Right now, this gets defined automatically if --enable-cassert.
|
||||||
|
*/
|
||||||
|
#ifdef USE_ASSERT_CHECKING
|
||||||
|
#define RANDOMIZE_ALLOCATED_MEMORY
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define this to cause pfree()'d memory to be cleared immediately, to
|
* Define this to cause pfree()'d memory to be cleared immediately, to
|
||||||
* facilitate catching bugs that refer to already-freed values. XXX
|
* facilitate catching bugs that refer to already-freed values.
|
||||||
* Right now, this gets defined automatically if --enable-cassert. In
|
* Right now, this gets defined automatically if --enable-cassert.
|
||||||
* the long term it probably doesn't need to be on by default.
|
|
||||||
*/
|
*/
|
||||||
#ifdef USE_ASSERT_CHECKING
|
#ifdef USE_ASSERT_CHECKING
|
||||||
#define CLOBBER_FREED_MEMORY
|
#define CLOBBER_FREED_MEMORY
|
||||||
@ -227,8 +235,7 @@
|
|||||||
/*
|
/*
|
||||||
* Define this to check memory allocation errors (scribbling on more
|
* Define this to check memory allocation errors (scribbling on more
|
||||||
* bytes than were allocated). Right now, this gets defined
|
* bytes than were allocated). Right now, this gets defined
|
||||||
* automatically if --enable-cassert. In the long term it probably
|
* automatically if --enable-cassert.
|
||||||
* doesn't need to be on by default.
|
|
||||||
*/
|
*/
|
||||||
#ifdef USE_ASSERT_CHECKING
|
#ifdef USE_ASSERT_CHECKING
|
||||||
#define MEMORY_CONTEXT_CHECKING
|
#define MEMORY_CONTEXT_CHECKING
|
||||||
|
Loading…
x
Reference in New Issue
Block a user