Fix possible corruption of AfterTriggerEventLists in subtransaction rollback.
authorTom Lane
Thu, 19 Aug 2010 15:46:24 +0000 (15:46 +0000)
committerTom Lane
Thu, 19 Aug 2010 15:46:24 +0000 (15:46 +0000)
afterTriggerInvokeEvents failed to adjust events->tailfree when truncating
the last chunk of an event list.  This could result in the data being
"de-truncated" by afterTriggerRestoreEventList during a subsequent
subtransaction abort.  Even that wouldn't kill us, because the re-added data
would just be events marked DONE --- unless the data had been partially
overwritten by new events.  Then we might crash, or in any case misbehave
(perhaps fire triggers twice, or fire triggers with the wrong event data).
Per bug #5622 from Thue Janus Kristensen.

Back-patch to 8.4 where the current trigger list representation was introduced.

src/backend/commands/trigger.c

index aef7838eb6e54058df488b1a5e952fada491f4d5..251c3e81a2f41cb3e3b3b94da8c7f6aa36302cdd 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.262 2010/02/26 02:00:39 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.262.4.1 2010/08/19 15:46:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2928,6 +2928,7 @@ afterTriggerAddEvent(AfterTriggerEventList *events,
        else
            events->tail->next = chunk;
        events->tail = chunk;
+       /* events->tailfree is now out of sync, but we'll fix it below */
    }
 
    /*
@@ -3329,6 +3330,15 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
        {
            chunk->freeptr = CHUNK_DATA_START(chunk);
            chunk->endfree = chunk->endptr;
+
+           /*
+            * If it's last chunk, must sync event list's tailfree too.  Note
+            * that delete_ok must NOT be passed as true if there could be
+            * stacked AfterTriggerEventList values pointing at this event
+            * list, since we'd fail to fix their copies of tailfree.
+            */
+           if (chunk == events->tail)
+               events->tailfree = chunk->freeptr;
        }
    }