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

Commit6b18b3f

Browse files
committed
Fail hard on out-of-memory failures in xlogreader.c
This commit changes the WAL reader routines so as a FATAL for thebackend or exit(FAILURE) for the frontend is triggered if an allocationfor a WAL record decode fails in walreader.c, rather than treating thiscase as bogus data, which would be equivalent to the end of WAL. Thekey is to avoid palloc_extended(MCXT_ALLOC_NO_OOM) in walreader.c,relying on plain palloc() calls.The previous behavior could make WAL replay finish too early than itshould. For example, crash recovery finishing earlier may corruptclusters because not all the WAL available locally was replayed toensure a consistent state. Out-of-memory failures would show uprandomly depending on the memory pressure on the host, but one simplecase would be to generate a large record, then replay this record afterdownsizing a host, as Ethan Mertz originally reported.This relies onbae868c, as the WAL reader routines now do thememory allocation required for a record only once its header has beenfully read and validated, making xl_tot_len trustable. Making the WALreader react differently on out-of-memory or bogus record data wouldrequire ABI changes, so this is the safest choice for stable branches.Also, it is worth noting that3f1ce97 has been using a plainpalloc() in this code for some time now.Thanks to Noah Misch and Thomas Munro for the discussion.Like the other commit, backpatch down to 12, leaving out v11 that willbe EOL'd soon. The behavior of considering a failed allocation as bogusdata comes originally from0ffe11a, where the record lengthretrieved from its header was not entirely trustable.Reported-by: Ethan MertzDiscussion:https://postgr.es/m/ZRKKdI5-RRlta3aF@paquier.xyzBackpatch-through: 12
1 parent6c77bb4 commit6b18b3f

File tree

1 file changed

+8
-39
lines changed

1 file changed

+8
-39
lines changed

‎src/backend/access/transam/xlogreader.c

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
staticvoidreport_invalid_record(XLogReaderState*state,constchar*fmt,...)
4545
pg_attribute_printf(2,3);
46-
staticboolallocate_recordbuf(XLogReaderState*state,uint32reclength);
46+
staticvoidallocate_recordbuf(XLogReaderState*state,uint32reclength);
4747
staticintReadPageInternal(XLogReaderState*state,XLogRecPtrpageptr,
4848
intreqLen);
4949
staticvoidXLogReaderInvalReadState(XLogReaderState*state);
@@ -155,14 +155,7 @@ XLogReaderAllocate(int wal_segment_size, const char *waldir,
155155
* Allocate an initial readRecordBuf of minimal size, which can later be
156156
* enlarged if necessary.
157157
*/
158-
if (!allocate_recordbuf(state,0))
159-
{
160-
pfree(state->errormsg_buf);
161-
pfree(state->readBuf);
162-
pfree(state);
163-
returnNULL;
164-
}
165-
158+
allocate_recordbuf(state,0);
166159
returnstate;
167160
}
168161

@@ -184,7 +177,6 @@ XLogReaderFree(XLogReaderState *state)
184177

185178
/*
186179
* Allocate readRecordBuf to fit a record of at least the given length.
187-
* Returns true if successful, false if out of memory.
188180
*
189181
* readRecordBufSize is set to the new buffer size.
190182
*
@@ -196,7 +188,7 @@ XLogReaderFree(XLogReaderState *state)
196188
* Note: This routine should *never* be called for xl_tot_len until the header
197189
* of the record has been fully validated.
198190
*/
199-
staticbool
191+
staticvoid
200192
allocate_recordbuf(XLogReaderState*state,uint32reclength)
201193
{
202194
uint32newSize=reclength;
@@ -206,15 +198,8 @@ allocate_recordbuf(XLogReaderState *state, uint32 reclength)
206198

207199
if (state->readRecordBuf)
208200
pfree(state->readRecordBuf);
209-
state->readRecordBuf=
210-
(char*)palloc_extended(newSize,MCXT_ALLOC_NO_OOM);
211-
if (state->readRecordBuf==NULL)
212-
{
213-
state->readRecordBufSize=0;
214-
return false;
215-
}
201+
state->readRecordBuf= (char*)palloc(newSize);
216202
state->readRecordBufSize=newSize;
217-
return true;
218203
}
219204

220205
/*
@@ -505,9 +490,7 @@ XLogReadRecordAlloc(XLogReaderState *state, size_t xl_tot_len, bool allow_oversi
505490
/* Not enough space in the decode buffer. Are we allowed to allocate? */
506491
if (allow_oversized)
507492
{
508-
decoded=palloc_extended(required_space,MCXT_ALLOC_NO_OOM);
509-
if (decoded==NULL)
510-
returnNULL;
493+
decoded=palloc(required_space);
511494
decoded->oversized= true;
512495
returndecoded;
513496
}
@@ -815,13 +798,7 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
815798
Assert(gotlen <=lengthof(save_copy));
816799
Assert(gotlen <=state->readRecordBufSize);
817800
memcpy(save_copy,state->readRecordBuf,gotlen);
818-
if (!allocate_recordbuf(state,total_len))
819-
{
820-
/* We treat this as a "bogus data" condition */
821-
report_invalid_record(state,"record length %u at %X/%X too long",
822-
total_len,LSN_FORMAT_ARGS(RecPtr));
823-
gotoerr;
824-
}
801+
allocate_recordbuf(state,total_len);
825802
memcpy(state->readRecordBuf,save_copy,gotlen);
826803
buffer=state->readRecordBuf+gotlen;
827804
}
@@ -877,16 +854,8 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
877854
decoded=XLogReadRecordAlloc(state,
878855
total_len,
879856
true/* allow_oversized */ );
880-
if (decoded==NULL)
881-
{
882-
/*
883-
* We failed to allocate memory for an oversized record. As
884-
* above, we currently treat this as a "bogus data" condition.
885-
*/
886-
report_invalid_record(state,
887-
"out of memory while trying to decode a record of length %u",total_len);
888-
gotoerr;
889-
}
857+
/* allocation should always happen under allow_oversized */
858+
Assert(decoded!=NULL);
890859
}
891860

892861
if (DecodeXLogRecord(state,decoded,record,RecPtr,&errormsg))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp