BUG #19491: Segmentation fault triggered by IS NULL
BUG #19491: Segmentation fault triggered by IS NULL
От:
PG Bug reporting form <noreply@postgresql.org>
Дата:
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
От:
Álvaro Herrera <alvherre@kurilemu.de>
Дата:
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>
Дата:
On 2026-Aug-04, ZhangChi wrote:
> Thanks all for fixing this issue and making pg better. Since this
> issue can reliably crash the PostgreSQL server, I would like to ask
> whether it should be treated as a security vulnerability and whether
> it is eligible for CVE assignment.
Hello,
Server crashes ("denial of service") requiring an authenticated user are
not, by themselves, considered security vulnerabilities. See "What is a
Security Vulnerability in PostgreSQL?" here:
https://www.postgresql.org/support/security/
Thanks
--
Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
"People get annoyed when you try to debug them." (Larry Wall)
Re: BUG #19491: Segmentation fault triggered by IS NULL
От:
Srinath Reddy Sadipiralla <srinath2133@gmail.com>
Дата:
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 textwhich also covers the JSON() WITH UNIQUE KEYS path.
Thanks for the updated patch, LGTM.
Re: BUG #19491: Segmentation fault triggered by IS NULL
От:
Srinath Reddy Sadipiralla <srinath2133@gmail.com>
Дата:
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;
}
Re: BUG #19491: Segmentation fault triggered by IS NULL
От:
Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Дата:
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
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
От:
"ZhangChi" <798604270@qq.com>
Дата:
Thanks all for fixing this issue and making pg better. Since this issue can reliably crash the PostgreSQL server, I would like to ask whether it should be treated as a security vulnerability and whether it is eligible for CVE assignment.
Original
From: Álvaro Herrera <alvherre@kurilemu.de> Date: 2026-06-11 22:27 To: Srinath Reddy Sadipiralla <srinath2133@gmail.com> Cc: Ayush Tiwari <ayushtiwari.slg01@gmail.com>, 798604270 <798604270@qq.com>, pgsql-bugs <pgsql-bugs@lists.postgresql.org> Subject: Re: BUG #19491: Segmentation fault triggered by IS NULL |
> 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/