Why our Valgrind reports suck
Tom Lane <tgl@sss.pgh.pa.us>
A nearby thread [1] reminded me to wonder why we seem to have
so many false-positive leaks reported by Valgrind these days.
For example, at exit of a backend that's executed a couple of
trivial queries, I see
==00:00:00:25.515 260013== LEAK SUMMARY:
==00:00:00:25.515 260013== definitely lost: 3,038 bytes in 90 blocks
==00:00:00:25.515 260013== indirectly lost: 4,431 bytes in 61 blocks
==00:00:00:25.515 260013== possibly lost: 390,242 bytes in 852 blocks
==00:00:00:25.515 260013== still reachable: 579,139 bytes in 1,457 blocks
==00:00:00:25.515 260013== suppressed: 0 bytes in 0 blocks
so about a thousand "leaked" blocks, all but a couple of which
are false positives --- including nearly all the "definitely"
leaked ones.
Some testing and reading of the Valgrind manual [2] turned up a
number of answers, which mostly boil down to us using very
Valgrind-unfriendly data structures. Per [2],
There are two ways a block can be reached. The first is with a
"start-pointer", i.e. a pointer to the start of the block. The
second is with an "interior-pointer", i.e. a pointer to the middle
of the block.
[ A block is reported as "possibly lost" if ] a chain of one or
more pointers to the block has been found, but at least one of the
pointers is an interior-pointer.
We have a number of places that allocate space in such a way that
blocks can only be reached by "interior pointers", leading to
those blocks being reported as possibly lost:
* MemoryContextAllocAligned does this more or less by definition.
* Dynahash tables often end up looking like this, since the first
element in each block created by element_alloc will be the tail end of
its freelist, and thus will be reachable only via interior pointers
later in the block, except when it's currently allocated.
* Blocks that are reached via slists or dlists are like this
unless the slist_node or dlist_node is at the front, which is not
our typical practice.
(There may be more cases, but those are what I identified in the
leak report quoted above.)
Another odd thing, which I have not found the explanation for, is
that strings made by MemoryContextCopyAndSetIdentifier() show up
as "definitely lost". This is nonsense, because they are surely
referenced by the context's "ident" field; but apparently Valgrind
isn't counting that for some reason.
I'd be okay with using a suppression pattern to hide the
MemoryContextCopyAndSetIdentifier cases, but that doesn't seem
like a very palatable answer for these other cases: too much
risk of hiding actual leaks.
I don't see a way to avoid the problem for MemoryContextAllocAligned
with the current context-type-agnostic implementation of that. We
could probably fix it though if we pushed it down a layer, so that the
alignment padding space could be treated as part of the chunk header.
Might be able to waste less space that way, too.
Dynahash tables could be fixed by expending a little extra storage
to chain all the element-pool blocks together explicitly, which
seems probably acceptable to do in USE_VALGRIND builds. (Maybe
while we are at that, we could fix things so that currently-unused
element slots are marked NOACCESS.)
I don't have an answer for slist/dlist usages other than rearranging
all the related structs. Anybody see a better way?
Or we could do nothing, but I think there is value in having
less clutter in Valgrind reports. Thoughts?
regards, tom lane
[1] https://www.postgresql.org/message-id/flat/CAA9OW9e4RbpgQd8NSzpW6BgJQNpKGEFoohWhkbEL8%3DZ5obvD0Q%40mail.gmail.com
[2] https://valgrind.org/docs/manual/mc-manual.html#mc-manual.leaks
Commits
-
Undo thinko in commit e78d1d6d4.
- 9d141466ff08 19 (unreleased) landed
-
Avoid leakage of zero-length arrays in partition_bounds_copy().
- 4fbfdde58e4c 19 (unreleased) landed
-
Fix MemoryContextAllocAligned's interaction with Valgrind.
- 9e9190154ef2 19 (unreleased) landed
-
Fix assorted pretty-trivial memory leaks in the backend.
- e78d1d6d47dc 19 (unreleased) landed
-
Improve our support for Valgrind's leak tracking.
- bb049a79d344 19 (unreleased) landed
-
Reduce leakage during PL/pgSQL function compilation.
- 9f18fa999562 19 (unreleased) landed
-
Silence Valgrind leakage complaints in more-or-less-hackish ways.
- db01c90b2f02 19 (unreleased) landed
-
Silence complaints about leaks in PlanCacheComputeResultDesc.
- b102c8c4733c 19 (unreleased) landed
-
Suppress complaints about leaks in TS dictionary loading.
- 7f6ededa764b 19 (unreleased) landed
-
Suppress complaints about leaks in function cache loading.
- 2c7b4ad24dda 19 (unreleased) landed
-
Fix per-relation memory leakage in autovacuum.
- e087b5b79452 16.10 landed
- 13d21b48a3a4 15.14 landed
- cd3064f9898c 17.6 landed
- 02502c1bca54 18.0 landed
-
Fix AlignedAllocRealloc to cope sanely with OOM.
- ac3afd1d0079 17.6 landed
- 6aa33afe6da1 18.0 landed