Re: BUG #17406: Segmentation fault on GiST index after 14.2 upgrade

From: Tomas Vondra <tomas(dot)vondra(at)enterprisedb(dot)com>
To: Peter Geoghegan <pg(at)bowt(dot)ie>
Cc: Victor Yegorov <vyegorov(at)gmail(dot)com>, PostgreSQL mailing lists <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: BUG #17406: Segmentation fault on GiST index after 14.2 upgrade
Date: 2022-02-17 16:29:37
Message-ID: 78098996-ca5e-a2ce-ae33-68ec8648ccc7@enterprisedb.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

On 2/17/22 13:26, Tomas Vondra wrote:
> On 2/17/22 03:52, Peter Geoghegan wrote:
>> On Wed, Feb 16, 2022 at 4:16 PM Tomas Vondra
>> <tomas(dot)vondra(at)enterprisedb(dot)com> wrote:
>>> test=# SELECT * FROM gist_page_items(get_raw_page('path_gist_idx', 0),
>>> 'path_gist_idx');
>>
>> Maybe this is obvious, but just in case: gist_page_items is *very*
>> trusting here. It's necessary to use gist_page_items_bytea() if you're
>> not 100% sure about the index definition for the index page you
>> provide. The fact that you can display the contents of each tuple
>> using the underlying type's own output function is very handy. But
>> potentially hazardous.
>>
>
> Sure, but I used this to inspect the index from example in our docs:
>
>   https://www.postgresql.org/docs/14/ltree.html#id-1.11.7.30.8
>
> I doubt we can be even more sure about the index definition.
>
>
> I don't know what the root cause is yet, but the memory corruption
> happens simply because ltree_out() sees entirely bogus data when
> executed from gist_page_items.
>
> For example it gets 16B varlena, allocates 16B string for it, and starts
> iterating over the ltree data. The it finds the first element is 60B
> long and happily copies it "into" the 16B buffer. That can't end well,
> obviously.
>
> Clearly, the ltree values are mangled somehow / somewhere. The funny
> thing is the bytea always looks 8B longer and with bogus data. So for
> example if you select this ltree from the table directly
>
>   Top.Collections.Pictures.Astronomy.Astronauts
>
> then ltree_out sees it as 80B varlena, with 5 levels. But if ltree_out
> gets called from gist_page_items, then it sees 88B with 1 level, which
> is completely bogus.
>
> And funnily enough, if you do this at the beginning of ltree_out:
>
>   in = (ltree *) ((char *) in + 8);
>
> then gist_page_items() starts working just fine.
>
> So, I guess gist_page_items() is broken/confused in some way. I'm not
> sure if this is related to the crash reported by Victor or a separate,
> independent issue.
>

I may be wrong, but it seems gist_page_items() is entirely oblivious to
the fact that GiST does "compression", and fails to decompress the
values before passing them to out function. So instead of "ltree" it
extracts "ltree_gist" and passes that to "ltree_out".

This is consistent with the 8B offset I mentioned before, because
ltree_gist has 8B header and then stores the original ltree value.

But I may be missing something - this seems like such an obvious gap
that I don't know how this could have worked with anything but the most
trivial cases without GiST compression.

Furthermore, it seems more like a pageinspect issue, unrelated to the
original issue reported by Victor.

regards

--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message Tomas Vondra 2022-02-17 16:35:00 Re: BUG #17406: Segmentation fault on GiST index after 14.2 upgrade
Previous Message Tomas Vondra 2022-02-17 12:26:30 Re: BUG #17406: Segmentation fault on GiST index after 14.2 upgrade