| From: | Heikki Linnakangas <hlinnaka(at)iki(dot)fi> |
|---|---|
| To: | Rahila Syed <rahilasyed90(at)gmail(dot)com>, Konstantin Knizhnik <knizhnik(at)garret(dot)ru> |
| Cc: | PostgreSQL mailing lists <pgsql-bugs(at)lists(dot)postgresql(dot)org> |
| Subject: | Re: SIGSEGV in dynahash |
| Date: | 2026-08-25 11:14:45 |
| Message-ID: | e3ae5aa3-a051-4e07-9fac-c0a24c361e22@iki.fi |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
On 25/08/2026 07:30, Rahila Syed wrote:
>> On PG19, ShmemInitHash always builds a fixed-size shared hash with a bump allocator (ShmemHashAlloc) whose alloc_arg is a stack-local region used only during hash_create. After init, that pointer is dead.
>>
>> In hash_search, for every HASH_ENTER / HASH_ENTER_NULL, dynahash does this before lookup:
>>
>> dynahash.cLines 927-937
>> if (action == HASH_ENTER || action == HASH_ENTER_NULL)
>> {
>> if (hctl->freeList[0].nentries > (int64) hctl->max_bucket &&
>> !IS_PARTITIONED(hctl) && !hashp->frozen &&
>> !has_seq_scans(hashp))
>> (void) expand_table(hashp);
>> }
>>
>>
>> It may cause SIGSEGV in case of using HASH_ENTER_NULL:
>>
>>
>> hash_search(HASH_ENTER_NULL)
>> → expand_table → seg_alloc → SIGSEGV in libc (MemSet/alloc)
>
> The same thing cannot be triggered by
> hash_search_with_hash_value()->get_hash_entry()->element_alloc()
> because element_alloc()'s
> if (hctl->isfixed) return false; guard trips before ever touching the allocator.
>
> Similarly for dir_realloc() which has a check if
> (hashp->hctl->max_dsize != NO_MAX_DSIZE) return false.
> Since shared hash tables set a fixed max_dsize (not NO_MAX_DSIZE),
> dir_realloc() returns false immediately instead of growing the
> directory.
>
> This makes me think we should add a check for hctl->isfixed in
> seg_alloc() instead of before
> expand_table() like it is done in the proposed patch.
Hmm, yeah, I see what you mean, although I don't feel too bad about just
assuming that they're not called from elsewhere. I added an
Assert(!hashp->hctl->isfixed) in both seg_alloc() and dir_realloc(), to
document that you shouldn't get there for fixed-size hash tables.
Committed the fix with those extra Asserts. Thanks!
> It would also be valuable to add this SIGSEGV as a regression test. It
> can't be triggered through any of the existing shared hash tables,
> though — LOCK and PROCLOCK are the only fixed-size ones in core, and
> both are partitioned, which makes expand_table() unreachable for them
> (!IS_PARTITIONED(hctl) at dynahash.c:934/:1497). A dedicated
> non-partitioned, fixed-size test hash table would be needed.
All shmem hash tables are fixed-size. But you need one that has just the
right number of elements, is not partitioned, and you then need to fill
it up to trigger the bug.
I came up with the attached, but now that we've fixed the bug it doesn't
feel very interesting to test for exactly that, so I didn't feel it's
worth committing. Maybe as part of a larger unit test of various hash
table operations, but even then the requirement that the hash table is
just the right size to exercise this case feels fragile.
- Heikki
| Attachment | Content-Type | Size |
|---|---|---|
| test-fixed-hash-expand-bug.patch | text/x-patch | 4.2 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Zsolt Parragi | 2026-08-25 11:16:53 | Re: autovacuum: automatically propagate updated parameters |
| Previous Message | Fujii Masao | 2026-08-25 05:14:25 | Re: BUG #19629: pg_restore_relation_stats reports XX000 instead of proper SQLSTATE for input validation errors |