PQexec infinite loop

From: Angus Lees <gus(at)switchonline(dot)com(dot)au>
To: pgsql-bugs(at)postgresql(dot)org
Subject: PQexec infinite loop
Date: 2001-09-12 08:08:15
Message-ID: 20010912180815.B23003@switchonline.com.au
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

we have some perl code that used a DBD::Pg statement handle after
the parent database handle had been disconnected.
by doing this we could consistently put libpq into a spin:

PQexec (conn=0x829e120,
query=0x82a2b80 "SELECT \"login\"\n\t FROM \"account\"\n", ' ' <repeats 15 times>, "WHERE \"id\" = '1'\n", ' ' <repeats 14 times>) at fe-exec.c:1207

(gdb) p *result
$5 = {ntups = 0, numAttributes = 0, attDescs = 0x0, tuples = 0x0,
tupArrSize = 0, resultStatus = PGRES_FATAL_ERROR,
cmdStatus = "\000\000\000\000 \000\000\000getdatabaseencoding\000\a\000\000\000 ,*\b", binary = 0, xconn = 0x829e120, noticeHook = 0, noticeArg = 0x0,
client_encoding = 0,
errMsg = 0x82a2c54 "PQgetResult: Unexpected asyncStatus 145\n",
null_field = "", curBlock = 0x82a2c50, curOffset = 45, spaceLeft = 2003}

looping in fe-exec.c:PQexec:
while ((result = PQgetResult(conn)) != NULL)
{
if (result->resultStatus == PGRES_COPY_IN ||
result->resultStatus == PGRES_COPY_OUT)
{
PQclear(result);
printfPQExpBuffer(&conn->errorMessage,
"PQexec: you gotta get out of a COPY state yourself.\n");
/* restore blocking status */
goto errout;
}
PQclear(result);
}

result is EmptyPGresult with PGRES_FATAL_ERROR, so never NULL

PQgetResult(conn) exits at default case of:

/* Return the appropriate thing. */
switch (conn->asyncStatus)
{
case PGASYNC_IDLE:
res = NULL; /* query is complete */
break;
case PGASYNC_READY:
res = prepareAsyncResult(conn);
/* Set the state back to BUSY, allowing parsing to proceed. */
conn->asyncStatus = PGASYNC_BUSY;
break;
case PGASYNC_COPY_IN:
res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN);
break;
case PGASYNC_COPY_OUT:
res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);
break;
default:
printfPQExpBuffer(&conn->errorMessage,
"PQgetResult: Unexpected asyncStatus %d\n",
(int) conn->asyncStatus);
res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
break;
}

return res;

no idea how asyncStatus came to be 145:
(this looks like garbage to me. scribbled on by DBD::Pg ?)

