]> granicus.if.org Git - postgresql/commitdiff
Fix error handling of XLogReaderAllocate in case of OOM
authorFujii Masao <fujii@postgresql.org>
Fri, 3 Apr 2015 12:55:37 +0000 (21:55 +0900)
committerFujii Masao <fujii@postgresql.org>
Fri, 3 Apr 2015 12:55:37 +0000 (21:55 +0900)
Similarly to previous fix 9b8d478, commit 2c03216 has switched
XLogReaderAllocate() to use a set of palloc calls instead of malloc,
causing any callers of this function to fail with an error instead of
receiving a NULL pointer in case of out-of-memory error. Fix this by
using palloc_extended with MCXT_ALLOC_NO_OOM that will safely return
NULL in case of an OOM.

Michael Paquier, slightly modified by me.

src/backend/access/transam/xlog.c
src/backend/access/transam/xlogreader.c
src/backend/replication/logical/logical.c
src/bin/pg_rewind/parsexlog.c

index 346a2b39f8585371e6700dfbf0ea65bb2c02f667..24cf520e579e27e7e2ab859695c89a367d294650 100644 (file)
@@ -1062,8 +1062,11 @@ XLogInsertRecord(XLogRecData *rdata, XLogRecPtr fpw_lsn)
                if (!debug_reader)
                        debug_reader = XLogReaderAllocate(NULL, NULL);
 
-               if (!debug_reader ||
-                       !DecodeXLogRecord(debug_reader, (XLogRecord *) recordBuf.data,
+               if (!debug_reader)
+               {
+                       appendStringInfo(&buf, "error decoding record: out of memory");
+               }
+               else if (!DecodeXLogRecord(debug_reader, (XLogRecord *) recordBuf.data,
                                                          &errormsg))
                {
                        appendStringInfo(&buf, "error decoding record: %s",
index ffdc9753ad739c14fcce3f587b6d581df59c7ef7..a4124d90d1b60561cdb26a0ffbe5127e63f50cd9 100644 (file)
@@ -58,15 +58,18 @@ report_invalid_record(XLogReaderState *state, const char *fmt,...)
 /*
  * Allocate and initialize a new XLogReader.
  *
- * The returned XLogReader is palloc'd. (In FRONTEND code, that means that
- * running out-of-memory causes an immediate exit(1).
+ * Returns NULL if the xlogreader couldn't be allocated.
  */
 XLogReaderState *
 XLogReaderAllocate(XLogPageReadCB pagereadfunc, void *private_data)
 {
        XLogReaderState *state;
 
-       state = (XLogReaderState *) palloc0(sizeof(XLogReaderState));
+       state = (XLogReaderState *)
+               palloc_extended(sizeof(XLogReaderState),
+                                               MCXT_ALLOC_NO_OOM | MCXT_ALLOC_ZERO);
+       if (!state)
+               return NULL;
 
        state->max_block_id = -1;
 
@@ -74,17 +77,30 @@ XLogReaderAllocate(XLogPageReadCB pagereadfunc, void *private_data)
         * Permanently allocate readBuf.  We do it this way, rather than just
         * making a static array, for two reasons: (1) no need to waste the
         * storage in most instantiations of the backend; (2) a static char array
-        * isn't guaranteed to have any particular alignment, whereas palloc()
-        * will provide MAXALIGN'd storage.
+        * isn't guaranteed to have any particular alignment, whereas
+        * palloc_extended() will provide MAXALIGN'd storage.
         */
-       state->readBuf = (char *) palloc(XLOG_BLCKSZ);
+       state->readBuf = (char *) palloc_extended(XLOG_BLCKSZ,
+                                                                                         MCXT_ALLOC_NO_OOM);
+       if (!state->readBuf)
+       {
+               pfree(state);
+               return NULL;
+       }
 
        state->read_page = pagereadfunc;
        /* system_identifier initialized to zeroes above */
        state->private_data = private_data;
        /* ReadRecPtr and EndRecPtr initialized to zeroes above */
        /* readSegNo, readOff, readLen, readPageTLI initialized to zeroes above */
-       state->errormsg_buf = palloc(MAX_ERRORMSG_LEN + 1);
+       state->errormsg_buf = palloc_extended(MAX_ERRORMSG_LEN + 1,
+                                                                                 MCXT_ALLOC_NO_OOM);
+       if (!state->errormsg_buf)
+       {
+               pfree(state->readBuf);
+               pfree(state);
+               return NULL;
+       }
        state->errormsg_buf[0] = '\0';
 
        /*
index 30baa45383a3dc9f896755a3e0eb9f737e47a032..774ebbc749cbd9460d4d63e1249c0b5aa16e3e81 100644 (file)
@@ -163,6 +163,11 @@ StartupDecodingContext(List *output_plugin_options,
        ctx->slot = slot;
 
        ctx->reader = XLogReaderAllocate(read_page, ctx);
+       if (!ctx->reader)
+               ereport(ERROR,
+                               (errcode(ERRCODE_OUT_OF_MEMORY),
+                                errmsg("out of memory")));
+
        ctx->reader->private_data = ctx;
 
        ctx->reorder = ReorderBufferAllocate();
index 0787ca12a7899d07d769946ad0da33cbfeee1da0..3cf96abd0850a593d4d11f022a8a28beba9a3820 100644 (file)
@@ -70,6 +70,8 @@ extractPageMap(const char *datadir, XLogRecPtr startpoint, TimeLineID tli,
        private.datadir = datadir;
        private.tli = tli;
        xlogreader = XLogReaderAllocate(&SimpleXLogPageRead, &private);
+       if (xlogreader == NULL)
+               pg_fatal("out of memory");
 
        do
        {
@@ -121,6 +123,8 @@ readOneRecord(const char *datadir, XLogRecPtr ptr, TimeLineID tli)
        private.datadir = datadir;
        private.tli = tli;
        xlogreader = XLogReaderAllocate(&SimpleXLogPageRead, &private);
+       if (xlogreader == NULL)
+               pg_fatal("out of memory");
 
        record = XLogReadRecord(xlogreader, ptr, &errormsg);
        if (record == NULL)
@@ -171,6 +175,8 @@ findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, TimeLineID tli,
        private.datadir = datadir;
        private.tli = tli;
        xlogreader = XLogReaderAllocate(&SimpleXLogPageRead, &private);
+       if (xlogreader == NULL)
+               pg_fatal("out of memory");
 
        searchptr = forkptr;
        for (;;)