*/
static XLogRecData *mainrdata_head;
static XLogRecData *mainrdata_last = (XLogRecData *) &mainrdata_head;
-static uint32 mainrdata_len; /* total # of bytes in chain */
+static uint64 mainrdata_len; /* total # of bytes in chain */
/* flags for the in-progress insertion */
static uint8 curinsert_flags = 0;
Assert(begininsert_called);
if (num_rdatas >= max_rdatas)
- elog(ERROR, "too much WAL data");
+ ereport(ERROR,
+ (errmsg_internal("too much WAL data"),
+ errdetail_internal("%u out of %u data segments are already in use.",
+ num_rdatas, max_rdatas)));
rdata = &rdatas[num_rdatas++];
rdata->data = data;
* regbuf->rdata_len does not grow beyond what
* XLogRecordBlockHeader->data_length can hold.
*/
- if (num_rdatas >= max_rdatas ||
- regbuf->rdata_len + len > UINT16_MAX)
- elog(ERROR, "too much WAL data");
+ if (num_rdatas >= max_rdatas)
+ ereport(ERROR,
+ (errmsg_internal("too much WAL data"),
+ errdetail_internal("%u out of %u data segments are already in use.",
+ num_rdatas, max_rdatas)));
+ if (regbuf->rdata_len + len > UINT16_MAX || len > UINT16_MAX)
+ ereport(ERROR,
+ (errmsg_internal("too much WAL data"),
+ errdetail_internal("Registering more than maximum %u bytes allowed to block %u: current %u bytes, adding %u bytes.",
+ UINT16_MAX, block_id, regbuf->rdata_len, len)));
rdata = &rdatas[num_rdatas++];
XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
{
XLogRecData *rdt;
- uint32 total_len = 0;
+ uint64 total_len = 0;
int block_id;
pg_crc32c rdata_crc;
registered_buffer *prev_regbuf = NULL;
{
if (mainrdata_len > 255)
{
+ uint32 mainrdata_len_4b;
+
+ if (mainrdata_len > PG_UINT32_MAX)
+ ereport(ERROR,
+ (errmsg_internal("too much WAL data"),
+ errdetail_internal("Main data length is %llu bytes for a maximum of %u bytes.",
+ (unsigned long long) mainrdata_len,
+ PG_UINT32_MAX)));
+
+ mainrdata_len_4b = (uint32) mainrdata_len;
*(scratch++) = (char) XLR_BLOCK_ID_DATA_LONG;
- memcpy(scratch, &mainrdata_len, sizeof(uint32));
+ memcpy(scratch, &mainrdata_len_4b, sizeof(uint32));
scratch += sizeof(uint32);
}
else
for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
COMP_CRC32C(rdata_crc, rdt->data, rdt->len);
+ /*
+ * Ensure that the XLogRecord is not too large.
+ *
+ * XLogReader machinery is only able to handle records up to a certain
+ * size (ignoring machine resource limitations), so make sure that we will
+ * not emit records larger than the sizes advertised to be supported.
+ * This cap is based on DecodeXLogRecordRequiredSpace().
+ */
+ if (total_len >= XLogRecordMaxSize)
+ ereport(ERROR,
+ (errmsg_internal("oversized WAL record"),
+ errdetail_internal("WAL record would be %llu bytes (of maximum %u bytes); rmid %u flags %u.",
+ (unsigned long long) total_len, XLogRecordMaxSize, rmid, info)));
+
/*
* Fill in the fields in the record header. Prev-link is filled in later,
* once we know where in the WAL the record will be inserted. The CRC does
* not include the record header yet.
*/
rechdr->xl_xid = GetCurrentTransactionIdIfAny();
- rechdr->xl_tot_len = total_len;
+ rechdr->xl_tot_len = (uint32) total_len;
rechdr->xl_info = info;
rechdr->xl_rmid = rmid;
rechdr->xl_prev = InvalidXLogRecPtr;
void
InitXLogInsert(void)
{
+#ifdef USE_ASSERT_CHECKING
+
+ /*
+ * Check that any records assembled can be decoded. This is capped based
+ * on what XLogReader would require at its maximum bound. This code path
+ * is called once per backend, more than enough for this check.
+ */
+ size_t max_required = DecodeXLogRecordRequiredSpace(XLogRecordMaxSize);
+
+ Assert(AllocSizeIsValid(max_required));
+#endif
+
/* Initialize the working areas */
if (xloginsert_cxt == NULL)
{