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

Commit739259d

Browse files
committed
Adjust the behavior of the PQExpBuffer code to make it have well-defined
results (ie, an empty "broken" buffer) if memory overrun occurs anywherealong the way to filling the buffer. The previous coding would just silentlydiscard portions of the intended buffer contents, as exhibited in troublereport from Sam Mason. Also, tweak psql's main loop to correctly detectand report such overruns. There's probably much more that should be donein this line, but this is a start.
1 parent8a10096 commit739259d

File tree

6 files changed

+124
-27
lines changed

6 files changed

+124
-27
lines changed

‎src/bin/psql/input.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.64 2008/01/01 19:45:56 momjian Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.65 2008/11/26 00:26:23 tgl Exp $
77
*/
88
#include"postgres_fe.h"
99

@@ -184,14 +184,21 @@ gets_fromFile(FILE *source)
184184
{
185185
if (ferror(source))
186186
{
187-
psql_error("could not read from input file: %s\n",strerror(errno));
187+
psql_error("could not read from input file: %s\n",
188+
strerror(errno));
188189
returnNULL;
189190
}
190191
break;
191192
}
192193

193194
appendPQExpBufferStr(buffer,line);
194195

196+
if (PQExpBufferBroken(buffer))
197+
{
198+
psql_error("out of memory\n");
199+
returnNULL;
200+
}
201+
195202
/* EOL? */
196203
if (buffer->data[buffer->len-1]=='\n')
197204
{

‎src/bin/psql/mainloop.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.92 2008/06/10 20:58:19 neilc Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.93 2008/11/26 00:26:23 tgl Exp $
77
*/
88
#include"postgres_fe.h"
99
#include"mainloop.h"
@@ -26,9 +26,9 @@ int
2626
MainLoop(FILE*source)
2727
{
2828
PsqlScanStatescan_state;/* lexer working state */
29-
PQExpBufferquery_buf;/* buffer for query being accumulated */
30-
PQExpBufferprevious_buf;/* if there isn't anything in the new buffer
31-
* yet, use this one for \e, etc. */
29+
volatilePQExpBufferquery_buf;/* buffer for query being accumulated */
30+
volatilePQExpBufferprevious_buf;/* if there isn't anything in the new
31+
*bufferyet, use this one for \e, etc. */
3232
PQExpBufferhistory_buf;/* earlier lines of a multi-line command, not
3333
* yet saved to readline history */
3434
char*line;/* current line of input */
@@ -62,7 +62,9 @@ MainLoop(FILE *source)
6262
query_buf=createPQExpBuffer();
6363
previous_buf=createPQExpBuffer();
6464
history_buf=createPQExpBuffer();
65-
if (!query_buf|| !previous_buf|| !history_buf)
65+
if (PQExpBufferBroken(query_buf)||
66+
PQExpBufferBroken(previous_buf)||
67+
PQExpBufferBroken(history_buf))
6668
{
6769
psql_error("out of memory\n");
6870
exit(EXIT_FAILURE);
@@ -220,6 +222,12 @@ MainLoop(FILE *source)
220222
scan_result=psql_scan(scan_state,query_buf,&prompt_tmp);
221223
prompt_status=prompt_tmp;
222224

225+
if (PQExpBufferBroken(query_buf))
226+
{
227+
psql_error("out of memory\n");
228+
exit(EXIT_FAILURE);
229+
}
230+
223231
/*
224232
* Send command if semicolon found, or if end of line and we're in
225233
* single-line mode.
@@ -242,9 +250,15 @@ MainLoop(FILE *source)
242250
success=SendQuery(query_buf->data);
243251
slashCmdStatus=success ?PSQL_CMD_SEND :PSQL_CMD_ERROR;
244252

245-
resetPQExpBuffer(previous_buf);
246-
appendPQExpBufferStr(previous_buf,query_buf->data);
253+
/* transfer query to previous_buf by pointer-swapping */
254+
{
255+
PQExpBufferswap_buf=previous_buf;
256+
257+
previous_buf=query_buf;
258+
query_buf=swap_buf;
259+
}
247260
resetPQExpBuffer(query_buf);
261+
248262
added_nl_pos=-1;
249263
/* we need not do psql_scan_reset() here */
250264
}
@@ -294,8 +308,13 @@ MainLoop(FILE *source)
294308
{
295309
success=SendQuery(query_buf->data);
296310

297-
resetPQExpBuffer(previous_buf);
298-
appendPQExpBufferStr(previous_buf,query_buf->data);
311+
/* transfer query to previous_buf by pointer-swapping */
312+
{
313+
PQExpBufferswap_buf=previous_buf;
314+
315+
previous_buf=query_buf;
316+
query_buf=swap_buf;
317+
}
299318
resetPQExpBuffer(query_buf);
300319

301320
/* flush any paren nesting info after forced send */

‎src/bin/psql/psqlscan.l

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* Portions Copyright (c) 1994, Regents of the University of California
3434
*
3535
* IDENTIFICATION
36-
* $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.26 2008/10/29 08:04:53 petere Exp $
36+
* $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.27 2008/11/26 00:26:23 tgl Exp $
3737
*
3838
*-------------------------------------------------------------------------
3939
*/
@@ -1453,6 +1453,12 @@ psql_scan_slash_option(PsqlScanState state,
14531453
error =true;
14541454
}
14551455

1456+
if (PQExpBufferBroken(&output))
1457+
{
1458+
psql_error("%s: out of memory\n", cmd);
1459+
error =true;
1460+
}
1461+
14561462
/* Now done with cmd, transfer result to mybuf */
14571463
resetPQExpBuffer(&mybuf);
14581464

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

Lines changed: 5 additions & 5 deletions
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.369 2008/11/25 19:30:42 tgl Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.370 2008/11/26 00:26:23 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -585,7 +585,7 @@ PQconndefaults(void)
585585
PQconninfoOption*connOptions;
586586

587587
initPQExpBuffer(&errorBuf);
588-
if (errorBuf.data==NULL)
588+
if (PQExpBufferBroken(&errorBuf))
589589
returnNULL;/* out of memory already :-( */
590590
connOptions=conninfo_parse("",&errorBuf, true);
591591
termPQExpBuffer(&errorBuf);
@@ -1970,8 +1970,8 @@ makeEmptyPGconn(void)
19701970

19711971
if (conn->inBuffer==NULL||
19721972
conn->outBuffer==NULL||
1973-
conn->errorMessage.data==NULL||
1974-
conn->workBuffer.data==NULL)
1973+
PQExpBufferBroken(&conn->errorMessage)||
1974+
PQExpBufferBroken(&conn->workBuffer))
19751975
{
19761976
/* out of memory already :-( */
19771977
freePGconn(conn);
@@ -3151,7 +3151,7 @@ PQconninfoParse(const char *conninfo, char **errmsg)
31513151
if (errmsg)
31523152
*errmsg=NULL;/* default */
31533153
initPQExpBuffer(&errorBuf);
3154-
if (errorBuf.data==NULL)
3154+
if (PQExpBufferBroken(&errorBuf))
31553155
returnNULL;/* out of memory already :-( */
31563156
connOptions=conninfo_parse(conninfo,&errorBuf, false);
31573157
if (connOptions==NULL&&errmsg)

‎src/interfaces/libpq/pqexpbuffer.c

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
1818
* Portions Copyright (c) 1994, Regents of the University of California
1919
*
20-
* $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.24 2008/01/01 19:46:00 momjian Exp $
20+
* $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.25 2008/11/26 00:26:23 tgl Exp $
2121
*
2222
*-------------------------------------------------------------------------
2323
*/
@@ -32,6 +32,32 @@
3232
#include"win32.h"
3333
#endif
3434

35+
36+
/* All "broken" PQExpBuffers point to this string. */
37+
staticconstcharoom_buffer[1]="";
38+
39+
40+
/*
41+
* markPQExpBufferBroken
42+
*
43+
* Put a PQExpBuffer in "broken" state if it isn't already.
44+
*/
45+
staticvoid
46+
markPQExpBufferBroken(PQExpBufferstr)
47+
{
48+
if (str->data!=oom_buffer)
49+
free(str->data);
50+
/*
51+
* Casting away const here is a bit ugly, but it seems preferable to
52+
* not marking oom_buffer const. We want to do that to encourage the
53+
* compiler to put oom_buffer in read-only storage, so that anyone who
54+
* tries to scribble on a broken PQExpBuffer will get a failure.
55+
*/
56+
str->data= (char*)oom_buffer;
57+
str->len=0;
58+
str->maxlen=0;
59+
}
60+
3561
/*
3662
* createPQExpBuffer
3763
*
@@ -61,6 +87,7 @@ initPQExpBuffer(PQExpBuffer str)
6187
str->data= (char*)malloc(INITIAL_EXPBUFFER_SIZE);
6288
if (str->data==NULL)
6389
{
90+
str->data= (char*)oom_buffer;/* see comment above */
6491
str->maxlen=0;
6592
str->len=0;
6693
}
@@ -96,28 +123,35 @@ destroyPQExpBuffer(PQExpBuffer str)
96123
void
97124
termPQExpBuffer(PQExpBufferstr)
98125
{
99-
if (str->data)
100-
{
126+
if (str->data!=oom_buffer)
101127
free(str->data);
102-
str->data=NULL;
103-
}
104128
/* just for luck, make the buffer validly empty. */
129+
str->data= (char*)oom_buffer;/* see comment above */
105130
str->maxlen=0;
106131
str->len=0;
107132
}
108133

109134
/*
110135
* resetPQExpBuffer
111136
*Reset a PQExpBuffer to empty
137+
*
138+
* Note: if possible, a "broken" PQExpBuffer is returned to normal.
112139
*/
113140
void
114141
resetPQExpBuffer(PQExpBufferstr)
115142
{
116143
if (str)
117144
{
118-
str->len=0;
119-
if (str->data)
145+
if (str->data!=oom_buffer)
146+
{
147+
str->len=0;
120148
str->data[0]='\0';
149+
}
150+
else
151+
{
152+
/* try to reinitialize to valid state */
153+
initPQExpBuffer(str);
154+
}
121155
}
122156
}
123157

@@ -126,21 +160,28 @@ resetPQExpBuffer(PQExpBuffer str)
126160
* Make sure there is enough space for 'needed' more bytes in the buffer
127161
* ('needed' does not include the terminating null).
128162
*
129-
* Returns 1 if OK, 0 if failed to enlarge buffer.
163+
* Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case
164+
* the buffer is left in "broken" state.)
130165
*/
131166
int
132167
enlargePQExpBuffer(PQExpBufferstr,size_tneeded)
133168
{
134169
size_tnewlen;
135170
char*newdata;
136171

172+
if (PQExpBufferBroken(str))
173+
return0;/* already failed */
174+
137175
/*
138176
* Guard against ridiculous "needed" values, which can occur if we're fed
139177
* bogus data.Without this, we can get an overflow or infinite loop in
140178
* the following.
141179
*/
142180
if (needed >= ((size_t)INT_MAX-str->len))
181+
{
182+
markPQExpBufferBroken(str);
143183
return0;
184+
}
144185

145186
needed+=str->len+1;/* total space required now */
146187

@@ -173,6 +214,8 @@ enlargePQExpBuffer(PQExpBuffer str, size_t needed)
173214
str->maxlen=newlen;
174215
return1;
175216
}
217+
218+
markPQExpBufferBroken(str);
176219
return0;
177220
}
178221

