public inbox for pgsql-bugs@postgresql.org
help / color / mirror / Atom feedBUG #19482: Recursive QueueFKConstraintValidation() lacks stack depth check
2+ messages / 2 participants
[nested] [flat]
* BUG #19482: Recursive QueueFKConstraintValidation() lacks stack depth check
@ 2026-05-16 11:00 PG Bug reporting form <noreply@postgresql.org>
0 siblings, 1 reply; 2+ messages in thread
From: PG Bug reporting form @ 2026-05-16 11:00 UTC (permalink / raw)
To: pgsql-bugs@lists.postgresql.org; +Cc: exclusion@gmail.com
The following bug has been logged on the website:
Bug reference: 19482
Logged by: Alexander Lakhin
Email address: exclusion@gmail.com
PostgreSQL version: 18.4
Operating system: Ubuntu 24.04
Description:
The following script:
echo "
CREATE TABLE tp0 (a int, PRIMARY KEY (a)) PARTITION BY RANGE(a);
ALTER TABLE tp0 ADD CONSTRAINT fk FOREIGN KEY (a) REFERENCES tp0 NOT VALID;
" | psql
for ((i=1;i<=48000;i++)); do # may take 2-3 hours
echo "CREATE TABLE tp$i PARTITION OF tp$(( $i - 1 ))
FOR VALUES FROM ($i) TO (1000000) PARTITION BY RANGE (a);";
done | psql > psql.log
echo "
ALTER TABLE tp0 VALIDATE CONSTRAINT fk;
" | psql
leads to:
2026-05-16 12:35:43.258 EEST|law|regression|6a083a6f.34aa38|LOG: statement:
ALTER TABLE tp0 VALIDATE CONSTRAINT fk;
2026-05-16 12:35:56.104 EEST|||6a07f1d1.32a4c7|LOG: client backend (PID
3451448) was terminated by signal 11: Segmentation fault
2026-05-16 12:35:56.104 EEST|||6a07f1d1.32a4c7|DETAIL: Failed process was
running: ALTER TABLE tp0 VALIDATE CONSTRAINT fk;
Core was generated by `postgres: law regression 127.0.0.1(48420) ALTER TABLE
'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00005e57e8d06ae9 in hash_initial_lookup (hashp=0x5e580f378e10,
hashvalue=795799848, bucketptr=0x7ffe0c940090) at dynahash.c:1767
1767 bucket = calc_bucket(hctl, hashvalue);
(gdb) (gdb) (gdb) (gdb) #0 0x00005e57e8d06ae9 in hash_initial_lookup
(hashp=0x5e580f378e10, hashvalue=795799848, bucketptr=0x7ffe0c940090) at
dynahash.c:1767
#1 0x00005e57e8d0545c in hash_search_with_hash_value (hashp=0x5e580f378e10,
keyPtr=0x7ffe0c94010c, hashvalue=795799848, action=HASH_FIND, foundPtr=0x0)
at dynahash.c:1010
#2 0x00005e57e8d0538a in hash_search (hashp=0x5e580f378e10,
keyPtr=0x7ffe0c94010c, action=HASH_FIND, foundPtr=0x0) at dynahash.c:961
#3 0x00005e57e8a7c224 in GetPrivateRefCountEntry (buffer=125, do_move=true)
at bufmgr.c:381
#4 0x00005e57e8a8051a in PinBuffer (buf=0x762990250980, strategy=0x0) at
bufmgr.c:3085
...
#20 0x00005e57e8ce0a15 in CheckNNConstraintFetch (relation=0x762989504168)
at relcache.c:4619
#21 0x00005e57e8cd9b66 in RelationBuildTupleDesc (relation=0x762989504168)
at relcache.c:701
#22 0x00005e57e8cdaa23 in RelationBuildDesc (targetRelId=464701,
insertIt=true) at relcache.c:1204
#23 0x00005e57e8cdc5cb in RelationIdGetRelation (relationId=464701) at
relcache.c:2142
#24 0x00005e57e84d14d2 in relation_open (relationId=464701, lockmode=4) at
relation.c:58
#25 0x00005e57e85a16c8 in table_open (relationId=464701, lockmode=4) at
table.c:44
#26 0x00005e57e877c41b in QueueFKConstraintValidation
(wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x7629895039e8,
pkrelid=16385,
contuple=0x5e5850492148, lockmode=4) at tablecmds.c:13080
#27 0x00005e57e877c450 in QueueFKConstraintValidation
(wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x762989503268,
pkrelid=16385,
contuple=0x5e5850491c98, lockmode=4) at tablecmds.c:13086
#28 0x00005e57e877c450 in QueueFKConstraintValidation
(wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x762989502ae8,
pkrelid=16385,
contuple=0x5e58504917e8, lockmode=4) at tablecmds.c:13086
...
#37383 0x00005e57e877c450 in QueueFKConstraintValidation
(wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x76299dd9b218,
pkrelid=16385,
contuple=0x5e580f357b98, lockmode=4) at tablecmds.c:13086
#37384 0x00005e57e877c450 in QueueFKConstraintValidation
(wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x76299dd98358,
pkrelid=16385,
contuple=0x5e580f35d628, lockmode=4) at tablecmds.c:13086
#37385 0x00005e57e877c025 in ATExecValidateConstraint
(wqueue=0x7ffe0d13d128, rel=0x76299dd98358, constrName=0x5e580f3554d8 "fk",
recurse=true,
recursing=false, lockmode=4) at tablecmds.c:12966
#37386 0x00005e57e876acde in ATExecCmd (wqueue=0x7ffe0d13d128,
tab=0x5e580f354fc8, cmd=0x5e580f355488, lockmode=4, cur_pass=AT_PASS_MISC,
context=0x7ffe0d13d320) at tablecmds.c:5497
#37387 0x00005e57e876a347 in ATRewriteCatalogs (wqueue=0x7ffe0d13d128,
lockmode=4, context=0x7ffe0d13d320) at tablecmds.c:5334
#37388 0x00005e57e876968c in ATController (parsetree=0x5e580f32aa88,
rel=0x76299dd98358, cmds=0x5e580f32aa38, recurse=true, lockmode=4,
context=0x7ffe0d13d320)
at tablecmds.c:4889
#37389 0x00005e57e876929d in AlterTable (stmt=0x5e580f32aa88, lockmode=4,
context=0x7ffe0d13d320) at tablecmds.c:4544
#37390 0x00005e57e8ae8380 in ProcessUtilitySlow (pstate=0x5e580f354470,
pstmt=0x5e580f32ab38,
queryString=0x5e580f329f60 "ALTER TABLE tp0 VALIDATE CONSTRAINT fk;",
context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0,
dest=0x5e580f32aef8,
qc=0x7ffe0d13d980) at utility.c:1321
Reproduced on REL_18_STABLE, starting from b663b9436, and on master.
^ permalink raw reply [nested|flat] 2+ messages in thread
* Re: BUG #19482: Recursive QueueFKConstraintValidation() lacks stack depth check
@ 2026-05-17 14:44 Ayush Tiwari <ayushtiwari.slg01@gmail.com>
parent: PG Bug reporting form <noreply@postgresql.org>
0 siblings, 0 replies; 2+ messages in thread
From: Ayush Tiwari @ 2026-05-17 14:44 UTC (permalink / raw)
To: exclusion@gmail.com; pgsql-bugs@lists.postgresql.org
Hi,
On Sun, 17 May 2026 at 18:01, PG Bug reporting form <noreply@postgresql.org>
wrote:
> The following bug has been logged on the website:
>
> Bug reference: 19482
> Logged by: Alexander Lakhin
> Email address: exclusion@gmail.com
> PostgreSQL version: 18.4
> Operating system: Ubuntu 24.04
> Description:
>
> The following script:
> echo "
> CREATE TABLE tp0 (a int, PRIMARY KEY (a)) PARTITION BY RANGE(a);
> ALTER TABLE tp0 ADD CONSTRAINT fk FOREIGN KEY (a) REFERENCES tp0 NOT VALID;
> " | psql
>
> for ((i=1;i<=48000;i++)); do # may take 2-3 hours
> echo "CREATE TABLE tp$i PARTITION OF tp$(( $i - 1 ))
> FOR VALUES FROM ($i) TO (1000000) PARTITION BY RANGE (a);";
> done | psql > psql.log
>
> echo "
> ALTER TABLE tp0 VALIDATE CONSTRAINT fk;
> " | psql
>
> leads to:
> 2026-05-16 12:35:43.258 EEST|law|regression|6a083a6f.34aa38|LOG:
> statement:
> ALTER TABLE tp0 VALIDATE CONSTRAINT fk;
> 2026-05-16 12:35:56.104 EEST|||6a07f1d1.32a4c7|LOG: client backend (PID
> 3451448) was terminated by signal 11: Segmentation fault
> 2026-05-16 12:35:56.104 EEST|||6a07f1d1.32a4c7|DETAIL: Failed process was
> running: ALTER TABLE tp0 VALIDATE CONSTRAINT fk;
>
> Core was generated by `postgres: law regression 127.0.0.1(48420) ALTER
> TABLE
> '.
> Program terminated with signal SIGSEGV, Segmentation fault.
> #0 0x00005e57e8d06ae9 in hash_initial_lookup (hashp=0x5e580f378e10,
> hashvalue=795799848, bucketptr=0x7ffe0c940090) at dynahash.c:1767
> 1767 bucket = calc_bucket(hctl, hashvalue);
> (gdb) (gdb) (gdb) (gdb) #0 0x00005e57e8d06ae9 in hash_initial_lookup
> (hashp=0x5e580f378e10, hashvalue=795799848, bucketptr=0x7ffe0c940090) at
> dynahash.c:1767
> #1 0x00005e57e8d0545c in hash_search_with_hash_value
> (hashp=0x5e580f378e10,
> keyPtr=0x7ffe0c94010c, hashvalue=795799848, action=HASH_FIND, foundPtr=0x0)
> at dynahash.c:1010
> #2 0x00005e57e8d0538a in hash_search (hashp=0x5e580f378e10,
> keyPtr=0x7ffe0c94010c, action=HASH_FIND, foundPtr=0x0) at dynahash.c:961
> #3 0x00005e57e8a7c224 in GetPrivateRefCountEntry (buffer=125,
> do_move=true)
> at bufmgr.c:381
> #4 0x00005e57e8a8051a in PinBuffer (buf=0x762990250980, strategy=0x0) at
> bufmgr.c:3085
> ...
> #20 0x00005e57e8ce0a15 in CheckNNConstraintFetch (relation=0x762989504168)
> at relcache.c:4619
> #21 0x00005e57e8cd9b66 in RelationBuildTupleDesc (relation=0x762989504168)
> at relcache.c:701
> #22 0x00005e57e8cdaa23 in RelationBuildDesc (targetRelId=464701,
> insertIt=true) at relcache.c:1204
> #23 0x00005e57e8cdc5cb in RelationIdGetRelation (relationId=464701) at
> relcache.c:2142
> #24 0x00005e57e84d14d2 in relation_open (relationId=464701, lockmode=4) at
> relation.c:58
> #25 0x00005e57e85a16c8 in table_open (relationId=464701, lockmode=4) at
> table.c:44
> #26 0x00005e57e877c41b in QueueFKConstraintValidation
> (wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x7629895039e8,
> pkrelid=16385,
> contuple=0x5e5850492148, lockmode=4) at tablecmds.c:13080
> #27 0x00005e57e877c450 in QueueFKConstraintValidation
> (wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x762989503268,
> pkrelid=16385,
> contuple=0x5e5850491c98, lockmode=4) at tablecmds.c:13086
> #28 0x00005e57e877c450 in QueueFKConstraintValidation
> (wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x762989502ae8,
> pkrelid=16385,
> contuple=0x5e58504917e8, lockmode=4) at tablecmds.c:13086
> ...
> #37383 0x00005e57e877c450 in QueueFKConstraintValidation
> (wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x76299dd9b218,
> pkrelid=16385,
> contuple=0x5e580f357b98, lockmode=4) at tablecmds.c:13086
> #37384 0x00005e57e877c450 in QueueFKConstraintValidation
> (wqueue=0x7ffe0d13d128, conrel=0x76299e17b6d0, fkrel=0x76299dd98358,
> pkrelid=16385,
> contuple=0x5e580f35d628, lockmode=4) at tablecmds.c:13086
> #37385 0x00005e57e877c025 in ATExecValidateConstraint
> (wqueue=0x7ffe0d13d128, rel=0x76299dd98358, constrName=0x5e580f3554d8 "fk",
> recurse=true,
> recursing=false, lockmode=4) at tablecmds.c:12966
> #37386 0x00005e57e876acde in ATExecCmd (wqueue=0x7ffe0d13d128,
> tab=0x5e580f354fc8, cmd=0x5e580f355488, lockmode=4, cur_pass=AT_PASS_MISC,
> context=0x7ffe0d13d320) at tablecmds.c:5497
> #37387 0x00005e57e876a347 in ATRewriteCatalogs (wqueue=0x7ffe0d13d128,
> lockmode=4, context=0x7ffe0d13d320) at tablecmds.c:5334
> #37388 0x00005e57e876968c in ATController (parsetree=0x5e580f32aa88,
> rel=0x76299dd98358, cmds=0x5e580f32aa38, recurse=true, lockmode=4,
> context=0x7ffe0d13d320)
> at tablecmds.c:4889
> #37389 0x00005e57e876929d in AlterTable (stmt=0x5e580f32aa88, lockmode=4,
> context=0x7ffe0d13d320) at tablecmds.c:4544
> #37390 0x00005e57e8ae8380 in ProcessUtilitySlow (pstate=0x5e580f354470,
> pstmt=0x5e580f32ab38,
> queryString=0x5e580f329f60 "ALTER TABLE tp0 VALIDATE CONSTRAINT fk;",
> context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0,
> dest=0x5e580f32aef8,
> qc=0x7ffe0d13d980) at utility.c:1321
>
> Reproduced on REL_18_STABLE, starting from b663b9436, and on master.
>
>
Thanks for the report and the bisected commit.
QueueFKConstraintValidation() recurses through the partition hierarchy
without a stack-depth check, which is the usual reason for SIGSEGV
crashes like the one in your stack trace. Other recursive helpers in
tablecmds.c (and elsewhere in the backend) call check_stack_depth() at
function entry so that we raise a controlled "stack depth limit
exceeded" error instead.
The attached patch does the same here. With max_stack_depth reduced
to 100kB, a scaled-down repro (2000 nested partitions) reproduces the
crash on master and produces the following clean error with the patch:
ALTER TABLE tp0 VALIDATE CONSTRAINT fk;
ERROR: stack depth limit exceeded
HINT: Increase the configuration parameter "max_stack_depth"
(currently 100kB), ...
Thoughts?
Regards,
Ayush
Attachments:
[application/octet-stream] v1-0001-Add-stack-depth-check-to-QueueFKConstraintValidat.patch (1.7K, 3-v1-0001-Add-stack-depth-check-to-QueueFKConstraintValidat.patch)
download | inline diff:
From 99861c3a304dba9d8b9c1f1f2fc01b4f0360da55 Mon Sep 17 00:00:00 2001
From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Date: Sun, 17 May 2026 14:18:27 +0000
Subject: [PATCH v1] Add stack depth check to QueueFKConstraintValidation()
QueueFKConstraintValidation() recurses through the partition hierarchy
to queue child constraint validations and to mark child rows as
validated. On a sufficiently deep partition tree (the report uses
roughly 48000 nested levels), the recursion exhausts the process
stack and the backend crashes with SIGSEGV from deep inside the
catalog access path.
Other recursive helpers in tablecmds.c (and elsewhere in the backend)
follow the convention of calling check_stack_depth() at function
entry so that the process raises a controlled "stack depth limit
exceeded" error well before we run out of stack. Do the same here.
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/19482-4cc37cbf52d55235@postgresql.org
---
src/backend/commands/tablecmds.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 92b0f38c353..b15b3198ce1 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13275,6 +13275,12 @@ QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation fkrel,
HeapTuple copyTuple;
Form_pg_constraint copy_con;
+ /*
+ * This function recurses through the partition hierarchy, so guard
+ * against stack overflow on very deeply nested partition trees.
+ */
+ check_stack_depth();
+
con = (Form_pg_constraint) GETSTRUCT(contuple);
Assert(con->contype == CONSTRAINT_FOREIGN);
Assert(!con->convalidated);
--
2.43.0
^ permalink raw reply [nested|flat] 2+ messages in thread
end of thread, other threads:[~2026-05-17 14:44 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-05-16 11:00 BUG #19482: Recursive QueueFKConstraintValidation() lacks stack depth check PG Bug reporting form <noreply@postgresql.org>
2026-05-17 14:44 ` Ayush Tiwari <ayushtiwari.slg01@gmail.com>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox