Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 72a5db1

Browse files
author
Neil Conway
committed
libpq was not consistently checking for memory allocation failures. This
patch adds missing checks to the call sites of malloc(), strdup(), PQmakeEmptyPGresult(), pqResultAlloc(), and pqResultStrdup(), and updates the documentation. Per original report from Volkan Yazici about PQmakeEmptyPGresult() not checking for malloc() failure.
1 parent 2f12106 commit 72a5db1

File tree

8 files changed

+206
-117
lines changed

8 files changed

+206
-117
lines changed

doc/src/sgml/libpq.sgml

+30-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.184 2005/06/10 03:02:01 momjian Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.185 2005/06/12 00:00:20 neilc Exp $
33
-->
44

55
<chapter id="libpq">
@@ -581,14 +581,15 @@ typedef struct
581581
</para>
582582

583583
<para>
584-
Returns a connection options array. This may
585-
be used to determine all possible <function>PQconnectdb</function> options and their
584+
Returns a connection options array. This may be used to determine
585+
all possible <function>PQconnectdb</function> options and their
586586
current default values. The return value points to an array of
587-
<structname>PQconninfoOption</structname> structures, which ends with an entry having a null
588-
<structfield>keyword</> pointer. Note that the current default values
589-
(<structfield>val</structfield> fields)
590-
will depend on environment variables and other context.
591-
Callers must treat the connection options data as read-only.
587+
<structname>PQconninfoOption</structname> structures, which ends
588+
with an entry having a null <structfield>keyword</> pointer. The
589+
null pointer is returned if memory could not be allocated. Note that
590+
the current default values (<structfield>val</structfield> fields)
591+
will depend on environment variables and other context. Callers
592+
must treat the connection options data as read-only.
592593
</para>
593594

594595
<para>
@@ -1651,18 +1652,22 @@ void PQclear(PGresult *res);
16511652
<para>
16521653
Constructs an empty <structname>PGresult</structname> object with the given status.
16531654
<synopsis>
1654-
PGresult* PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
1655+
PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
16551656
</synopsis>
16561657
</para>
16571658

16581659
<para>
1659-
This is <application>libpq</>'s internal function to allocate and initialize an empty
1660-
<structname>PGresult</structname> object. It is exported because some applications find it
1661-
useful to generate result objects (particularly objects with error
1662-
status) themselves. If <parameter>conn</parameter> is not null and <parameter>status</> indicates an error,
1663-
the current error message of the specified connection is copied into the <structname>PGresult</structname>.
1664-
Note that <function>PQclear</function> should eventually be called on the object, just
1665-
as with a <structname>PGresult</structname> returned by <application>libpq</application> itself.
1660+
This is <application>libpq</>'s internal function to allocate and
1661+
initialize an empty <structname>PGresult</structname> object. This
1662+
function returns NULL if memory could not be allocated. It is exported
1663+
because some applications find it useful to generate result objects
1664+
(particularly objects with error status) themselves. If
1665+
<parameter>conn</parameter> is not null and <parameter>status</>
1666+
indicates an error, the current error message of the specified
1667+
connection is copied into the <structname>PGresult</structname>. Note
1668+
that <function>PQclear</function> should eventually be called on the
1669+
object, just as with a <structname>PGresult</structname> returned by
1670+
<application>libpq</application> itself.
16661671
</para>
16671672
</listitem>
16681673
</varlistentry>
@@ -2266,15 +2271,15 @@ unsigned char *PQescapeBytea(const unsigned char *from,
22662271
<para>
22672272
<function>PQescapeBytea</> returns an escaped version of the
22682273
<parameter>from</parameter> parameter binary string in memory
2269-
allocated with <function>malloc()</>. This memory must be freed
2270-
using <function>PQfreemem</> when the result is no longer needed.
2271-
The return string has all special characters replaced so that they
2272-
can be properly processed by the
2273-
<productname>PostgreSQL</productname> string literal parser, and
2274-
the <type>bytea</type> input function. A terminating zero byte is
2275-
also added. The single quotes that must surround
2276-
<productname>PostgreSQL</productname> string literals are not part
2277-
of the result string.
2274+
allocated with <function>malloc()</> (a null pointer is returned if
2275+
memory could not be allocated). This memory must be freed using
2276+
<function>PQfreemem</> when the result is no longer needed. The
2277+
return string has all special characters replaced so that they can
2278+
be properly processed by the <productname>PostgreSQL</productname>
2279+
string literal parser, and the <type>bytea</type> input function. A
2280+
terminating zero byte is also added. The single quotes that must
2281+
surround <productname>PostgreSQL</productname> string literals are
2282+
not part of the result string.
22782283
</para>
22792284
</listitem>
22802285
</varlistentry>

src/interfaces/libpq/fe-connect.c

+44-23
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.309 2005/06/10 04:01:36 momjian Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.310 2005/06/12 00:00:21 neilc Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -368,6 +368,8 @@ connectOptions1(PGconn *conn, const char *conninfo)
368368
*
369369
* Don't put anything cute here --- intelligence should be in
370370
* connectOptions2 ...
371+
*
372+
* XXX: probably worth checking strdup() return value here...
371373
*/
372374
tmp = conninfo_getval(connOptions, "hostaddr");
373375
conn->pghostaddr = tmp ? strdup(tmp) : NULL;
@@ -459,7 +461,6 @@ connectOptions2(PGconn *conn)
459461
}
460462

