Skip to content

Commit ac3afd1

Browse files
committed
Fix AlignedAllocRealloc to cope sanely with OOM.
If the inner allocation call returns NULL, we should restore the previous state and return NULL. Previously this code pfree'd the old chunk anyway, which is surely wrong. Also, make it call MemoryContextAllocationFailure rather than summarily returning NULL. The fact that we got control back from the inner call proves that MCXT_ALLOC_NO_OOM was passed, so this change is just cosmetic, but someday it might be less so. This is just a latent bug at present: AFAICT no in-core callers use this function at all, let alone call it with MCXT_ALLOC_NO_OOM. Still, it's the kind of bug that might bite back-patched code pretty hard someday, so let's back-patch to v17 where the bug was introduced (by commit 743112a). Author: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/285483.1746756246@sss.pgh.pa.us Backpatch-through: 17
1 parent 20bae06 commit ac3afd1

File tree

1 file changed

+22
-7
lines changed

1 file changed

+22
-7
lines changed

src/backend/utils/mmgr/alignedalloc.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ AlignedAllocFree(void *pointer)
4545
GetMemoryChunkContext(unaligned)->name, chunk);
4646
#endif
4747

48+
/* Recursively pfree the unaligned chunk */
4849
pfree(unaligned);
4950
}
5051

@@ -96,18 +97,32 @@ AlignedAllocRealloc(void *pointer, Size size, int flags)
9697
Assert(old_size >= redirchunk->requested_size);
9798
#endif
9899

100+
/*
101+
* To keep things simple, we always allocate a new aligned chunk and copy
102+
* data into it. Because of the above inaccuracy, this may end in copying
103+
* more data than was in the original allocation request size, but that
104+
* should be OK.
105+
*/
99106
ctx = GetMemoryChunkContext(unaligned);
100107
newptr = MemoryContextAllocAligned(ctx, size, alignto, flags);
101108

102-
/*
103-
* We may memcpy beyond the end of the original allocation request size,
104-
* so we must mark the entire allocation as defined.
105-
*/
106-
if (likely(newptr != NULL))
109+
/* Cope cleanly with OOM */
110+
if (unlikely(newptr == NULL))
107111
{
108-
VALGRIND_MAKE_MEM_DEFINED(pointer, old_size);
109-
memcpy(newptr, pointer, Min(size, old_size));
112+
VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
113+
return MemoryContextAllocationFailure(ctx, size, flags);
110114
}
115+
116+
/*
117+
* We may memcpy more than the original allocation request size, which
118+
* would result in trying to copy trailing bytes that the original
119+
* MemoryContextAllocAligned call marked NOACCESS. So we must mark the
120+
* entire old_size as defined. That's slightly annoying, but probably not
121+
* worth improving.
122+
*/
123+
VALGRIND_MAKE_MEM_DEFINED(pointer, old_size);
124+
memcpy(newptr, pointer, Min(size, old_size));
125+
111126
pfree(unaligned);
112127

113128
return newptr;

0 commit comments

Comments
 (0)