Thread
Commits
-
IS JSON/JSON(): Protect against expressions uncoercible to text
- d0acd2535b4a 17 (unreleased) landed
- 7dd15325952f 19 (unreleased) landed
- 60abb3c73175 16 (unreleased) landed
- 35d9a6263407 18 (unreleased) landed
-
Reject degenerate SPLIT PARTITION with DEFAULT partition
- d8af73010033 19 (unreleased) cited
-
BUG #19491: Segmentation fault triggered by IS NULL
The Post Office <noreply@postgresql.org> — 2026-05-22T06:27:28Z
The following bug has been logged on the website: Bug reference: 19491 Logged by: Chi Zhang Email address: 798604270@qq.com PostgreSQL version: 18.4 Operating system: Ubuntu 24.04 Description: Hi, I found that the following test case triggers a segmentation fault. ``` CREATE SCHEMA IF NOT EXISTS poc; CREATE FUNCTION poc.mystring_in(cstring) RETURNS poc.mystring AS 'textin' LANGUAGE internal IMMUTABLE STRICT; CREATE FUNCTION poc.mystring_out(poc.mystring) RETURNS cstring AS 'textout' LANGUAGE internal IMMUTABLE STRICT; CREATE TYPE poc.mystring ( INPUT = poc.mystring_in, OUTPUT = poc.mystring_out, LIKE = text, CATEGORY = 'S' ); SELECT '{"a":1}'::poc.mystring IS JSON; DROP SCHEMA IF EXISTS poc CASCADE; ``` This is the output: ``` sqlancer=# CREATE SCHEMA IF NOT EXISTS poc; CREATE SCHEMA sqlancer=# CREATE FUNCTION poc.mystring_in(cstring) RETURNS poc.mystring AS 'textin' LANGUAGE internal IMMUTABLE STRICT; NOTICE: type "poc.mystring" is not yet defined DETAIL: Creating a shell type definition. CREATE FUNCTION sqlancer=# CREATE FUNCTION poc.mystring_out(poc.mystring) RETURNS cstring AS 'textout' LANGUAGE internal IMMUTABLE STRICT; NOTICE: argument type poc.mystring is only a shell LINE 1: CREATE FUNCTION poc.mystring_out(poc.mystring) ^ CREATE FUNCTION sqlancer=# CREATE TYPE poc.mystring ( INPUT = poc.mystring_in, OUTPUT = poc.mystring_out, LIKE = text, CATEGORY = 'S' ); CREATE TYPE sqlancer=# SELECT '{"a":1}'::poc.mystring IS JSON; server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. The connection to the server was lost. Attempting reset: Succeeded. ``` This is the log: ``` 2026-05-22 06:19:00.811 UTC [1] LOG: starting PostgreSQL 18.1 (Debian 18.1-1.pgdg13+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit 2026-05-22 06:19:00.811 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 2026-05-22 06:19:00.811 UTC [1] LOG: listening on IPv6 address "::", port 5432 2026-05-22 06:19:00.816 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" 2026-05-22 06:19:00.825 UTC [32] LOG: database system was shut down at 2026-05-22 06:18:54 UTC 2026-05-22 06:19:00.830 UTC [1] LOG: database system is ready to accept connections 2026-05-22 06:21:48.272 UTC [1] LOG: client backend (PID 42) was terminated by signal 11: Segmentation fault 2026-05-22 06:21:48.272 UTC [1] DETAIL: Failed process was running: SELECT '{"a":1}'::poc.mystring IS JSON; 2026-05-22 06:21:48.272 UTC [1] LOG: terminating any other active server processes 2026-05-22 06:21:48.273 UTC [1] LOG: all server processes terminated; reinitializing 2026-05-22 06:21:48.324 UTC [49] LOG: database system was interrupted; last known up at 2026-05-22 06:19:00 UTC 2026-05-22 06:21:48.428 UTC [49] LOG: database system was not properly shut down; automatic recovery in progress 2026-05-22 06:21:48.431 UTC [49] LOG: redo starts at 0/1C07F50 2026-05-22 06:21:48.432 UTC [49] LOG: invalid record length at 0/1C1AE88: expected at least 24, got 0 2026-05-22 06:21:48.432 UTC [49] LOG: redo done at 0/1C1AE00 system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s 2026-05-22 06:21:48.437 UTC [50] LOG: checkpoint starting: end-of-recovery immediate wait 2026-05-22 06:21:48.450 UTC [50] LOG: checkpoint complete: wrote 15 buffers (0.1%), wrote 3 SLRU buffers; 0 WAL file(s) added, 0 removed, 0 recycled; write=0.003 s, sync=0.004 s, total=0.016 s; sync files=16, longest=0.002 s, average=0.001 s; distance=75 kB, estimate=75 kB; lsn=0/1C1AE88, redo lsn=0/1C1AE88 2026-05-22 06:21:48.455 UTC [1] LOG: database system is ready to accept connections ``` I can reproduce this on the github commit d8af73010033cb8ad6c941942d6b03d74d7e4f7e -
Re: BUG #19491: Segmentation fault triggered by IS NULL
Ayush Tiwari <ayushtiwari.slg01@gmail.com> — 2026-05-25T15:12:41Z
Hi, On Mon, 25 May 2026 at 18:57, PG Bug reporting form <noreply@postgresql.org> wrote: > The following bug has been logged on the website: > > Bug reference: 19491 > Logged by: Chi Zhang > Email address: 798604270@qq.com > PostgreSQL version: 18.4 > Operating system: Ubuntu 24.04 > Description: > > Hi, > > I found that the following test case triggers a segmentation fault. > > ``` > CREATE SCHEMA IF NOT EXISTS poc; > > CREATE FUNCTION poc.mystring_in(cstring) > RETURNS poc.mystring > AS 'textin' LANGUAGE internal IMMUTABLE STRICT; > > CREATE FUNCTION poc.mystring_out(poc.mystring) > RETURNS cstring > AS 'textout' LANGUAGE internal IMMUTABLE STRICT; > > CREATE TYPE poc.mystring ( > INPUT = poc.mystring_in, > OUTPUT = poc.mystring_out, > LIKE = text, > CATEGORY = 'S' > ); > > SELECT '{"a":1}'::poc.mystring IS JSON; > > DROP SCHEMA IF EXISTS poc CASCADE; > ``` > > This is the output: > > ``` > sqlancer=# CREATE SCHEMA IF NOT EXISTS poc; > CREATE SCHEMA > sqlancer=# CREATE FUNCTION poc.mystring_in(cstring) > RETURNS poc.mystring > AS 'textin' LANGUAGE internal IMMUTABLE STRICT; > NOTICE: type "poc.mystring" is not yet defined > DETAIL: Creating a shell type definition. > CREATE FUNCTION > sqlancer=# CREATE FUNCTION poc.mystring_out(poc.mystring) > RETURNS cstring > AS 'textout' LANGUAGE internal IMMUTABLE STRICT; > NOTICE: argument type poc.mystring is only a shell > LINE 1: CREATE FUNCTION poc.mystring_out(poc.mystring) > ^ > CREATE FUNCTION > sqlancer=# CREATE TYPE poc.mystring ( > INPUT = poc.mystring_in, > OUTPUT = poc.mystring_out, > LIKE = text, > CATEGORY = 'S' > ); > CREATE TYPE > sqlancer=# SELECT '{"a":1}'::poc.mystring IS JSON; > server closed the connection unexpectedly > This probably means the server terminated abnormally > before or while processing the request. > The connection to the server was lost. Attempting reset: Succeeded. > ``` > Thanks for the report. I was able to reproduce this on HEAD with your SQL. The crash is in the executor while building expression state for the IS JSON predicate -- ExecInitExprRec() ends up being called with a NULL node: #0 ExecInitExprRec(node=0x0, ...) execExpr.c:966 #1 ExecInitExprRec(<JsonIsPredicate>) execExpr.c:2507 #2 ExecBuildProjectionInfo(...) execExpr.c:511 The NULL comes from transformJsonParseArg(). For UNKNOWN or string-category input types it implicitly coerces to text via coerce_to_target_type() and then sets exprtype to TEXTOID without checking if the coercion succeeded. poc.mystring is in CATEGORY = 'S' but has no implicit cast to text, so coerce_to_target_type() returns NULL; the parser still claims it's text and that NULL ends up as the JsonIsPredicate subject. String-category alone isn't a promise of text-coercibility -- adding CREATE CAST (poc.mystring AS text) ... AS IMPLICIT makes the same query works fine. I guess the parser just shouldn't assume the coercion worked? The smallest fix I could see is to only update expr / exprtype when coerce_to_target_type() returns non-NULL. Then transformJsonIsPredicate() (and the similar JSON() WITH UNIQUE KEYS path) raise their existing "cannot use type X" errors instead of crashing: ERROR: cannot use type poc.mystring in IS JSON predicate Attached is a small patch with that fix and a regression test in sqljson. Blame points at 6ee30209a6f1 (March 2023), so this looks like it goes back to v16. Regards, Ayush -
Re: BUG #19491: Segmentation fault triggered by IS NULL
Srinath Reddy Sadipiralla <srinath2133@gmail.com> — 2026-05-25T16:36:01Z
Hi, On Mon, May 25, 2026 at 8:43 PM Ayush Tiwari <ayushtiwari.slg01@gmail.com> wrote: > Hi, > > On Mon, 25 May 2026 at 18:57, PG Bug reporting form < > noreply@postgresql.org> wrote: > >> The following bug has been logged on the website: >> >> Bug reference: 19491 >> Logged by: Chi Zhang >> Email address: 798604270@qq.com >> PostgreSQL version: 18.4 >> Operating system: Ubuntu 24.04 >> Description: >> >> Hi, >> >> I found that the following test case triggers a segmentation fault. >> >> ``` >> CREATE SCHEMA IF NOT EXISTS poc; >> >> CREATE FUNCTION poc.mystring_in(cstring) >> RETURNS poc.mystring >> AS 'textin' LANGUAGE internal IMMUTABLE STRICT; >> >> CREATE FUNCTION poc.mystring_out(poc.mystring) >> RETURNS cstring >> AS 'textout' LANGUAGE internal IMMUTABLE STRICT; >> >> CREATE TYPE poc.mystring ( >> INPUT = poc.mystring_in, >> OUTPUT = poc.mystring_out, >> LIKE = text, >> CATEGORY = 'S' >> ); >> >> SELECT '{"a":1}'::poc.mystring IS JSON; >> >> DROP SCHEMA IF EXISTS poc CASCADE; >> ``` >> >> This is the output: >> >> ``` >> sqlancer=# CREATE SCHEMA IF NOT EXISTS poc; >> CREATE SCHEMA >> sqlancer=# CREATE FUNCTION poc.mystring_in(cstring) >> RETURNS poc.mystring >> AS 'textin' LANGUAGE internal IMMUTABLE STRICT; >> NOTICE: type "poc.mystring" is not yet defined >> DETAIL: Creating a shell type definition. >> CREATE FUNCTION >> sqlancer=# CREATE FUNCTION poc.mystring_out(poc.mystring) >> RETURNS cstring >> AS 'textout' LANGUAGE internal IMMUTABLE STRICT; >> NOTICE: argument type poc.mystring is only a shell >> LINE 1: CREATE FUNCTION poc.mystring_out(poc.mystring) >> ^ >> CREATE FUNCTION >> sqlancer=# CREATE TYPE poc.mystring ( >> INPUT = poc.mystring_in, >> OUTPUT = poc.mystring_out, >> LIKE = text, >> CATEGORY = 'S' >> ); >> CREATE TYPE >> sqlancer=# SELECT '{"a":1}'::poc.mystring IS JSON; >> server closed the connection unexpectedly >> This probably means the server terminated abnormally >> before or while processing the request. >> The connection to the server was lost. Attempting reset: Succeeded. >> ``` >> > > Thanks for the report. I was able to reproduce this on HEAD with your SQL. > The crash is in the executor while building expression state for the IS > JSON > predicate -- ExecInitExprRec() ends up being called with a NULL node: > > #0 ExecInitExprRec(node=0x0, ...) execExpr.c:966 > #1 ExecInitExprRec(<JsonIsPredicate>) execExpr.c:2507 > #2 ExecBuildProjectionInfo(...) execExpr.c:511 > > The NULL comes from transformJsonParseArg(). For UNKNOWN or > string-category > input types it implicitly coerces to text via coerce_to_target_type() and > then sets exprtype to TEXTOID without checking if the coercion succeeded. > poc.mystring is in CATEGORY = 'S' but has no implicit cast to text, so > coerce_to_target_type() returns NULL; the parser still claims it's text and > that NULL ends up as the JsonIsPredicate subject. > yeah , this was the reason. > > String-category alone isn't a promise of text-coercibility -- adding > CREATE CAST (poc.mystring AS text) ... AS IMPLICIT makes the same query > works fine. I guess the parser just shouldn't assume the coercion worked? > > The smallest fix I could see is to only update expr / exprtype when > coerce_to_target_type() returns non-NULL. Then transformJsonIsPredicate() > (and the similar JSON() WITH UNIQUE KEYS path) raise their existing > "cannot use type X" errors instead of crashing: > > ERROR: cannot use type poc.mystring in IS JSON predicate > I have reviewed the patch , i think the error message might be something like diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 89d0f348303..59e34f082e4 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -4203,6 +4203,13 @@ transformJsonParseArg(ParseState *pstate, Node *jsexpr, JsonFormat *format, TEXTOID, -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); + if(expr == NULL) + ereport(ERROR, + (errcode(ERRCODE_CANNOT_COERCE), + errmsg("cannot cast type %s to %s", + format_type_be(*exprtype), + format_type_be(TEXTOID)), + parser_errposition(pstate, exprLocation(raw_expr)))); *exprtype = TEXTOID; } -- Thanks, Srinath Reddy Sadipiralla EDB: https://www.enterprisedb.com/ -
Re: BUG #19491: Segmentation fault triggered by IS NULL
Ayush Tiwari <ayushtiwari.slg01@gmail.com> — 2026-06-05T16:11:34Z
Hi, On Mon, 25 May 2026 at 22:06, Srinath Reddy Sadipiralla < srinath2133@gmail.com> wrote: > Hi, > > I have reviewed the patch , i think the error message might be > something like > > diff --git a/src/backend/parser/parse_expr.c > b/src/backend/parser/parse_expr.c > index 89d0f348303..59e34f082e4 100644 > --- a/src/backend/parser/parse_expr.c > +++ b/src/backend/parser/parse_expr.c > @@ -4203,6 +4203,13 @@ transformJsonParseArg(ParseState *pstate, Node > *jsexpr, JsonFormat *format, > > TEXTOID, -1, > > COERCION_IMPLICIT, > > COERCE_IMPLICIT_CAST, -1); > + if(expr == NULL) > + ereport(ERROR, > + (errcode(ERRCODE_CANNOT_COERCE), > + errmsg("cannot cast type %s to %s", > + format_type_be(*exprtype), > + format_type_be(TEXTOID)), > + parser_errposition(pstate, > exprLocation(raw_expr)))); > *exprtype = TEXTOID; > } > Thanks, that reads better. v2 attached, raising ERRCODE_CANNOT_COERCE right where the coercion fails: ERROR: cannot cast type sqljson_mystr to text which also covers the JSON() WITH UNIQUE KEYS path. Regards, Ayush -
Re: BUG #19491: Segmentation fault triggered by IS NULL
Srinath Reddy Sadipiralla <srinath2133@gmail.com> — 2026-06-06T06:27:38Z
Hi, On Fri, Jun 5, 2026 at 9:41 PM Ayush Tiwari <ayushtiwari.slg01@gmail.com> wrote: > Hi, > > On Mon, 25 May 2026 at 22:06, Srinath Reddy Sadipiralla < > srinath2133@gmail.com> wrote: > >> Hi, >> >> I have reviewed the patch , i think the error message might be >> something like >> >> diff --git a/src/backend/parser/parse_expr.c >> b/src/backend/parser/parse_expr.c >> index 89d0f348303..59e34f082e4 100644 >> --- a/src/backend/parser/parse_expr.c >> +++ b/src/backend/parser/parse_expr.c >> @@ -4203,6 +4203,13 @@ transformJsonParseArg(ParseState *pstate, Node >> *jsexpr, JsonFormat *format, >> >> TEXTOID, -1, >> >> COERCION_IMPLICIT, >> >> COERCE_IMPLICIT_CAST, -1); >> + if(expr == NULL) >> + ereport(ERROR, >> + (errcode(ERRCODE_CANNOT_COERCE), >> + errmsg("cannot cast type %s to %s", >> + format_type_be(*exprtype), >> + format_type_be(TEXTOID)), >> + parser_errposition(pstate, >> exprLocation(raw_expr)))); >> *exprtype = TEXTOID; >> } >> > > Thanks, that reads better. v2 attached, raising ERRCODE_CANNOT_COERCE > right where the coercion fails: > > ERROR: cannot cast type sqljson_mystr to text > > which also covers the JSON() WITH UNIQUE KEYS path. > Thanks for the updated patch, LGTM. -- Thanks :) Srinath Reddy Sadipiralla EDB: https://www.enterprisedb.com/ -
Re: BUG #19491: Segmentation fault triggered by IS NULL
Álvaro Herrera <alvherre@kurilemu.de> — 2026-06-08T18:40:20Z
On 2026-Jun-06, Srinath Reddy Sadipiralla wrote: > > Thanks, that reads better. v2 attached, raising ERRCODE_CANNOT_COERCE > > right where the coercion fails: > > > > ERROR: cannot cast type sqljson_mystr to text > > > > which also covers the JSON() WITH UNIQUE KEYS path. > > Thanks for the updated patch, LGTM. Thanks -- will review, hoping to push soon. -- Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/ "That sort of implies that there are Emacs keystrokes which aren't obscure. I've been using it daily for 2 years now and have yet to discover any key sequence which makes any sense." (Paul Thomas)
-
Re: BUG #19491: Segmentation fault triggered by IS NULL
Álvaro Herrera <alvherre@kurilemu.de> — 2026-06-11T14:27:17Z
On 2026-Jun-06, Srinath Reddy Sadipiralla wrote: > On Fri, Jun 5, 2026 at 9:41 PM Ayush Tiwari <ayushtiwari.slg01@gmail.com> > wrote: > > Thanks, that reads better. v2 attached, raising ERRCODE_CANNOT_COERCE > > right where the coercion fails: > > > > ERROR: cannot cast type sqljson_mystr to text > > > > which also covers the JSON() WITH UNIQUE KEYS path. > > Thanks for the updated patch, LGTM. Thank you, I have pushed this to all branches since 16. I also added an Assert() to makeJsonIsPredicate() that 'expr' is not null. This wouldn't have caught this problem, mind, because what was really missing is an example case where the problem appears. However, it seems good manners to disallow that case explicitly rather than have it return a Expr node with a embedded null pointer that's only going to cause indirect problems. BTW the subject of this thread is somehow comically bogus. The problem is IS JSON causing a NULL pointer dereference, not IS NULL. -- Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/