461463
#ifdef NOT_USED
462-
463464
/*
464465
* parse dbName to get all additional info in it, if any
465466
*/
@@ -2167,11 +2168,9 @@ closePGconn(PGconn *conn)
21672168
}
21682169

21692170
/*
2170-
PQfinish:
2171-
properly close a connection to the backend
2172-
also frees the PGconn data structure so it shouldn't be re-used
2173-
after this
2174-
*/
2171+
* PQfinish: properly close a connection to the backend. Also frees
2172+
* the PGconn data structure so it shouldn't be re-used after this.
2173+
*/
21752174
void
21762175
PQfinish(PGconn *conn)
21772176
{
@@ -2182,10 +2181,10 @@ PQfinish(PGconn *conn)
21822181
}
21832182
}
21842183

2185-
/* PQreset :
2186-
resets the connection to the backend
2187-
closes the existing connection and makes a new one
2188-
*/
2184+
/*
2185+
* PQreset: resets the connection to the backend by closing the
2186+
* existing connection and creating a new one.
2187+
*/
21892188
void
21902189
PQreset(PGconn *conn)
21912190
{
@@ -2199,11 +2198,12 @@ PQreset(PGconn *conn)
21992198
}
22002199

22012200

2202-
/* PQresetStart :
2203-
resets the connection to the backend
2204-
closes the existing connection and makes a new one
2205-
Returns 1 on success, 0 on failure.
2206-
*/
2201+
/*
2202+
* PQresetStart:
2203+
* resets the connection to the backend
2204+
* closes the existing connection and makes a new one
2205+
* Returns 1 on success, 0 on failure.
2206+
*/
22072207
int
22082208
PQresetStart(PGconn *conn)
22092209
{
@@ -2218,11 +2218,11 @@ PQresetStart(PGconn *conn)
22182218
}
22192219

22202220

2221-
/* PQresetPoll :
2222-
resets the connection to the backend
2223-
closes the existing connection and makes a new one
2224-
*/
2225-
2221+
/*
2222+
* PQresetPoll:
2223+
* resets the connection to the backend
2224+
* closes the existing connection and makes a new one
2225+
*/
22262226
PostgresPollingStatusType
22272227
PQresetPoll(PGconn *conn)
22282228
{
@@ -2514,7 +2514,7 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
25142514
* location to find our config files.
25152515
*/
25162516
snprintf(serviceFile, MAXPGPATH, "%s/pg_service.conf",
2517-
getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR);
2517+
getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR);
25182518

25192519
if (service != NULL)
25202520
{
@@ -2802,7 +2802,14 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
28022802
if (option->val)
28032803
free(option->val);
28042804
option->val = strdup(pval);
2805-
2805+
if (!option->val)
2806+
{
2807+
printfPQExpBuffer(errorMessage,
2808+
libpq_gettext("out of memory\n"));
2809+
PQconninfoFree(options);
2810+
free(buf);
2811+
return NULL;
2812+
}
28062813
}
28072814

28082815
/* Done with the modifiable input string */
@@ -2835,6 +2842,13 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
28352842
if ((tmp = getenv(option->envvar)) != NULL)
28362843
{
28372844
option->val = strdup(tmp);
2845+
if (!option->val)
2846+
{
2847+
printfPQExpBuffer(errorMessage,
2848+
libpq_gettext("out of memory\n"));
2849+
PQconninfoFree(options);
2850+
return NULL;
2851+
}
28382852
continue;
28392853
}
28402854
}
@@ -2846,6 +2860,13 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
28462860
if (option->compiled != NULL)
28472861
{
28482862
option->val = strdup(option->compiled);
2863+
if (!option->val)
2864+
{
2865+
printfPQExpBuffer(errorMessage,
2866+
libpq_gettext("out of memory\n"));
2867+
PQconninfoFree(options);
2868+
return NULL;
2869+
}
28492870
continue;
28502871
}
28512872

src/interfaces/libpq/fe-exec.c

+19-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.168 2005/06/09 20:01:16 tgl Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.169 2005/06/12 00:00:21 neilc Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -134,6 +134,8 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
134134
PGresult *result;
135135

