Re: BUG #18830: ExecInitMerge Segfault on MERGE

From: Tender Wang <tndrwang(at)gmail(dot)com>
To: tharakan(at)gmail(dot)com, pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: BUG #18830: ExecInitMerge Segfault on MERGE
Date: 2025-03-03 15:46:11
Message-ID: CAHewXNmO1JxKwqHXw7L0LV7ef2Dkd+EOC2qs=3i3SKtFnm9_Ww@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

PG Bug reporting form <noreply(at)postgresql(dot)org> 于2025年3月3日周一 18:31写道:

> The following bug has been logged on the website:
>
> Bug reference: 18830
> Logged by: Robins Tharakan
> Email address: tharakan(at)gmail(dot)com
> PostgreSQL version: Unsupported/Unknown
> Operating system: Ubuntu
> Description:
>
> With this SQL (backtraces below), postgres starts to segfault starting at
> cbc127917e.
>
>
> SQL
> ===
> CREATE AGGREGATE d(double precision ORDER BY anyelement) (
> SFUNC = ordered_set_transition_multi,
> STYPE = internal,
> FINALFUNC = rank_final);
> CREATE TABLE e (
> a text,
> b integer
> ) PARTITION BY LIST (a);
> CREATE TABLE f (
> a text,
> b integer
> );
> CREATE TABLE g (
> a text,
> b integer
> );
> CREATE VIEW h AS
> SELECT XMLSERIALIZE(DOCUMENT '<foo><bar>42</bar></foo>'AS text );
> ALTER TABLE e ATTACH PARTITION f FOR VALUES IN ('a');
> ALTER TABLE e ATTACH PARTITION g FOR VALUES IN ('b');
>
> MERGE INTO e USING h ON a = xmlserialize WHEN NOT MATCHED THEN INSERT
> VALUES (CAST(NULL AS text));
>
>
> SQL Output
> ==========
> $ psql -p 9999 postgres -f ../sqith/repro_final.sql
> CREATE AGGREGATE
> CREATE TABLE
> CREATE TABLE
> CREATE TABLE
> CREATE VIEW
> ALTER TABLE
> ALTER TABLE
> psql:../sqith/repro_final.sql:25: server closed the connection
> unexpectedly
> This probably means the server terminated abnormally
> before or while processing the request.
> psql:../sqith/repro_final.sql:25: error: connection to server was lost
>
>
>
> Error Log
> =========
> 2025-03-03 06:55:54.014 ACDT [137463] LOG: client backend (PID 137479) was
> terminated by signal 11: Segmentation fault
> 2025-03-03 06:55:54.014 ACDT [137463] DETAIL: Failed process was running:
> MERGE INTO e USING h ON a = xmlserialize WHEN NOT MATCHED THEN INSERT
> VALUES (CAST(NULL AS text));
> 2025-03-03 06:55:54.014 ACDT [137463] LOG: terminating any other active
> server processes
>
>
> Commit
> ======
> Checking (15a79c73111~0) - 15a79c7311 - fail
> Checking (15a79c73111~10) - 424ededc58 - fail
> Checking (15a79c73111~30) - 945a9e3832 - fail
> Checking (15a79c73111~70) - a4e986ef5a - fail
> Checking (15a79c73111~150) - 6a2275b895 - fail
> Checking (15a79c73111~310) - 117f9f328e - Pass
> Checking (15a79c73111~230) - c89525d57b - Pass
> Checking (15a79c73111~190) - c366d2bdba - fail
> Checking (15a79c73111~210) - fb056564ec - fail
> Checking (15a79c73111~220) - 44ec095751 - Pass
> Checking (15a79c73111~215) - cbc127917e - fail
> Checking (15a79c73111~217) - 428fadb7e9 - Pass
> Checking (15a79c73111~216) - 926c7fce03 - Pass
> Offending Commit is cbc127917e - HEAD~215
>
>
> BackTrace
> =========
> (gdb) bt
> #0 ExecInitMerge (mtstate=0x599c6b260330, estate=0x599c6b260080) at
> nodeModifyTable.c:3663
> #1 0x0000599c2ca1ce11 in ExecInitModifyTable (node=0x599c6b282e08,
> estate=0x599c6b260080, eflags=0) at nodeModifyTable.c:4889
> #2 0x0000599c2c9d63a3 in ExecInitNode (node=0x599c6b282e08,
> estate=0x599c6b260080, eflags=0) at execProcnode.c:177
> #3 0x0000599c2c9cac66 in InitPlan (queryDesc=0x599c6b218ba0, eflags=0) at
> execMain.c:985
> #4 0x0000599c2c9c99f0 in standard_ExecutorStart (queryDesc=0x599c6b218ba0,
> eflags=0) at execMain.c:259
> #5 0x0000599c2c9c96fb in ExecutorStart (queryDesc=0x599c6b218ba0,
> eflags=0)
> at execMain.c:135
> #6 0x0000599c2ccb3925 in ProcessQuery (plan=0x599c6b284188,
> sourceText=0x599c6b16c4e0 "MERGE INTO e USING h ON a = xmlserialize
> WHEN NOT MATCHED THEN INSERT VALUES (CAST(NULL AS text));", params=0x0,
> queryEnv=0x0, dest=0x599c6b284308,
> qc=0x7ffc8bc1aaf0) at pquery.c:155
> #7 0x0000599c2ccb546e in PortalRunMulti (portal=0x599c6b1ef0a0,
> isTopLevel=true, setHoldSnapshot=false, dest=0x599c6b284308,
> altdest=0x599c6b284308, qc=0x7ffc8bc1aaf0)
> at pquery.c:1271
> #8 0x0000599c2ccb497a in PortalRun (portal=0x599c6b1ef0a0,
> count=9223372036854775807, isTopLevel=true, dest=0x599c6b284308,
> altdest=0x599c6b284308, qc=0x7ffc8bc1aaf0) at pquery.c:787
> #9 0x0000599c2ccad440 in exec_simple_query (query_string=0x599c6b16c4e0
> "MERGE INTO e USING h ON a = xmlserialize WHEN NOT MATCHED THEN INSERT
> VALUES (CAST(NULL AS text));")
> at postgres.c:1271
> #10 0x0000599c2ccb27ef in PostgresMain (dbname=0x599c6b1a6680
> "smithreduce",
> username=0x599c6b1a6668 "smith") at postgres.c:4691
>
>
>
> BackTrace Full
> ==============
> #0 ExecInitMerge (mtstate=0x599c6b260330, estate=0x599c6b260080) at
> nodeModifyTable.c:3663
> mergeActionList = 0x599c6b281b70
> joinCondition = 0x0
> relationDesc = 0x599c2c9df7cb <ExecTypeFromTL+33>
> l = 0x100000000
> lc__state = {l = 0x599c6b281bc0, i = 0}
> node = 0x599c6b282e08
> rootRelInfo = 0x599c6b260f98
> resultRelInfo = 0x599c6b260f80
> econtext = 0x599c6b2695f8
> lc = 0x599c6b281bd8
> i = 1
> __func__ = "ExecInitMerge"
> #1 0x0000599c2ca1ce11 in ExecInitModifyTable (node=0x599c6b282e08,
> estate=0x599c6b260080, eflags=0) at nodeModifyTable.c:4889
> mtstate = 0x599c6b260330
> subplan = 0x599c6b282d78
> operation = CMD_MERGE
> nrels = 0
> resultRelations = 0x0
> withCheckOptionLists = 0x0
> returningLists = 0x0
> updateColnosLists = 0x0
> resultRelInfo = 0x599c6b260f80
> arowmarks = 0x0
> l = 0x0
> i = 0
> rel = 0x7be2ba49e368
> __func__ = "ExecInitModifyTable"
> #2 0x0000599c2c9d63a3 in ExecInitNode (node=0x599c6b282e08,
> estate=0x599c6b260080, eflags=0) at execProcnode.c:177
> result = 0x0
> subps = 0x599c6b282760
> l = 0x599c6b2608c0
> __func__ = "ExecInitNode"
> #3 0x0000599c2c9cac66 in InitPlan (queryDesc=0x599c6b218ba0, eflags=0) at
> execMain.c:985
> operation = CMD_MERGE
> plannedstmt = 0x599c6b284188
> plan = 0x599c6b282e08
> rangeTable = 0x599c6b283228
> estate = 0x599c6b260080
> planstate = 0x599c6b1ab310
> tupType = 0x599c6b2011f0
> l = 0x0
> i = 1
> __func__ = "InitPlan"
>
>
> This (and bug #18828) found using SQLSmith / SQLReduce / creduce.
>
>
Thanks for reporting.
I can reproduce this crash. On HEAD 3f1db99bfa, crash on a different
place due to the commit 75dfde1.
But cbc127917e is the root cause commit.

MERGE INTO e USING h ON a = xmlserialize WHEN NOT MATCHED THEN INSERT
VALUES (CAST(NULL AS text));
The plan of the above query looks as below:
QUERY PLAN
------------------------------------------------------------------
Merge on e (cost=0.00..58.29 rows=0 width=0)
-> Nested Loop Left Join (cost=0.00..58.29 rows=12 width=10)
-> Result (cost=0.00..0.01 rows=1 width=0)
-> Append (cost=0.00..58.16 rows=12 width=10)
Subplans Removed: 2

You can see that all partitions are pruned. After cbc127917e, we only
consider unpruned relations, then the list resultRelations is empty.
the estate->es_unpruned_relids contains (1,2), the node->resultRelations
contains (5,6).

nrels = list_length(resultRelations);
...
mtstate->resultRelInfo = (ResultRelInfo *)
palloc(nrels * sizeof(ResultRelInfo));

The memory of mtstate->resultRelInfo point to is undefined. When we access
its memory in ExecInitMerge(),

relationDesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);

crash happened.

After 75dfde1, mergeActionLists list is empty, so in ExecInitMerge() we
don't enter the foreach(lc, mergeActionLists),
and the mtstate->ps.ps_ExprContext has no chance to initialize. So
in ExecMergeNotMatched(), econtext is NULL.
econtext->ecxt_scantuple = NULL;
The above statement can trigger a segment fault.

For Merge command NOT MATCH, should we need the logic that only consider
unpruned relations in ExecInitModifyTable()?

Merge command seems more complex than update and delete. Can we consider
the unpruned relations in ExecInitModifyTable()
according to the command type. For merge, we do the logic before
cbc127917e, for now?

--
Thanks,
Tender Wang

In response to

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Masahiko Sawada 2025-03-03 20:42:01 Re: BUG #18828: Crash when pg_get_logical_snapshot_meta() passed empty string
Previous Message Tom Lane 2025-03-03 15:22:31 Re: Query result differences between PostgreSQL 17 vs 16