@@ -192,6 +235,9 @@ printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
192235

193236
resetPQExpBuffer(str);
194237

238+
if (PQExpBufferBroken(str))
239+
return;/* already failed */
240+
195241
for (;;)
196242
{
197243
/*
@@ -240,6 +286,9 @@ appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
240286
size_tavail;
241287
intnprinted;
242288

289+
if (PQExpBufferBroken(str))
290+
return;/* already failed */
291+
243292
for (;;)
244293
{
245294
/*

‎src/interfaces/libpq/pqexpbuffer.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
1919
* Portions Copyright (c) 1994, Regents of the University of California
2020
*
21-
* $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.h,v 1.19 2008/01/01 19:46:00 momjian Exp $
21+
* $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.h,v 1.20 2008/11/26 00:26:23 tgl Exp $
2222
*
2323
*-------------------------------------------------------------------------
2424
*/
@@ -35,6 +35,10 @@
3535
*string size (including the terminating '\0' char) that we can
3636
*currently store in 'data' without having to reallocate
3737
*more space. We must always have maxlen > len.
38+
*
39+
* An exception occurs if we failed to allocate enough memory for the string
40+
* buffer. In that case data points to a statically allocated empty string,
41+
* and len = maxlen = 0.
3842
*-------------------------
3943
*/
4044
typedefstructPQExpBufferData
@@ -46,6 +50,15 @@ typedef struct PQExpBufferData
4650

4751
typedefPQExpBufferData*PQExpBuffer;
4852

53+
/*------------------------
54+
* Test for a broken (out of memory) PQExpBuffer.
55+
* When a buffer is "broken", all operations except resetting or deleting it
56+
* are no-ops.
57+
*------------------------
58+
*/
59+
#definePQExpBufferBroken(str) \
60+
(!(str) || (str)->maxlen == 0)
61+
4962
/*------------------------
5063
* Initial size of the data buffer in a PQExpBuffer.
5164
* NB: this must be large enough to hold error messages that might
@@ -103,6 +116,8 @@ extern void termPQExpBuffer(PQExpBuffer str);
103116
/*------------------------
104117
* resetPQExpBuffer
105118
*Reset a PQExpBuffer to empty
119+
*
120+
* Note: if possible, a "broken" PQExpBuffer is returned to normal.
106121
*/
107122
externvoidresetPQExpBuffer(PQExpBufferstr);
108123

@@ -111,7 +126,8 @@ extern void resetPQExpBuffer(PQExpBuffer str);
111126
* Make sure there is enough space for 'needed' more bytes in the buffer
112127
* ('needed' does not include the terminating null).
113128
*
114-
* Returns 1 if OK, 0 if failed to enlarge buffer.
129+
* Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case
130+
* the buffer is left in "broken" state.)
115131
*/
116132
externintenlargePQExpBuffer(PQExpBufferstr,size_tneeded);
117133

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp