Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit be23432

Browse files
committed
Protect against hypothetical memory leaks in RelationGetPartitionKey
Also, fix a comment that commit 8a0596c made obsolete. Reported-by: Robert Haas Discussion: http://postgr.es/m/CA+TgmoYbpuUUUp2GhYNwWm0qkah39spiU7uOiNXLz20ASfKYoA@mail.gmail.com
1 parent b726eaa commit be23432

File tree

2 files changed

+30
-25
lines changed

2 files changed

+30
-25
lines changed

src/backend/utils/cache/relcache.c

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -807,17 +807,16 @@ RelationBuildRuleLock(Relation relation)
807807
* RelationBuildPartitionKey
808808
* Build and attach to relcache partition key data of relation
809809
*
810-
* Partitioning key data is stored in CacheMemoryContext to ensure it survives
811-
* as long as the relcache. To avoid leaking memory in that context in case
812-
* of an error partway through this function, we build the structure in the
813-
* working context (which must be short-lived) and copy the completed
814-
* structure into the cache memory.
815-
*
816-
* Also, since the structure being created here is sufficiently complex, we
817-
* make a private child context of CacheMemoryContext for each relation that
818-
* has associated partition key information. That means no complicated logic
819-
* to free individual elements whenever the relcache entry is flushed - just
820-
* delete the context.
810+
* Partitioning key data is a complex structure; to avoid complicated logic to
811+
* free individual elements whenever the relcache entry is flushed, we give it
812+
* its own memory context, child of CacheMemoryContext, which can easily be
813+
* deleted on its own. To avoid leaking memory in that context in case of an
814+
* error partway through this function, the context is initially created as a
815+
* child of CurTransactionContext and only re-parented to CacheMemoryContext
816+
* at the end, when no further errors are possible. Also, we don't make this
817+
* context the current context except in very brief code sections, out of fear
818+
* that some of our callees allocate memory on their own which would be leaked
819+
* permanently.
821820
*/
822821
static void
823822
RelationBuildPartitionKey(Relation relation)
@@ -850,9 +849,9 @@ RelationBuildPartitionKey(Relation relation)
850849
RelationGetRelationName(relation),
851850
MEMCONTEXT_COPY_NAME,
852851
ALLOCSET_SMALL_SIZES);
853-
oldcxt = MemoryContextSwitchTo(partkeycxt);
854852

855-
key = (PartitionKey) palloc0(sizeof(PartitionKeyData));
853+
key = (PartitionKey) MemoryContextAllocZero(partkeycxt,
854+
sizeof(PartitionKeyData));
856855

857856
/* Fixed-length attributes */
858857
form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
@@ -894,17 +893,20 @@ RelationBuildPartitionKey(Relation relation)
894893
/*
895894
* Run the expressions through const-simplification since the planner
896895
* will be comparing them to similarly-processed qual clause operands,
897-
* and may fail to detect valid matches without this step. We don't
898-
* need to bother with canonicalize_qual() though, because partition
899-
* expressions are not full-fledged qualification clauses.
896+
* and may fail to detect valid matches without this step; fix
897+
* opfuncids while at it. We don't need to bother with
898+
* canonicalize_qual() though, because partition expressions are not
899+
* full-fledged qualification clauses.
900900
*/
901-
expr = eval_const_expressions(NULL, (Node *) expr);
901+
expr = eval_const_expressions(NULL, expr);
902+
fix_opfuncids(expr);
902903

903-
/* May as well fix opfuncids too */
904-
fix_opfuncids((Node *) expr);
905-
key->partexprs = (List *) expr;
904+
oldcxt = MemoryContextSwitchTo(partkeycxt);
905+
key->partexprs = (List *) copyObject(expr);
906+
MemoryContextSwitchTo(oldcxt);
906907
}
907908

909+
oldcxt = MemoryContextSwitchTo(partkeycxt);
908910
key->partattrs = (AttrNumber *) palloc0(key->partnatts * sizeof(AttrNumber));
909911
key->partopfamily = (Oid *) palloc0(key->partnatts * sizeof(Oid));
910912
key->partopcintype = (Oid *) palloc0(key->partnatts * sizeof(Oid));
@@ -919,8 +921,9 @@ RelationBuildPartitionKey(Relation relation)
919921
key->parttypbyval = (bool *) palloc0(key->partnatts * sizeof(bool));
920922
key->parttypalign = (char *) palloc0(key->partnatts * sizeof(char));
921923
key->parttypcoll = (Oid *) palloc0(key->partnatts * sizeof(Oid));
924+
MemoryContextSwitchTo(oldcxt);
922925

923-
/* For the hash partitioning, an extended hash function will be used. */
926+
/* determine support function number to search for */
924927
procnum = (key->strategy == PARTITION_STRATEGY_HASH) ?
925928
HASHEXTENDED_PROC : BTORDER_PROC;
926929

@@ -952,7 +955,7 @@ RelationBuildPartitionKey(Relation relation)
952955
if (!OidIsValid(funcid))
953956
ereport(ERROR,
954957
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
955-
errmsg("operator class \"%s\" of access method %s is missing support function %d for data type \"%s\"",
958+
errmsg("operator class \"%s\" of access method %s is missing support function %d for type %s",
956959
NameStr(opclassform->opcname),
957960
(key->strategy == PARTITION_STRATEGY_HASH) ?
958961
"hash" : "btree",
@@ -989,11 +992,13 @@ RelationBuildPartitionKey(Relation relation)
989992

990993
ReleaseSysCache(tuple);
991994

992-
/* Success --- make the relcache point to the newly constructed key */
995+
/*
996+
* Success --- reparent our context and make the relcache point to the
997+
* newly constructed key
998+
*/
993999
MemoryContextSetParent(partkeycxt, CacheMemoryContext);
9941000
relation->rd_partkeycxt = partkeycxt;
9951001
relation->rd_partkey = key;
996-
MemoryContextSwitchTo(oldcxt);
9971002
}
9981003

9991004
/*

src/include/access/hash.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ typedef HashMetaPageData *HashMetaPage;
338338

339339
/*
340340
* When a new operator class is declared, we require that the user supply
341-
* us with an amproc procudure for hashing a key of the new type, returning
341+
* us with an amproc procedure for hashing a key of the new type, returning
342342
* a 32-bit hash value. We call this the "standard" hash procedure. We
343343
* also allow an optional "extended" hash procedure which accepts a salt and
344344
* returns a 64-bit hash value. This is highly recommended but, for reasons

0 commit comments

Comments
 (0)