Thread: How to crash postgres using savepoints
test=# begin; BEGIN test=# savepoint "A"; SAVEPOINT test=# rollback to a; server closed the connection unexpectedly This probably means the server terminated abnormally before or whileprocessing the request. LOG: server process (PID 45905) was terminated by signal 11 LOG: terminating any other active server processes The connection to the server was lost. Attempting reset: LOG: background writer process (PID 45899) exited with exit code 1 LOG: all server processes terminated; reinitializing LOG: database system was interrupted at 2004-08-03 09:42:11 WST LOG: checkpoint record is at 0/A7067C Chris
Did this get through? Hadn't seen anyone comment on it, and I thought it was pretty major :P Christopher Kings-Lynne wrote: > test=# begin; > BEGIN > test=# savepoint "A"; > SAVEPOINT > test=# rollback to a; > server closed the connection unexpectedly > This probably means the server terminated abnormally > before or while processing the request. > LOG: server process (PID 45905) was terminated by signal 11 > LOG: terminating any other active server processes > The connection to the server was lost. Attempting reset: LOG: background > writer process (PID 45899) exited with exit code 1 > LOG: all server processes terminated; reinitializing > LOG: database system was interrupted at 2004-08-03 09:42:11 WST > LOG: checkpoint record is at 0/A7067C > > Chris > > ---------------------------(end of broadcast)--------------------------- > TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
On Mon, 2004-08-02 at 22:37, Christopher Kings-Lynne wrote: > Did this get through? Hadn't seen anyone comment on it, and I thought > it was pretty major :P > I'd just like to second your claims. I have a snapshot from 2004-08-02 and I appended a sequence of SQL commands that causes a crash for me. Regards, Jeff Davis Sequence that causes crash: test=# begin; BEGIN test=# savepoint a; SAVEPOINT test=# rollback to b; server closed the connection unexpectedly This probably means the server terminated abnormally before or whileprocessing the request. The connection to the server was lost. Attempting reset: LOG: server process (PID 23751) was terminated by signal 11 LOG: terminating any other active server processes LOG: background writer process (PID 20334) exited with exit code 1 LOG: all server processes terminated; reinitializing LOG: database system was interrupted at 2004-08-02 21:40:58 PDT LOG: checkpoint record is at 0/A70914 LOG: redo record is at 0/A70914; undo record is at 0/0; shutdown TRUE LOG: next transaction ID: 529; next OID: 25420 LOG: database system was not properly shut down; automatic recovery in progressLOG: record with zero length at 0/A70954 LOG: redo is not required LOG: database system is ready Succeeded. test=#
Attached is a patch fixing this. One question I do have: if (target->savepointLevel != s->savepointLevel) Will this ever be true in the current code? I cannot see anything setting savepointLevel explicitly. Gavin
On Tue, 2004-08-03 at 03:41, Gavin Sherry wrote: > Attached is a patch fixing this. > > One question I do have: > > if (target->savepointLevel != s->savepointLevel) > > Will this ever be true in the current code? I cannot see anything setting > savepointLevel explicitly. >From reading the lists, it seems like that's allowing for some functionality that was talked about but wasn't part of the semantics agreed upon by the end of the discussion. I have a question for you also. I just posted a patch at about the same time you did (I sent it to pgsql-patches, but I haven't seen it appear yet). Mine was a one-liner (appended to end of this email) and all it did was add a check into the aforementioned line for a non-null target pointer. My patch seemed to work, so I'd like to know why you changed the structure around more. I did notice some things were a little cleaner, so was it just clean-up or does my patch fail in some way? Regards,Jeff --- xact.c.old 2004-08-03 03:18:12.000000000 -0700 +++ xact.c 2004-08-03 03:19:05.000000000 -0700 @@ -2529,7 +2529,7 @@ target = target->parent; /* we don't cross savepoint level boundaries */ - if (target->savepointLevel != s->savepointLevel) + if (PointerIsValid(target) && (target->savepointLevel != s->savepointLevel)) ereport(ERROR, (errcode(ERRCODE_S_E_INVALID_SPECIFICATION), errmsg("no such savepoint")));
On Tue, 3 Aug 2004, Jeff Davis wrote: > On Tue, 2004-08-03 at 03:41, Gavin Sherry wrote: > > Attached is a patch fixing this. > > > > One question I do have: > > > > if (target->savepointLevel != s->savepointLevel) > > > > Will this ever be true in the current code? I cannot see anything setting > > savepointLevel explicitly. > > >From reading the lists, it seems like that's allowing for some > functionality that was talked about but wasn't part of the semantics > agreed upon by the end of the discussion. Yes. Savepoint levels are covered in the spec I was more or less just wondering if there was any more code to come or if I'd missed something. > > I have a question for you also. I just posted a patch at about the same > time you did (I sent it to pgsql-patches, but I haven't seen it appear > yet). Mine was a one-liner (appended to end of this email) and all it > did was add a check into the aforementioned line for a non-null target > pointer. My patch seemed to work, so I'd like to know why you changed > the structure around more. I did notice some things were a little > cleaner, so was it just clean-up or does my patch fail in some way? Just a clean up. Gavin
Gavin Sherry <swm@linuxworld.com.au> writes: > On Tue, 3 Aug 2004, Jeff Davis wrote: >> I have a question for you also. I just posted a patch at about the same >> time you did (I sent it to pgsql-patches, but I haven't seen it appear >> yet). Mine was a one-liner (appended to end of this email) and all it >> did was add a check into the aforementioned line for a non-null target >> pointer. My patch seemed to work, so I'd like to know why you changed >> the structure around more. I did notice some things were a little >> cleaner, so was it just clean-up or does my patch fail in some way? > Just a clean up. Actually, there's an easier fix than either of these, which is just to pull the savepointLevel test out of the loop and only do it after we've found a candidate savepoint. There's no point in checking the level at every loop iteration (especially since the feature isn't even being used yet, as noted). Attached is the patch I just applied (which also includes my own notions about how to make the loop prettier...) regards, tom lane *** src/backend/access/transam/xact.c.orig Sun Aug 1 16:57:59 2004 --- src/backend/access/transam/xact.c Tue Aug 3 11:53:41 2004 *************** *** 2520,2541 **** Assert(PointerIsValid(name)); ! target = CurrentTransactionState; ! ! while (target != NULL) { if (PointerIsValid(target->name) && strcmp(target->name, name) == 0) break; - target = target->parent; - - /* we don't cross savepoint level boundaries */ - if (target->savepointLevel != s->savepointLevel) - ereport(ERROR, - (errcode(ERRCODE_S_E_INVALID_SPECIFICATION), - errmsg("no such savepoint"))); } if (!PointerIsValid(target)) ereport(ERROR, (errcode(ERRCODE_S_E_INVALID_SPECIFICATION), errmsg("no such savepoint"))); --- 2520,2538 ---- Assert(PointerIsValid(name)); ! for (target = s; PointerIsValid(target); target = target->parent) { if (PointerIsValid(target->name) &&strcmp(target->name, name) == 0) break; } if (!PointerIsValid(target)) + ereport(ERROR, + (errcode(ERRCODE_S_E_INVALID_SPECIFICATION), + errmsg("no such savepoint"))); + + /* disallow crossing savepoint level boundaries */ + if (target->savepointLevel != s->savepointLevel) ereport(ERROR, (errcode(ERRCODE_S_E_INVALID_SPECIFICATION), errmsg("no such savepoint")));