136136
result = (PGresult *) malloc(sizeof(PGresult));
137+
if (!result)
138+
return NULL;
137139

138140
result->ntups = 0;
139141
result->numAttributes = 0;
@@ -453,7 +455,7 @@ pqPrepareAsyncResult(PGconn *conn)
453455
* a trailing newline, and should not be more than one line).
454456
*/
455457
void
456-
pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
458+
pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt, ...)
457459
{
458460
char msgBuf[1024];
459461
va_list args;
@@ -470,6 +472,8 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
470472

471473
/* Make a PGresult to pass to the notice receiver */
472474
res = PQmakeEmptyPGresult(NULL, PGRES_NONFATAL_ERROR);
475+
if (!res)
476+
return;
473477
res->noticeHooks = *hooks;
474478

475479
/*
@@ -480,15 +484,19 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
480484
/* XXX should provide a SQLSTATE too? */
481485

482486
/*
483-
* Result text is always just the primary message + newline.
487+
* Result text is always just the primary message + newline. If we
488+
* can't allocate it, don't bother invoking the receiver.
484489
*/
485490
res->errMsg = (char *) pqResultAlloc(res, strlen(msgBuf) + 2, FALSE);
486-
sprintf(res->errMsg, "%s\n", msgBuf);
491+
if (res->errMsg)
492+
{
493+
sprintf(res->errMsg, "%s\n", msgBuf);
487494

488-
/*
489-
* Pass to receiver, then free it.
490-
*/
491-
(*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
495+
/*
496+
* Pass to receiver, then free it.
497+
*/
498+
(*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
499+
}
492500
PQclear(res);
493501
}
494502

@@ -1127,8 +1135,9 @@ PQisBusy(PGconn *conn)
11271135

11281136
/*
11291137
* PQgetResult
1130-
* Get the next PGresult produced by a query.
1131-
* Returns NULL if and only if no query work remains.
1138+
* Get the next PGresult produced by a query. Returns NULL if no
1139+
* query work remains or an error has occurred (e.g. out of
1140+
* memory).
11321141
*/
11331142

11341143
PGresult *

src/interfaces/libpq/fe-misc.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* Portions Copyright (c) 1994, Regents of the University of California
2424
*
2525
* IDENTIFICATION
26-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-misc.c,v 1.113 2005/02/22 04:42:20 momjian Exp $
26+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-misc.c,v 1.114 2005/06/12 00:00:21 neilc Exp $
2727
*
2828
*-------------------------------------------------------------------------
2929
*/
@@ -175,7 +175,8 @@ pqGetnchar(char *s, size_t len, PGconn *conn)
175175
conn->inCursor += len;
176176

177177
if (conn->Pfdebug)
178-
fprintf(conn->Pfdebug, libpq_gettext("From backend (%lu)> %.*s\n"), (unsigned long) len, (int) len, s);
178+
fprintf(conn->Pfdebug, libpq_gettext("From backend (%lu)> %.*s\n"),
179+
(unsigned long) len, (int) len, s);
179180

180181
return 0;
181182
}

src/interfaces/libpq/fe-print.c

+14-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* didn't really belong there.
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.59 2005/02/22 04:42:20 momjian Exp $
13+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.60 2005/06/12 00:00:21 neilc Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -62,14 +62,11 @@ static void fill(int length, int max, char filler, FILE *fp);
6262
* details
6363
*
6464
* This function should probably be removed sometime since psql
65-
* doesn't use it anymore. It is unclear to what extend this is used
65+
* doesn't use it anymore. It is unclear to what extent this is used
6666
* by external clients, however.
6767
*/
68-
6968
void
70-
PQprint(FILE *fout,
71-
const PGresult *res,
72-
const PQprintOpt *po)
69+
PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
7370
{
7471
int nFields;
7572

@@ -611,6 +608,12 @@ PQdisplayTuples(const PGresult *res,
611608
if (fillAlign)
612609
{
613610
fLength = (int *) malloc(nFields * sizeof(int));
611+
if (!fLength)
612+
{
613+
fprintf(stderr, libpq_gettext("out of memory\n"));
614+
exit(1);
615+
}
616+
614617
for (j = 0; j < nFields; j++)
615618
{
616619
fLength[j] = strlen(PQfname(res, j));
@@ -705,6 +708,11 @@ PQprintTuples(const PGresult *res,
705708

706709
width = nFields * 14;
707710
tborder = malloc(width + 1);
711+
if (!tborder)
712+
{
713+
fprintf(stderr, libpq_gettext("out of memory\n"));
714+
exit(1);
715+
}
708716
for (i = 0; i <= width; i++)
709717
tborder[i] = '-';
710718
tborder[i] = '\0';

0 commit comments

Comments
 (0)