(gdb) p *conn
$8 = {
pghost = 0x40169928 " \231\026@ \231\026(at)\030)\b\030)\b0\231\026(at)0\231\026@8\231\026(at)8\231\026@@\231\026@@\231\026(at)H\231\026@H\231\026(at)P\231\026@P\231\026(at)X\231\026@X\231\026(at)`\231\026@`\231\026(at)h\231\026@h\231\026(at)p\231\026@p\231\026(at)x\231\026@x\231\026(at)\200\231\026@\200\231\026(at)\210\231\026@\210\231\026(at)\220\231\026@\220\231\026(at)\230\231\026@\230\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026@"...,
pghostaddr = 0x40169928 " \231\026@ \231\026(at)\030)\b\030)\b0\231\026(at)0\231\026@8\231\026(at)8\231\026@@\231\026@@\231\026(at)H\231\026@H\231\026(at)P\231\026@P\231\026(at)X\231\026@X\231\026(at)`\231\026@`\231\026(at)h\231\026@h\231\026(at)p\231\026@p\231\026(at)x\231\026@x\231\026(at)\200\231\026@\200\231\026(at)\210\231\026@\210\231\026(at)\220\231\026@\220\231\026(at)\230\231\026@\230\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026(at)\231\026@\231\026@"...,
pgport = 0x8290fb8 "\017)\b\200\031\b\f)\b\017)\b\230\031\b",
pgunixsocket = 0x0, pgtty = 0x0,
pgoptions = 0x8290fc4 "\017)\b\230\031\b",
dbName = 0x8290fac "\017)\bH\"\b\030)\b\017)\b\200\031\b\f)\b\017)\b\230\031\b", pguser = 0x8290fd0 "\017)\bh\031\b$)\b", pgpass = 0x0,
Pfdebug = 0x0, noticeHook = 0, noticeArg = 0x0, status = CONNECTION_BAD,
asyncStatus = 145, notifyList = 0x401698f0, sock = 1075222768, laddr = {
sa = {sa_family = 7, sa_data = '\000' <repeats 13 times>}, in = {
sin_family = 7, sin_port = 0, sin_addr = {s_addr = 0},
sin_zero = "\000\000\000\000\000\000\000"}, un = {sun_family = 7,
sun_path = '\000' <repeats 22 times>, "", '\000' <repeats 16 times>, "Y\000\000\000\230\026(at)\230\026@", '\000' <repeats 20 times>, "\224\017)\b", '\000' <repeats 20 times>, "!\000\000\000)\b\200\230"}}, raddr = {sa = {
sa_family = 2, sa_data = "\0258\021\000\000\000)\bhi*\b"}, in = {
sin_family = 2, sin_port = 14357, sin_addr = {s_addr = 17},
sin_zero = ")\bhi*\b"}, un = {sun_family = 2,
sun_path = "\0258\021\000\000\000)\bhi*\b\000\000\000\020\000\000\000DBD::Pg::db\0009", '\000' <repeats 51 times>, "8\000\000\000\021\000\000\000test\000\230\026(at)\000\000\000\000\021"}}, raddr_len = 0, be_pid = 0, be_key = 16,
salt = "\021", lobjfuncs = 0x40169800,
inBuffer = 0x40169868 "H\213*\b`\230\026(at)P4*\bP4*\ba*\b)\bx\230\026(at)x\230\026@)\b)\b\210i*\b\210i*\b\220\230\026(at)\220\230\026@\213)\b\213)\b()\b()\b\030)\b\030)\b\230\026(at)\230\026@)\b)\b\230\026(at)\230\026@\230\026(at)\230\026@\230\026(at)\230\026@\230\026(at)\230\026@\230\026(at)\230\026@\230\026(at)\230\026@\230\026(at)\230\026@\230\026(at)\230\026@", inBufSize = 16384,
inStart = 57, inCursor = 57, inEnd = 4, nonblocking = 0,
outBuffer = 0xb <Address 0xb out of bounds>, outBufSize = 0, outCount = 0,
result = 0x829e4c8, curTuple = 0x81d2b98, setenv_state = 4294967295,
next_eo = 0x0, allow_ssl_try = 0 '\000', require_ssl = 0 '\000', ssl = 0x0,
errorMessage = {
data = 0x82a6770 "PQgetResult: Unexpected asyncStatus 145\n", len = 40,
maxlen = 977551940}, workBuffer = {
data = 0x3a67503a <Address 0x3a67503a out of bounds>, len = 6448186,
maxlen = 57}, client_encoding = 0}

is it correct to just do this?
(should BAD_RESPONSE and NONFATAL_ERROR also be checked?)

while ((result = PQgetResult(conn)) != NULL)
{
if (result->resultStatus == PGRES_COPY_IN ||
result->resultStatus == PGRES_COPY_OUT)
{
PQclear(result);
printfPQExpBuffer(&conn->errorMessage,
"PQexec: you gotta get out of a COPY state yourself.\n");
/* restore blocking status */
goto errout;
}
+ else if (result->resultStatus == PGRES_FATAL_ERROR)
+ {
+ PQclear(result);
+ goto errout;
+ }
PQclear(result);
}

(yes i know -- if DBD::Pg screwed up then it isn't PQexec's fault, but
afaics PQexec should still be checking for errors)

--
- Gus

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message pie yves 2001-09-12 10:28:19 problem with foreign key
Previous Message Hiroshi Inoue 2001-09-12 05:55:56 Re: Bug #446: Windows 2000 ODBC driver(7.01.0006) crashes.