]> granicus.if.org Git - postgresql/commitdiff
Fix failure to consider failure cases in GetComboCommandId().
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 26 Nov 2015 18:23:02 +0000 (13:23 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 26 Nov 2015 18:23:02 +0000 (13:23 -0500)
Failure to initially palloc the comboCids array, or to realloc it bigger
when needed, left combocid's data structures in an inconsistent state that
would cause trouble if the top transaction continues to execute.  Noted
while examining a user complaint about the amount of memory used for this.
(There's not much we can do about that, but it does point up that repalloc
failure has a non-negligible chance of occurring here.)

In HEAD/9.5, also avoid possible invocation of memcpy() with a null pointer
in SerializeComboCIDState; cf commit 13bba0227.

src/backend/utils/time/combocid.c

index 44f7ef1bbb8bc4ad588b9a17884b489c467b3070..670299644da94e3ea449c431ea2f929b24efa1cd 100644 (file)
@@ -207,6 +207,13 @@ GetComboCommandId(CommandId cmin, CommandId cmax)
        {
                HASHCTL         hash_ctl;
 
+               /* Make array first; existence of hash table asserts array exists */
+               comboCids = (ComboCidKeyData *)
+                       MemoryContextAlloc(TopTransactionContext,
+                                                          sizeof(ComboCidKeyData) * CCID_ARRAY_SIZE);
+               sizeComboCids = CCID_ARRAY_SIZE;
+               usedComboCids = 0;
+
                memset(&hash_ctl, 0, sizeof(hash_ctl));
                hash_ctl.keysize = sizeof(ComboCidKeyData);
                hash_ctl.entrysize = sizeof(ComboCidEntryData);
@@ -217,12 +224,20 @@ GetComboCommandId(CommandId cmin, CommandId cmax)
                                                                CCID_HASH_SIZE,
                                                                &hash_ctl,
                                                                HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
+       }
+
+       /*
+        * Grow the array if there's not at least one free slot.  We must do this
+        * before possibly entering a new hashtable entry, else failure to
+        * repalloc would leave a corrupt hashtable entry behind.
+        */
+       if (usedComboCids >= sizeComboCids)
+       {
+               int                     newsize = sizeComboCids * 2;
 
                comboCids = (ComboCidKeyData *)
-                       MemoryContextAlloc(TopTransactionContext,
-                                                          sizeof(ComboCidKeyData) * CCID_ARRAY_SIZE);
-               sizeComboCids = CCID_ARRAY_SIZE;
-               usedComboCids = 0;
+                       repalloc(comboCids, sizeof(ComboCidKeyData) * newsize);
+               sizeComboCids = newsize;
        }
 
        /* Lookup or create a hash entry with the desired cmin/cmax */
@@ -241,20 +256,7 @@ GetComboCommandId(CommandId cmin, CommandId cmax)
                return entry->combocid;
        }
 
-       /*
-        * We have to create a new combo cid. Check that there's room for it in
-        * the array, and grow it if there isn't.
-        */
-       if (usedComboCids >= sizeComboCids)
-       {
-               /* We need to grow the array */
-               int                     newsize = sizeComboCids * 2;
-
-               comboCids = (ComboCidKeyData *)
-                       repalloc(comboCids, sizeof(ComboCidKeyData) * newsize);
-               sizeComboCids = newsize;
-       }
-
+       /* We have to create a new combo cid; we already made room in the array */
        combocid = usedComboCids;
 
        comboCids[combocid].cmin = cmin;