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:
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.