Re: BUG #19491: Segmentation fault triggered by IS NULL

Ayush Tiwari <ayushtiwari.slg01@gmail.com>

From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
To: 798604270@qq.com, pgsql-bugs@lists.postgresql.org, Álvaro Herrera <alvherre@kurilemu.de>
Date: 2026-05-25T15:12:41Z
Lists: pgsql-bugs

Attachments

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

Commits

  1. IS JSON/JSON(): Protect against expressions uncoercible to text

  2. Reject degenerate SPLIT PARTITION with DEFAULT partition