Re: Reducing the chunk header sizes on all memory context types
Tom Lane <tgl@sss.pgh.pa.us>
Attachments
- harden-aset-some-more-1.patch (text/x-diff) patch
So I pushed that, but I don't feel that we're out of the woods yet.
As I mentioned at [1], while testing this stuff I hit a case where
aset.c will try to wipe_mem practically the entire address space after
being asked to pfree() an invalid pointer. The specific reproducer
isn't too interesting because it depends on the pre-80ef92675 state of
the code, but what I take away from this is that aset.c is still far
too fragile as it stands.
One problem is that aset.c generally isn't too careful about whether
a putative chunk is actually one of its chunks. That was okay before
c6e0fe1f2 because we would never get to AllocSetFree etc unless the
word before the chunk data pointed at a moderately-sane AllocSet.
Now, we can arrive at that code on the strength of three random bits,
so it's got to be more careful. In the attached patch, I make
AllocSetIsValid do an IsA() test, and make sure to apply it to the
aset we think we have found from the chunk header. This is not in
any way a new check: what it is doing is replacing the IsA check done
by the "AssertArg(MemoryContextIsValid(context))" that was performed
by GetMemoryChunkContext in the old code, and that we've completely
lost in the code as it stands.
The other problem, which is what is leading to wipe_mem-the-universe,
is that aset.c figures the size of a non-external chunk essentially
as "1 << MemoryChunkGetValue(chunk)", where the "value" field is 30
bits wide and has undergone exactly zero validation before
AllocSetFree uses the size in memset. That's far, far too trusting.
In the attached I put in some asserts to verify that the value field
is in the valid range for a freelist index, which should usually
trigger if we have a garbage value, or at the very least constrain
the damage.
What I am mainly wondering about at this point is whether Asserts
are good enough or we should use actual test-and-elog checks for
these things. The precedent of the old GetMemoryChunkContext
implementation suggests that assertions are good enough for the
AllocSetIsValid tests. On the other hand, there are existing
cross-checks like
if (block->freeptr != block->endptr)
elog(ERROR, "could not find block containing chunk %p", chunk);
so at least in some code paths we've thought it is worth expending
such tests in production builds. Any opinions?
I imagine generation.c and slab.c need similar bulletproofing
measures, but I didn't look at them yet.
regards, tom lane
[1] https://www.postgresql.org/message-id/3436789.1665187055%40sss.pgh.pa.us
Commits
-
Harden memory context allocators against bogus chunk pointers.
- 0e87dfe46443 16.0 landed
-
Improve our ability to detect bogus pointers passed to pfree et al.
- 80ef92675823 16.0 landed
-
Remove MemoryContextContains().
- 9543eff5e015 16.0 landed
-
Remove uses of MemoryContextContains in nodeAgg.c and nodeWindowAgg.c.
- 42b746d4c982 16.0 landed
-
Temporarily make MemoryContextContains return false
- b76fb6c2a99e 16.0 landed
-
Make MemoryContextContains work correctly again
- 5265e91fd10d 16.0 landed
-
Make more effort to put a sentinel at the end of allocated memory
- 0e480385ec59 16.0 landed
-
Fix some possibly latent bugs in slab.c
- 258b0411b243 10.23 landed
- 1b1154396798 11.18 landed
- f249f1026f71 12.13 landed
- 210bece161b0 13.9 landed
- 6ec896109254 14.6 landed
- c4e861b7bba3 15.0 landed
-
Various cleanups of the new memory context header code
- 05f908423695 16.0 landed
-
Revert "Add missing padding from MemoryChunk struct"
- 5495796ad12a 16.0 landed
-
Use MAXALIGN() in calculations using sizeof(SlabBlock)
- d5ee4db0eaf6 16.0 landed
-
Add missing padding from MemoryChunk struct
- df0f4feef8de 16.0 landed
-
Improve performance of and reduce overheads of memory management
- c6e0fe1f2a08 16.0 landed