From aa5377d221371f6be8729a27f1df18aa9c4a48e2 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 3 Oct 2023 16:12:14 +0900 Subject: [PATCH v5 1/4] Revert "Fail hard on out-of-memory failures in xlogreader.c" This reverts commit 6b18b3fe2c2, putting back the code of xlogreader.c to handle OOMs as soft failures. --- src/backend/access/transam/xlogreader.c | 47 ++++++++++++++++++++----- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index a1363e3b8f..a17263df20 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -43,7 +43,7 @@ static void report_invalid_record(XLogReaderState *state, const char *fmt,...) pg_attribute_printf(2, 3); -static void allocate_recordbuf(XLogReaderState *state, uint32 reclength); +static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength); static int ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen); static void XLogReaderInvalReadState(XLogReaderState *state); @@ -155,7 +155,14 @@ XLogReaderAllocate(int wal_segment_size, const char *waldir, * Allocate an initial readRecordBuf of minimal size, which can later be * enlarged if necessary. */ - allocate_recordbuf(state, 0); + if (!allocate_recordbuf(state, 0)) + { + pfree(state->errormsg_buf); + pfree(state->readBuf); + pfree(state); + return NULL; + } + return state; } @@ -177,6 +184,7 @@ XLogReaderFree(XLogReaderState *state) /* * Allocate readRecordBuf to fit a record of at least the given length. + * Returns true if successful, false if out of memory. * * readRecordBufSize is set to the new buffer size. * @@ -188,7 +196,7 @@ XLogReaderFree(XLogReaderState *state) * Note: This routine should *never* be called for xl_tot_len until the header * of the record has been fully validated. */ -static void +static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength) { uint32 newSize = reclength; @@ -198,8 +206,15 @@ allocate_recordbuf(XLogReaderState *state, uint32 reclength) if (state->readRecordBuf) pfree(state->readRecordBuf); - state->readRecordBuf = (char *) palloc(newSize); + state->readRecordBuf = + (char *) palloc_extended(newSize, MCXT_ALLOC_NO_OOM); + if (state->readRecordBuf == NULL) + { + state->readRecordBufSize = 0; + return false; + } state->readRecordBufSize = newSize; + return true; } /* @@ -490,7 +505,9 @@ XLogReadRecordAlloc(XLogReaderState *state, size_t xl_tot_len, bool allow_oversi /* Not enough space in the decode buffer. Are we allowed to allocate? */ if (allow_oversized) { - decoded = palloc(required_space); + decoded = palloc_extended(required_space, MCXT_ALLOC_NO_OOM); + if (decoded == NULL) + return NULL; decoded->oversized = true; return decoded; } @@ -798,7 +815,13 @@ restart: Assert(gotlen <= lengthof(save_copy)); Assert(gotlen <= state->readRecordBufSize); memcpy(save_copy, state->readRecordBuf, gotlen); - allocate_recordbuf(state, total_len); + if (!allocate_recordbuf(state, total_len)) + { + /* We treat this as a "bogus data" condition */ + report_invalid_record(state, "record length %u at %X/%X too long", + total_len, LSN_FORMAT_ARGS(RecPtr)); + goto err; + } memcpy(state->readRecordBuf, save_copy, gotlen); buffer = state->readRecordBuf + gotlen; } @@ -854,8 +877,16 @@ restart: decoded = XLogReadRecordAlloc(state, total_len, true /* allow_oversized */ ); - /* allocation should always happen under allow_oversized */ - Assert(decoded != NULL); + if (decoded == NULL) + { + /* + * We failed to allocate memory for an oversized record. As + * above, we currently treat this as a "bogus data" condition. + */ + report_invalid_record(state, + "out of memory while trying to decode a record of length %u", total_len); + goto err; + } } if (DecodeXLogRecord(state, decoded, record, RecPtr, &errormsg)) -- 2.42.0