Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7b96bf4

Browse files
committed
Fix out-of-memory error handling in ParameterDescription message processing.
If libpq ran out of memory while constructing the result set, it would hang,waiting for more data from the server, which might never arrive. To fix,distinguish between out-of-memory error and not-enough-data cases, and givea proper error message back to the client on OOM.There are still similar issues in handling COPY start messages, but let'shandle that as a separate patch.Michael Paquier, Amit Kapila and me. Backpatch to all supported versions.
1 parentcca705a commit7b96bf4

File tree

1 file changed

+53
-11
lines changed

1 file changed

+53
-11
lines changed

‎src/interfaces/libpq/fe-protocol3.c

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
staticvoidhandleSyncLoss(PGconn*conn,charid,intmsgLength);
4747
staticintgetRowDescriptions(PGconn*conn,intmsgLength);
48-
staticintgetParamDescriptions(PGconn*conn);
48+
staticintgetParamDescriptions(PGconn*conn,intmsgLength);
4949
staticintgetAnotherTuple(PGconn*conn,intmsgLength);
5050
staticintgetParameterStatus(PGconn*conn);
5151
staticintgetNotify(PGconn*conn);
@@ -278,8 +278,17 @@ pqParseInput3(PGconn *conn)
278278
return;
279279
break;
280280
case'T':/* Row Description */
281-
if (conn->result==NULL||
282-
conn->queryclass==PGQUERY_DESCRIBE)
281+
if (conn->result!=NULL&&
282+
conn->result->resultStatus==PGRES_FATAL_ERROR)
283+
{
284+
/*
285+
* We've already choked for some reason. Just discard
286+
* the data till we get to the end of the query.
287+
*/
288+
conn->inCursor+=msgLength;
289+
}
290+
elseif (conn->result==NULL||
291+
conn->queryclass==PGQUERY_DESCRIBE)
283292
{
284293
/* First 'T' in a query sequence */
285294
if (getRowDescriptions(conn,msgLength))
@@ -329,9 +338,10 @@ pqParseInput3(PGconn *conn)
329338
}
330339
break;
331340
case't':/* Parameter Description */
332-
if (getParamDescriptions(conn))
341+
if (getParamDescriptions(conn,msgLength))
333342
return;
334-
break;
343+
/* getParamDescriptions() moves inStart itself */
344+
continue;
335345
case'D':/* Data Row */
336346
if (conn->result!=NULL&&
337347
conn->result->resultStatus==PGRES_TUPLES_OK)
@@ -637,20 +647,21 @@ getRowDescriptions(PGconn *conn, int msgLength)
637647
* that shouldn't happen often, since 't' messages usually fit in a packet.
638648
*/
639649
staticint
640-
getParamDescriptions(PGconn*conn)
650+
getParamDescriptions(PGconn*conn,intmsgLength)
641651
{
642652
PGresult*result;
643653
intnparams;
644654
inti;
655+
constchar*errmsg=NULL;
645656

646657
result=PQmakeEmptyPGresult(conn,PGRES_COMMAND_OK);
647658
if (!result)
648-
gotofailure;
659+
gotoadvance_and_error;
649660

650661
/* parseInput already read the 't' label and message length. */
651662
/* the next two bytes are the number of parameters */
652663
if (pqGetInt(&(result->numParameters),2,conn))
653-
gotofailure;
664+
gotonot_enough_data;
654665
nparams=result->numParameters;
655666

656667
/* allocate space for the parameter descriptors */
@@ -659,7 +670,7 @@ getParamDescriptions(PGconn *conn)
659670
result->paramDescs= (PGresParamDesc*)
660671
pqResultAlloc(result,nparams*sizeof(PGresParamDesc), TRUE);
661672
if (!result->paramDescs)
662-
gotofailure;
673+
gotoadvance_and_error;
663674
MemSet(result->paramDescs,0,nparams*sizeof(PGresParamDesc));
664675
}
665676

@@ -669,17 +680,48 @@ getParamDescriptions(PGconn *conn)
669680
inttypid;
670681

671682
if (pqGetInt(&typid,4,conn))
672-
gotofailure;
683+
gotonot_enough_data;
673684
result->paramDescs[i].typid=typid;
674685
}
675686

676687
/* Success! */
677688
conn->result=result;
689+
690+
/* Advance inStart to show that the "t" message has been processed. */
691+
conn->inStart=conn->inCursor;
692+
678693
return0;
679694

680-
failure:
695+
not_enough_data:
681696
PQclear(result);
682697
returnEOF;
698+
699+
advance_and_error:
700+
/* Discard unsaved result, if any */
701+
if (result&&result!=conn->result)
702+
PQclear(result);
703+
704+
/* Discard the failed message by pretending we read it */
705+
conn->inStart+=5+msgLength;
706+
707+
/*
708+
* Replace partially constructed result with an error result. First
709+
* discard the old result to try to win back some memory.
710+
*/
711+
pqClearAsyncResult(conn);
712+
713+
/*
714+
* If preceding code didn't provide an error message, assume "out of
715+
* memory" was meant. The advantage of having this special case is that
716+
* freeing the old result first greatly improves the odds that gettext()
717+
* will succeed in providing a translation.
718+
*/
719+
if (!errmsg)
720+
errmsg=libpq_gettext("out of memory");
721+
printfPQExpBuffer(&conn->errorMessage,"%s\n",errmsg);
722+
pqSaveErrorResult(conn);
723+
724+
return0;
683725
}
684726

685727
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp