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