Opened 3 months ago
Last modified 3 months ago
#5793 new defect
Crash on Buffer of Empty array on PG17
Reported by: | pramsey | Owned by: | pramsey |
---|---|---|---|
Priority: | medium | Milestone: | PostGIS PostgreSQL |
Component: | postgis | Version: | 3.4.x |
Keywords: | pg17 | Cc: |
Description (last modified by )
create extension postgis; create table tab (shape geography); select st_buffer(st_collect(array_agg (tab.shape)::geometry[])::geography, 10.0) from tab;
Change History (12)
comment:1 by , 3 months ago
comment:2 by , 3 months ago
Does it only crash for pg17? Wondering if maybe something changed with array_agg function in PG17 or something with the transitioning of that.
comment:3 by , 3 months ago
Hmm this is interesting:
— this doesn't crash
select st_buffer(st_collect(array_agg(tab.shape::geometry))::geography, 10.0) from tab
Not sure why the order of casting should matter
comment:4 by , 3 months ago
Keywords: | pg17 added |
---|---|
Summary: | Crash on Buffer of Empty array → Crash on Buffer of Empty array on PG17 |
This does seem to be isolated to pg17. Just tested this on a pg16 instance with 3.5.0.
It does not crash.
comment:5 by , 3 months ago
Oh interesting. I have a stack trace and no postgis code is touched. Exercise for the reader: reconstruct this crash using only core functions.
* frame #0: 0x00000001053a945c postgres`find_base_rel(root=0x0000000000000000, relid=1) at relnode.c:419:38 frame #1: 0x00000001056c5d64 postgres`examine_variable(root=0x0000000000000000, node=0x000000011e8092c8, varRelid=0, vardata=0x000000016afc76f0) at selfuncs.c:5073:14 frame #2: 0x00000001056c8474 postgres`estimate_array_length(root=0x0000000000000000, arrayexpr=0x000000011e8092c8) at selfuncs.c:2164:3 frame #3: 0x000000010531cbec postgres`cost_qual_eval_walker(node=0x000000011e809dc8, context=0x000000016afc82e0) at costsize.c:4861:5 frame #4: 0x000000010529f46c postgres`expression_tree_walker_impl(node=0x000000011e809ff8, walker=(postgres`cost_qual_eval_walker at costsize.c:4681), context=0x000000016afc82e0) at nodeFuncs.c:2524:9 frame #5: 0x000000010529e404 postgres`expression_tree_walker_impl(node=0x000000011e80a048, walker=(postgres`cost_qual_eval_walker at costsize.c:4681), context=0x000000016afc82e0) at nodeFuncs.c:2193:9 frame #6: 0x000000010531cf84 postgres`cost_qual_eval_walker(node=0x000000011e80a048, context=0x000000016afc82e0) at costsize.c:4945:9 frame #7: 0x000000010529f46c postgres`expression_tree_walker_impl(node=0x000000011e80a098, walker=(postgres`cost_qual_eval_walker at costsize.c:4681), context=0x000000016afc82e0) at nodeFuncs.c:2524:9 frame #8: 0x000000010529e404 postgres`expression_tree_walker_impl(node=0x000000011e80a0e8, walker=(postgres`cost_qual_eval_walker at costsize.c:4681), context=0x000000016afc82e0) at nodeFuncs.c:2193:9 frame #9: 0x000000010531cf84 postgres`cost_qual_eval_walker(node=0x000000011e80a0e8, context=0x000000016afc82e0) at costsize.c:4945:9 frame #10: 0x0000000105315b18 postgres`cost_qual_eval(cost=0x000000016afc8378, quals=0x000000011e80b768, root=0x0000000000000000) at costsize.c:4655:3 frame #11: 0x000000010538fab0 postgres`inline_function(funcid=18459, result_type=18318, result_collid=0, input_collid=0, args=0x000000011e80a138, funcvariadic=false, func_tuple=0x00000001480ab478, context=0x000000016afca1b8) at clauses.c:4816:4 frame #12: 0x000000010538e59c postgres`simplify_function(funcid=18459, result_type=18318, result_typmod=-1, result_collid=0, input_collid=0, args_p=0x000000016afc89f0, funcvariadic=false, process_args=true, allow_non_const=true, context=0x000000016afca1b8) at clauses.c:4133:13 frame #13: 0x0000000105389fa4 postgres`eval_const_expressions_mutator(node=0x000000011e809788, context=0x000000016afca1b8) at clauses.c:2591:14 frame #14: 0x00000001052a1f94 postgres`expression_tree_mutator_impl(node=0x000000011e8097d8, mutator=(postgres`eval_const_expressions_mutator at clauses.c:2442), context=0x000000016afca1b8) at nodeFuncs.c:3459:5 frame #15: 0x000000010538c178 postgres`eval_const_expressions_mutator(node=0x000000011e8097d8, context=0x000000016afca1b8) at clauses.c:3711:9 frame #16: 0x00000001052a236c postgres`expression_tree_mutator_impl(node=0x000000011e809828, mutator=(postgres`eval_const_expressions_mutator at clauses.c:2442), context=0x000000016afca1b8) at nodeFuncs.c:3545:12 frame #17: 0x000000010538c178 postgres`eval_const_expressions_mutator(node=0x000000011e809828, context=0x000000016afca1b8) at clauses.c:3711:9 frame #18: 0x00000001053898bc postgres`eval_const_expressions(root=0x000000011e809918, node=0x000000011e809828) at clauses.c:2266:9 frame #19: 0x0000000105358664 postgres`preprocess_expression(root=0x000000011e809918, expr=0x000000011e809828, kind=1) at planner.c:1175:10 frame #20: 0x0000000105357388 postgres`subquery_planner(glob=0x000000012e016580, parse=0x000000012e016690, parent_root=0x0000000000000000, hasRecursion=false, tuple_fraction=0, setops=0x0000000000000000) at planner.c:842:3 frame #21: 0x000000010535635c postgres`standard_planner(parse=0x000000012e016690, query_string="select st_buffer(st_collect(array_agg (tab.shape)::geometry[])::geography, 10.0) from tab;", cursorOptions=2048, boundParams=0x0000000000000000) at planner.c:421:9 frame #22: 0x0000000105356078 postgres`planner(parse=0x000000012e016690, query_string="select st_buffer(st_collect(array_agg (tab.shape)::geometry[])::geography, 10.0) from tab;", cursorOptions=2048, boundParams=0x0000000000000000) at planner.c:282:12 frame #23: 0x00000001054fe95c postgres`pg_plan_query(querytree=0x000000012e016690, query_string="select st_buffer(st_collect(array_agg (tab.shape)::geometry[])::geography, 10.0) from tab;", cursorOptions=2048, boundParams=0x0000000000000000) at postgres.c:908:9 frame #24: 0x00000001054feb3c postgres`pg_plan_queries(querytrees=0x000000011e8098c8, query_string="select st_buffer(st_collect(array_agg (tab.shape)::geometry[])::geography, 10.0) from tab;", cursorOptions=2048, boundParams=0x0000000000000000) at postgres.c:1000:11 frame #25: 0x0000000105502684 postgres`exec_simple_query(query_string="select st_buffer(st_collect(array_agg (tab.shape)::geometry[])::geography, 10.0) from tab;") at postgres.c:1197:19 frame #26: 0x00000001055018f4 postgres`PostgresMain(dbname="pramsey", username="pramsey") at postgres.c:4767:7 frame #27: 0x00000001054f8fc0 postgres`BackendMain(startup_data="", startup_data_len=4) at backend_startup.c:105:2 frame #28: 0x00000001053d6974 postgres`postmaster_child_launch(child_type=B_BACKEND, startup_data="", startup_data_len=4, client_sock=0x000000016afcaab8) at launch_backend.c:277:3 frame #29: 0x00000001053de840 postgres`BackendStartup(client_sock=0x000000016afcaab8) at postmaster.c:3593:8 frame #30: 0x00000001053db48c postgres`ServerLoop at postmaster.c:1674:6 frame #31: 0x00000001053da358 postgres`PostmasterMain(argc=3, argv=0x00006000026e2d80) at postmaster.c:1372:11 frame #32: 0x000000010525ed00 postgres`main(argc=3, argv=0x00006000026e2d80) at main.c:197:3 frame #33: 0x000000018792b154 dyld`start + 2476
comment:6 by , 3 months ago
I haven't been able to crash it with built in types, but it looks like that area of code was changed about a year ago.
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=d40d827
comment:7 by , 3 months ago
Description: | modified (diff) |
---|
comment:8 by , 3 months ago
Ladles and jelly spoons, I give you a pure PgSQL reproduction:
CREATE TABLE n (i integer); CREATE OR REPLACE FUNCTION add(integer) RETURNS integer AS 'SELECT 2 * $1 + 4 * $1' LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE; SELECT add(array_length(array_agg(i)::numeric[],1)::integer) FROM n;
comment:9 by , 3 months ago
Milestone: | PostGIS 3.5.1 → PostGIS PostgreSQL |
---|
comment:10 by , 3 months ago
Milestone: | PostGIS PostgreSQL → PostGIS 3.5.1 |
---|
Actually, can get it down to this
CREATE TABLE n (i integer); CREATE OR REPLACE FUNCTION l2(numeric[]) RETURNS integer AS 'SELECT array_length($1,1) + array_length($1,1)' LANGUAGE 'sql' IMMUTABLE; SELECT l2(array_agg(i)::numeric[]) FROM n;
comment:11 by , 3 months ago
comment:12 by , 3 months ago
Milestone: | PostGIS 3.5.1 → PostGIS PostgreSQL |
---|
switching back to PostgreSQL, looks like they have a tentative fix as discussed here:
https://www.postgresql.org/message-id/Zwbri-LE-8OJEIlW%40nathan
and the culprit was this commit https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=9391f71
This is such a large collection of functions, it would stand to reason that a simpler version would still crash, but this doesn't, even though I think it's pushing the same stuff into the buffer call.