On Monday 19 July 2010 17:58:06 Andres Freund wrote:
> On Monday 19 July 2010 17:26:25 Hans van Kranenburg wrote:
> > When issuing an update statement in a transaction with ~30800 levels of
> > savepoint nesting, (which is insane, but possible), postgresql segfaults
> > due to a stack overflow in the AssignTransactionId function, which
> > recursively assign transaction ids to parent transactions.
> 
> It seems easy enough to throw a check_stack_depth() in there - survives
> make check here.
> 
> It would be nice to check this earlier on though - or simply impose a
> artificial limit of nested transactions. I severely doubt that there are
> non- bug situations with a nesting of above 1k (so maybe set the limit to
> 3k).
> 
> Thats independent from checking stack depth there though - it sounds
> possible to get there after an already relatively deep stack usage (deeply
> nested functions or such).
A patch doing both is attached. No idea whether 3k is a good limit.

A small testprogramm is also attached.

Andres
From 79567e1aa864bcd3692546965d774285bc1fcc7c Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Mon, 19 Jul 2010 19:44:45 +0200
Subject: [PATCH] Don't segfault upon too deeply nested subtransactions.

Instead check the stack depth in AssignTransactionId() and refuse
deeper nesting in PushTransaction(). Both is checked as
AssignTransactionId might start from a relatively high stack level and
erroring out in PushTransaction gives a better error location.
---
 src/backend/access/transam/xact.c |   11 ++++++++++-
 src/include/access/xact.h         |    7 +++++++
 2 files changed, 17 insertions(+), 1 deletions(-)

diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 6ba6534..6a69355 100644
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
*************** AssignTransactionId(TransactionState s)
*** 410,417 ****
  	 * Ensure parent(s) have XIDs, so that a child always has an XID later
  	 * than its parent.
  	 */
! 	if (isSubXact && !TransactionIdIsValid(s->parent->transactionId))
  		AssignTransactionId(s->parent);
  
  	/*
  	 * Generate a new Xid and record it in PG_PROC and pg_subtrans.
--- 410,419 ----
  	 * Ensure parent(s) have XIDs, so that a child always has an XID later
  	 * than its parent.
  	 */
! 	if (isSubXact && !TransactionIdIsValid(s->parent->transactionId)){
! 		check_stack_depth();
  		AssignTransactionId(s->parent);
+ 	}
  
  	/*
  	 * Generate a new Xid and record it in PG_PROC and pg_subtrans.
*************** PushTransaction(void)
*** 4129,4134 ****
--- 4131,4143 ----
  	TransactionState p = CurrentTransactionState;
  	TransactionState s;
  
+ 	if(p->nestingLevel > XACT_MAX_NESTING){
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ 				 errmsg("cannot have more than %i nested subtransactions", XACT_MAX_NESTING)));
+ 	}
+ 
+ 
  	/*
  	 * We keep subtransaction state nodes in TopTransactionContext.
  	 */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 3bce72f..b654312 100644
*** a/src/include/access/xact.h
--- b/src/include/access/xact.h
***************
*** 28,33 ****
--- 28,40 ----
  #define XACT_REPEATABLE_READ	2
  #define XACT_SERIALIZABLE		3
  
+ /*
+  * too deep nesting causes stack depth problems and performance
+  * degradiations.
+  * This number is arbitrary.
+  */
+ #define XACT_MAX_NESTING		3000
+ 
  extern int	DefaultXactIsoLevel;
  extern int	XactIsoLevel;
  
-- 
1.7.2.rc1.10.gae32f

#!/usr/bin/python

import time
import psycopg2

x = psycopg2.connect("port=5433 host=/tmp dbname=postgres")
c = x.cursor()

c.execute("SELECT pg_backend_pid();")
print "started as pid: %i" % c.fetchall()[0][0]

print "waiting 5s to start"
time.sleep(5)

for i in xrange(50000):
    c.execute("SAVEPOINT f_%i;" % i);

#Acquire a transaction id
c.execute("INSERT INTO tstack VALUES(1)");

-- 
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

Reply via email to