Commit 65c3d05e authored by Tom Lane's avatar Tom Lane

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.
parent c846f7ca
......@@ -8,7 +8,7 @@
*
*
* 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 "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
......@@ -485,13 +486,38 @@ typeTypeRelid(Type typ)
Datum
stringTypeDatum(Type tp, char *string, int32 atttypmod)
{
Oid typinput;
Oid typioparam;
Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
Oid typinput = typform->typinput;
Oid typioparam = getTypeIOParam(tp);
Datum result;
typinput = ((Form_pg_type) GETSTRUCT(tp))->typinput;
typioparam = getTypeIOParam(tp);
return OidInputFunctionCall(typinput, string,
result = 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) */
......
......@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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:
* This is a new (Feb. 05, 1999) implementation of the allocation set
......@@ -282,6 +282,32 @@ AllocSetFreeIndex(Size size)
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
......@@ -552,6 +578,10 @@ AllocSetAlloc(MemoryContext context, Size size)
if (size < chunk_size)
((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;
#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
......@@ -596,6 +626,10 @@ AllocSetAlloc(MemoryContext context, Size size)
if (size < chunk->size)
((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;
#endif
#ifdef RANDOMIZE_ALLOCATED_MEMORY
/* fill the allocated space with junk */
randomize_mem((char *) AllocChunkGetPointer(chunk), size);
#endif
/* isReset must be false already */
Assert(!set->isReset);
......@@ -752,6 +786,10 @@ AllocSetAlloc(MemoryContext context, Size size)
if (size < chunk->size)
((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;
#endif
#ifdef RANDOMIZE_ALLOCATED_MEMORY
/* fill the allocated space with junk */
randomize_mem((char *) AllocChunkGetPointer(chunk), size);
#endif
set->isReset = false;
......@@ -864,6 +902,13 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
if (oldsize >= size)
{
#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;
/* set mark to catch clobber of "unused" space */
if (size < oldsize)
......@@ -921,6 +966,12 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
chunk->size = chksize;
#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;
/* set mark to catch clobber of "unused" space */
if (size < chunk->size)
......
......@@ -6,7 +6,7 @@
* for developers. If you edit any of these, be sure to do a *full*
* 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
* facilitate catching bugs that refer to already-freed values. XXX
* Right now, this gets defined automatically if --enable-cassert. In
* the long term it probably doesn't need to be on by default.
* facilitate catching bugs that refer to already-freed values.
* Right now, this gets defined automatically if --enable-cassert.
*/
#ifdef USE_ASSERT_CHECKING
#define CLOBBER_FREED_MEMORY
......@@ -227,8 +235,7 @@
/*
* Define this to check memory allocation errors (scribbling on more
* bytes than were allocated). Right now, this gets defined
* automatically if --enable-cassert. In the long term it probably
* doesn't need to be on by default.
* automatically if --enable-cassert.
*/
#ifdef USE_ASSERT_CHECKING
#define MEMORY_CONTEXT_CHECKING
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment