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

Commitd391fb6

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 parent669bef9 commitd391fb6

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,
@@ -415,18 +417,26 @@ dupEvents(PGEvent *events, int count)
415417
* equal to PQntuples(res). If it is equal, a new tuple is created and
416418
* added to the result.
417419
* Returns a non-zero value for success and zero for failure.
420+
* (On failure, we report the specific problem via pqInternalNotice.)
418421
*/
419422
int
420423
PQsetvalue(PGresult*res,inttup_num,intfield_num,char*value,intlen)
421424
{
422425
PGresAttValue*attval;
426+
constchar*errmsg=NULL;
423427

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

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

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

441451
if (!tup)
442-
return FALSE;
452+
gotofail;
443453

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

451461
/* add it to the array */
452-
if (!pqAddTuple(res,tup))
453-
return FALSE;
462+
if (!pqAddTuple(res,tup,&errmsg))
463+
gotofail;
454464
}
455465

456466
attval=&res->tuples[tup_num][field_num];
@@ -470,13 +480,24 @@ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
470480
{
471481
attval->value= (char*)pqResultAlloc(res,len+1, TRUE);
472482
if (!attval->value)
473-
return FALSE;
483+
gotofail;
474484
attval->len=len;
475485
memcpy(attval->value,value,len);
476486
attval->value[len]='\0';
477487
}
478488

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

482503
/*
@@ -845,10 +866,13 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
845866
/*
846867
* pqAddTuple
847868
* add a row pointer to the PGresult structure, growing it if necessary
848-
* Returns TRUE if OK, FALSE if not enough memory to add the row
869+
* Returns TRUE if OK, FALSE if an error prevented adding the row
870+
*
871+
* On error, *errmsgp can be set to an error string to be returned.
872+
* If it is left NULL, the error is presumed to be "out of memory".
849873
*/
850874
staticbool
851-
pqAddTuple(PGresult*res,PGresAttValue*tup)
875+
pqAddTuple(PGresult*res,PGresAttValue*tup,constchar**errmsgp)
852876
{
853877
if (res->ntups >=res->tupArrSize)
854878
{
@@ -863,9 +887,36 @@ pqAddTuple(PGresult *res, PGresAttValue *tup)
863887
* existing allocation. Note that the positions beyond res->ntups are
864888
* garbage, not necessarily NULL.
865889
*/
866-
intnewSize= (res->tupArrSize>0) ?res->tupArrSize*2 :128;
890+
intnewSize;
867891
PGresAttValue**newTuples;
868892

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

10921143
/* And add the tuple to the PGresult's tuple array */
1093-
if (!pqAddTuple(res,tup))
1144+
if (!pqAddTuple(res,tup,errmsgp))
10941145
gotofail;
10951146

10961147
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp