Re: Autoprewarm workers terminated due to a segmentation fault

From: Melanie Plageman <melanieplageman(at)gmail(dot)com>
To: Tomas Vondra <tomas(at)vondra(dot)me>
Cc: Matheus Alcantara <matheusssilv97(at)gmail(dot)com>, Glauber Batista <glauberrbatista(at)gmail(dot)com>, pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: Autoprewarm workers terminated due to a segmentation fault
Date: 2026-06-15 14:35:43
Message-ID: CAAKRu_aekYazEexpT0KtjFaJOFD=Z=4Of8vwLrf+fsuJBSaBcg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

On Thu, Jun 11, 2026 at 10:40 AM Tomas Vondra <tomas(at)vondra(dot)me> wrote:
>
> After looking a bit closer, I think this bug was introduced by
>
> commit 6acab8bdbcda735ef47b1bb0ba2284d6c465cd88
> Author: Melanie Plageman <melanieplageman(at)gmail(dot)com>
> Date: Fri Apr 4 15:25:27 2025 -0400
>
> Refactor autoprewarm_database_main() in preparation for read stream
>
> which happens to advance to the next block in a couple places
>
> blk = block_info[++i];
>
> before we know it the incremented "i" is a valid element. The following
> commit (d9c7911e1a5f adding the read stream) ends up doing the same
> thing, except the index is incremented in a callback.
>
> Melanie, do you agree with the proposed fix?

Thanks all for investigating this! I agree that the proposed fix is
correct (both v1 and v2). I am a bit torn between the two versions.
v1:

i = p.pos;
if (i >= apw_state->prewarm_stop_idx)
break;
blk = block_info[i];

preserves what I had intended in that it sets blk as close to where i
was advanced as possible. I had wanted this behavior because we have
the "fast-forwarding" that happens in a few places in that loop, and I
was afraid it would get quite confusing. The other thing I wanted was
the invariant that blk is always the i'th block when exiting the loop.
This was in case future code restructured the outer loop and added
other break conditions and then used blk.

However, I do hate duplicating the loop bounds checking in two places.
And future code that restructures the control flow of this function is
going to have to be extremely careful anyway. The combination of
multiple nested loops, "fast-forwarding" behavior, and skipping
forward X number of blocks with the read stream made the requirements
of this function's control flow quite complex.

v2:

while (i < apw_state->prewarm_stop_idx)
{
ForkNumber forknum;
BlockNumber nblocks;
struct AutoPrewarmReadStreamData p;
ReadStream *stream;
Buffer buf;

blk = block_info[i];

/* Stop when we reach a different relation. */
if (blk.tablespace != tablespace ||
blk.filenumber != filenumber)
break;

has the advantage that we set blk directly before using it instead of
at the end of the previous iteration, which people may find less
confusing.

So, overall, I am fine with either approach. Whatever other hackers
find more clear is the right approach. In my attempt to make it clear,
I obviously made it incorrect -- which is far worse :)

- Melanie

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message Heikki Linnakangas 2026-06-15 15:08:05 Re: Fw:Re: Fw: ltree_compare in contrib/ltree/ltree_op.c overflows int32 on deep ltree comparisons, returning the wrong sign
Previous Message PG Bug reporting form 2026-06-15 13:39:54 BUG #19521: After a minor PostgreSQL update from 14.22 to 14.23, the database goes into an infinite loop.