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

Commit2e70d6b

Browse files
committed
Teach libpq to detect integer overflow in the row count of a PGresult.
Adding more than 1 billion rows to a PGresult would overflow its ntups andtupArrSize fields, leading to client crashes. It'd be desirable to usewider fields on 64-bit machines, but because all of libpq's external APIsuse plain "int" for row counters, that's going to be hard to accomplishwithout an ABI break. Given the lack of complaints so far, and the generalpain that would be involved in using such huge PGresults, let's settle forjust preventing the overflow and reporting a useful error message if itdoes happen. Also, for a couple more lines of code we can increase thethreshold of trouble from INT_MAX/2 to INT_MAX rows.To do that, refactor pqAddTuple() to allow returning an error message thatreplaces the default assumption that it failed because of out-of-memory.Along the way, fix PQsetvalue() so that it reports all failures viapqInternalNotice(). It already did so in the case of bad field number,but neglected to report anything for other error causes.Because of the potential for crashes, this seems like a back-patchablebug fix, despite the lack of field reports.Michael Paquier, per a complaint from Igor Korot.Discussion:https://postgr.es/m/CA+FnnTxyLWyjY1goewmJNxC==HQCCF4fKkoCTa9qR36oRAHDPw@mail.gmail.com
1 parentbf11e7e commit2e70d6b

File tree

1 file changed

+60
-9
lines changed

1 file changed

+60
-9
lines changed

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

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include<ctype.h>
1818
#include<fcntl.h>
19+
#include<limits.h>
1920

2021
#include"libpq-fe.h"
2122
#include"libpq-int.h"
@@ -51,7 +52,8 @@ static bool static_std_strings = false;
5152

5253

5354
staticPGEvent*dupEvents(PGEvent*events,intcount);
54-
staticboolpqAddTuple(PGresult*res,PGresAttValue*tup);
55+
staticboolpqAddTuple(PGresult*res,PGresAttValue*tup,
56+
constchar**errmsgp);
5557
staticboolPQsendQueryStart(PGconn*conn);
5658
staticintPQsendQueryGuts(PGconn*conn,
5759
constchar*command,
@@ -416,18 +418,26 @@ dupEvents(PGEvent *events, int count)
416418
* equal to PQntuples(res). If it is equal, a new tuple is created and
417419
* added to the result.
418420
* Returns a non-zero value for success and zero for failure.
421+
* (On failure, we report the specific problem via pqInternalNotice.)
419422
*/
420423
int
421424
PQsetvalue(PGresult*res,inttup_num,intfield_num,char*value,intlen)
422425
{
423426
PGresAttValue*attval;
427+
constchar*errmsg=NULL;
424428

429+
/* Note that this check also protects us against null "res" */
425430
if (!check_field_number(res,field_num))
426431
return FALSE;
427432

428433
/* Invalid tup_num, must be <= ntups */
429434
if (tup_num<0||tup_num>res->ntups)
435+
{
436+
pqInternalNotice(&res->noticeHooks,
437+
"row number %d is out of range 0..%d",
438+
tup_num,res->ntups);
430439
return FALSE;
440+
}
431441

432442
/* need to allocate a new tuple? */
433443
if (tup_num==res->ntups)
@@ -440,7 +450,7 @@ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
440450
TRUE);
441451

442452
if (!tup)
443-
return FALSE;
453+
gotofail;
444454

445455
/* initialize each column to NULL */
446456
for (i=0;i<res->numAttributes;i++)
@@ -450,8 +460,8 @@ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
450460
}
451461

452462
/* add it to the array */
453-
if (!pqAddTuple(res,tup))
454-
return FALSE;
463+
if (!pqAddTuple(res,tup,&errmsg))
464+
gotofail;
455465
}
456466

457467
attval=&res->tuples[tup_num][field_num];
@@ -471,13 +481,24 @@ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
471481
{
472482
attval->value= (char*)pqResultAlloc(res,len+1, TRUE);
473483
if (!attval->value)
474-
return FALSE;
484+
gotofail;
475485
attval->len=len;
476486
memcpy(attval->value,value,len);
477487
attval->value[len]='\0';
478488
}
479489

480490
return TRUE;
491+
492+
/*
493+
* Report failure via pqInternalNotice. If preceding code didn't provide
494+
* an error message, assume "out of memory" was meant.
495+
*/
496+
fail:
497+
if (!errmsg)
498+
errmsg=libpq_gettext("out of memory");
499+
pqInternalNotice(&res->noticeHooks,"%s",errmsg);
500+
501+
return FALSE;
481502
}
482503

483504
/*
@@ -847,10 +868,13 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
847868
/*
848869
* pqAddTuple
849870
* add a row pointer to the PGresult structure, growing it if necessary
850-
* Returns TRUE if OK, FALSE if not enough memory to add the row
871+
* Returns TRUE if OK, FALSE if an error prevented adding the row
872+
*
873+
* On error, *errmsgp can be set to an error string to be returned.
874+
* If it is left NULL, the error is presumed to be "out of memory".
851875
*/
852876
staticbool
853-
pqAddTuple(PGresult*res,PGresAttValue*tup)
877+
pqAddTuple(PGresult*res,PGresAttValue*tup,constchar**errmsgp)
854878
{
855879
if (res->ntups >=res->tupArrSize)
856880
{
@@ -865,9 +889,36 @@ pqAddTuple(PGresult *res, PGresAttValue *tup)
865889
* existing allocation. Note that the positions beyond res->ntups are
866890
* garbage, not necessarily NULL.
867891
*/
868-
intnewSize= (res->tupArrSize>0) ?res->tupArrSize*2 :128;
892+
intnewSize;
869893
PGresAttValue**newTuples;
870894

895+
/*
896+
* Since we use integers for row numbers, we can't support more than
897+
* INT_MAX rows. Make sure we allow that many, though.
898+
*/
899+
if (res->tupArrSize <=INT_MAX /2)
900+
newSize= (res->tupArrSize>0) ?res->tupArrSize*2 :128;
901+
elseif (res->tupArrSize<INT_MAX)
902+
newSize=INT_MAX;
903+
else
904+
{
905+
*errmsgp=libpq_gettext("PGresult cannot support more than INT_MAX tuples");
906+
return FALSE;
907+
}
908+
909+
/*
910+
* Also, on 32-bit platforms we could, in theory, overflow size_t even
911+
* before newSize gets to INT_MAX. (In practice we'd doubtless hit
912+
* OOM long before that, but let's check.)
913+
*/
914+
#ifINT_MAX >= (SIZE_MAX /2)
915+
if (newSize>SIZE_MAX /sizeof(PGresAttValue*))
916+
{
917+
*errmsgp=libpq_gettext("size_t overflow");
918+
return FALSE;
919+
}
920+
#endif
921+
871922
if (res->tuples==NULL)
872923
newTuples= (PGresAttValue**)
873924
malloc(newSize*sizeof(PGresAttValue*));
@@ -1093,7 +1144,7 @@ pqRowProcessor(PGconn *conn, const char **errmsgp)
10931144
}
10941145

10951146
/* And add the tuple to the PGresult's tuple array */
1096-
if (!pqAddTuple(res,tup))
1147+
if (!pqAddTuple(res,tup,errmsgp))
10971148
gotofail;
10981149

10991150
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp