*
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.64 2008/01/01 19:45:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.65 2008/11/26 00:26:23 tgl Exp $
*/
#include "postgres_fe.h"
{
if (ferror(source))
{
- psql_error("could not read from input file: %s\n", strerror(errno));
+ psql_error("could not read from input file: %s\n",
+ strerror(errno));
return NULL;
}
break;
appendPQExpBufferStr(buffer, line);
+ if (PQExpBufferBroken(buffer))
+ {
+ psql_error("out of memory\n");
+ return NULL;
+ }
+
/* EOL? */
if (buffer->data[buffer->len - 1] == '\n')
{
*
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.92 2008/06/10 20:58:19 neilc Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.93 2008/11/26 00:26:23 tgl Exp $
*/
#include "postgres_fe.h"
#include "mainloop.h"
MainLoop(FILE *source)
{
PsqlScanState scan_state; /* lexer working state */
- PQExpBuffer query_buf; /* buffer for query being accumulated */
- PQExpBuffer previous_buf; /* if there isn't anything in the new buffer
- * yet, use this one for \e, etc. */
+ volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
+ volatile PQExpBuffer previous_buf; /* if there isn't anything in the new
+ * buffer yet, use this one for \e, etc. */
PQExpBuffer history_buf; /* earlier lines of a multi-line command, not
* yet saved to readline history */
char *line; /* current line of input */
query_buf = createPQExpBuffer();
previous_buf = createPQExpBuffer();
history_buf = createPQExpBuffer();
- if (!query_buf || !previous_buf || !history_buf)
+ if (PQExpBufferBroken(query_buf) ||
+ PQExpBufferBroken(previous_buf) ||
+ PQExpBufferBroken(history_buf))
{
psql_error("out of memory\n");
exit(EXIT_FAILURE);
scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
prompt_status = prompt_tmp;
+ if (PQExpBufferBroken(query_buf))
+ {
+ psql_error("out of memory\n");
+ exit(EXIT_FAILURE);
+ }
+
/*
* Send command if semicolon found, or if end of line and we're in
* single-line mode.
success = SendQuery(query_buf->data);
slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
- resetPQExpBuffer(previous_buf);
- appendPQExpBufferStr(previous_buf, query_buf->data);
+ /* transfer query to previous_buf by pointer-swapping */
+ {
+ PQExpBuffer swap_buf = previous_buf;
+
+ previous_buf = query_buf;
+ query_buf = swap_buf;
+ }
resetPQExpBuffer(query_buf);
+
added_nl_pos = -1;
/* we need not do psql_scan_reset() here */
}
{
success = SendQuery(query_buf->data);
- resetPQExpBuffer(previous_buf);
- appendPQExpBufferStr(previous_buf, query_buf->data);
+ /* transfer query to previous_buf by pointer-swapping */
+ {
+ PQExpBuffer swap_buf = previous_buf;
+
+ previous_buf = query_buf;
+ query_buf = swap_buf;
+ }
resetPQExpBuffer(query_buf);
/* flush any paren nesting info after forced send */
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.26 2008/10/29 08:04:53 petere Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.27 2008/11/26 00:26:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
error = true;
}
+ if (PQExpBufferBroken(&output))
+ {
+ psql_error("%s: out of memory\n", cmd);
+ error = true;
+ }
+
/* Now done with cmd, transfer result to mybuf */
resetPQExpBuffer(&mybuf);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.369 2008/11/25 19:30:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.370 2008/11/26 00:26:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
PQconninfoOption *connOptions;
initPQExpBuffer(&errorBuf);
- if (errorBuf.data == NULL)
+ if (PQExpBufferBroken(&errorBuf))
return NULL; /* out of memory already :-( */
connOptions = conninfo_parse("", &errorBuf, true);
termPQExpBuffer(&errorBuf);
if (conn->inBuffer == NULL ||
conn->outBuffer == NULL ||
- conn->errorMessage.data == NULL ||
- conn->workBuffer.data == NULL)
+ PQExpBufferBroken(&conn->errorMessage) ||
+ PQExpBufferBroken(&conn->workBuffer))
{
/* out of memory already :-( */
freePGconn(conn);
if (errmsg)
*errmsg = NULL; /* default */
initPQExpBuffer(&errorBuf);
- if (errorBuf.data == NULL)
+ if (PQExpBufferBroken(&errorBuf))
return NULL; /* out of memory already :-( */
connOptions = conninfo_parse(conninfo, &errorBuf, false);
if (connOptions == NULL && errmsg)
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.24 2008/01/01 19:46:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.25 2008/11/26 00:26:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "win32.h"
#endif
+
+/* All "broken" PQExpBuffers point to this string. */
+static const char oom_buffer[1] = "";
+
+
+/*
+ * markPQExpBufferBroken
+ *
+ * Put a PQExpBuffer in "broken" state if it isn't already.
+ */
+static void
+markPQExpBufferBroken(PQExpBuffer str)
+{
+ if (str->data != oom_buffer)
+ free(str->data);
+ /*
+ * Casting away const here is a bit ugly, but it seems preferable to
+ * not marking oom_buffer const. We want to do that to encourage the
+ * compiler to put oom_buffer in read-only storage, so that anyone who
+ * tries to scribble on a broken PQExpBuffer will get a failure.
+ */
+ str->data = (char *) oom_buffer;
+ str->len = 0;
+ str->maxlen = 0;
+}
+
/*
* createPQExpBuffer
*
str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
if (str->data == NULL)
{
+ str->data = (char *) oom_buffer; /* see comment above */
str->maxlen = 0;
str->len = 0;
}
void
termPQExpBuffer(PQExpBuffer str)
{
- if (str->data)
- {
+ if (str->data != oom_buffer)
free(str->data);
- str->data = NULL;
- }
/* just for luck, make the buffer validly empty. */
+ str->data = (char *) oom_buffer; /* see comment above */
str->maxlen = 0;
str->len = 0;
}
/*
* resetPQExpBuffer
* Reset a PQExpBuffer to empty
+ *
+ * Note: if possible, a "broken" PQExpBuffer is returned to normal.
*/
void
resetPQExpBuffer(PQExpBuffer str)
{
if (str)
{
- str->len = 0;
- if (str->data)
+ if (str->data != oom_buffer)
+ {
+ str->len = 0;
str->data[0] = '\0';
+ }
+ else
+ {
+ /* try to reinitialize to valid state */
+ initPQExpBuffer(str);
+ }
}
}
* Make sure there is enough space for 'needed' more bytes in the buffer
* ('needed' does not include the terminating null).
*
- * Returns 1 if OK, 0 if failed to enlarge buffer.
+ * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case
+ * the buffer is left in "broken" state.)
*/
int
enlargePQExpBuffer(PQExpBuffer str, size_t needed)
size_t newlen;
char *newdata;
+ if (PQExpBufferBroken(str))
+ return 0; /* already failed */
+
/*
* Guard against ridiculous "needed" values, which can occur if we're fed
* bogus data. Without this, we can get an overflow or infinite loop in
* the following.
*/
if (needed >= ((size_t) INT_MAX - str->len))
+ {
+ markPQExpBufferBroken(str);
return 0;
+ }
needed += str->len + 1; /* total space required now */
str->maxlen = newlen;
return 1;
}
+
+ markPQExpBufferBroken(str);
return 0;
}
resetPQExpBuffer(str);
+ if (PQExpBufferBroken(str))
+ return; /* already failed */
+
for (;;)
{
/*
size_t avail;
int nprinted;
+ if (PQExpBufferBroken(str))
+ return; /* already failed */
+
for (;;)
{
/*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.h,v 1.19 2008/01/01 19:46:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.h,v 1.20 2008/11/26 00:26:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* string size (including the terminating '\0' char) that we can
* currently store in 'data' without having to reallocate
* more space. We must always have maxlen > len.
+ *
+ * An exception occurs if we failed to allocate enough memory for the string
+ * buffer. In that case data points to a statically allocated empty string,
+ * and len = maxlen = 0.
*-------------------------
*/
typedef struct PQExpBufferData
typedef PQExpBufferData *PQExpBuffer;
+/*------------------------
+ * Test for a broken (out of memory) PQExpBuffer.
+ * When a buffer is "broken", all operations except resetting or deleting it
+ * are no-ops.
+ *------------------------
+ */
+#define PQExpBufferBroken(str) \
+ (!(str) || (str)->maxlen == 0)
+
/*------------------------
* Initial size of the data buffer in a PQExpBuffer.
* NB: this must be large enough to hold error messages that might
/*------------------------
* resetPQExpBuffer
* Reset a PQExpBuffer to empty
+ *
+ * Note: if possible, a "broken" PQExpBuffer is returned to normal.
*/
extern void resetPQExpBuffer(PQExpBuffer str);
* Make sure there is enough space for 'needed' more bytes in the buffer
* ('needed' does not include the terminating null).
*
- * Returns 1 if OK, 0 if failed to enlarge buffer.
+ * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case
+ * the buffer is left in "broken" state.)
*/
extern int enlargePQExpBuffer(PQExpBuffer str, size_t needed);