Hi, While testing the current master with SQLsmith, I found a query that crashes the backend. After running the regression tests, the issue can be reproduced in the regression database with:
postgres=# \c regression You are now connected to database "regression" as user "ubuntu". regression=# SELECT expanded_record_info(2); 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. (gdb) bt #0 0x000062d8180991a3 in VARATT_IS_EXTERNAL (PTR=0x2) at ../../../../src/include/varatt.h:403 #1 0x000062d8180991c5 in VARATT_IS_EXTERNAL_EXPANDED_RW (PTR=0x2) at ../../../../src/include/varatt.h:436 #2 0x000062d81809a654 in DatumGetExpandedRecord (d=2) at expandedrecord.c:847 #3 0x000076332abce2b7 in expanded_record_info (fcinfo=0x62d845e6d230) at regress.c:475 #4 0x000062d817cce8ba in ExecInterpExpr (state=0x62d845e6cca0, econtext=0x62d845e6c480, isnull=0x7ffcbda7663f) at execExprInterp.c:987 #5 0x000062d817cd1502 in ExecInterpExprStillValid (state=0x62d845e6cca0, econtext=0x62d845e6c480, isNull=0x7ffcbda7663f) at execExprInterp.c:2309 #6 0x000062d817d3bae2 in ExecEvalExprSwitchContext (state=0x62d845e6cca0, econtext=0x62d845e6c480, isNull=0x7ffcbda7663f) at ../../../src/include/executor/executor.h:452 #7 0x000062d817d3bc33 in ExecQual (state=0x62d845e6cca0, econtext=0x62d845e6c480) at ../../../src/include/executor/executor.h:539 #8 0x000062d817d3c01b in ExecScanExtended (node=0x62d845e6c370, accessMtd=0x62d817d3c08a <SeqNext>, recheckMtd=0x62d817d3c16f <SeqRecheck>, The function has a polymorphic argument, so a scalar value such as an integer is accepted during function resolution. However, expanded_record_info() passes the argument directly to DatumGetExpandedRecord() through PG_GETARG_EXPANDED_RECORD(), assuming that it is a composite Datum. The integer value 2 is consequently treated as a pointer, causing an access at address 0x2 and crashing the backend. The same issue exists in expanded_record_identity() and expanded_record_field_text(), since they make the same assumption about their polymorphic arguments. The attached patch checks that the resolved argument type is a row type before converting the Datum. -- Thanks, Tender Wang
From 9130f943eec34b8f2df2fd287a991120b277f0ec Mon Sep 17 00:00:00 2001 From: Tender Wang <[email protected]> Date: Tue, 10 Nov 2026 09:59:40 +0800 Subject: [PATCH] Validate expanded record test function arguments The expanded-record regression test functions accept polymorphic arguments, allowing them to be called with scalar values. However, their C implementations passed such values directly to DatumGetExpandedRecord(), which treats the Datum as a pointer. For example, passing the integer 2 caused the backend to dereference address 0x2 and crash. Check that the resolved argument type is a row type before converting the Datum. Apply the check to expanded_record_identity(), expanded_record_info(), and expanded_record_field_text(), all of which have the same issue. --- src/test/regress/regress.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index 6e61c0d201b..9c65b723a8a 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -440,6 +440,17 @@ make_tuple_indirect(PG_FUNCTION_ARGS) PG_RETURN_POINTER(newtup->t_data); } +static ExpandedRecordHeader * +get_test_expanded_record(FunctionCallInfo fcinfo, int argno) +{ + Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, argno); + + if (!OidIsValid(argtype) || !type_is_rowtype(argtype)) + elog(ERROR, "argument must be of a composite type"); + + return DatumGetExpandedRecord(fcinfo->args[argno].value); +} + /* * Functions for testing expanded records built from a flat composite datum. * @@ -456,7 +467,7 @@ PG_FUNCTION_INFO_V1(expanded_record_identity); Datum expanded_record_identity(PG_FUNCTION_ARGS) { - ExpandedRecordHeader *erh = PG_GETARG_EXPANDED_RECORD(0); + ExpandedRecordHeader *erh = get_test_expanded_record(fcinfo, 0); PG_RETURN_EXPANDED_RECORD(erh); } @@ -472,7 +483,7 @@ PG_FUNCTION_INFO_V1(expanded_record_info); Datum expanded_record_info(PG_FUNCTION_ARGS) { - ExpandedRecordHeader *erh = PG_GETARG_EXPANDED_RECORD(0); + ExpandedRecordHeader *erh = get_test_expanded_record(fcinfo, 0); TupleDesc tupdesc = expanded_record_get_tupdesc(erh); PG_RETURN_TEXT_P(cstring_to_text(psprintf("type %s, typmod is default: %s, natts %d", @@ -489,7 +500,7 @@ PG_FUNCTION_INFO_V1(expanded_record_field_text); Datum expanded_record_field_text(PG_FUNCTION_ARGS) { - ExpandedRecordHeader *erh = PG_GETARG_EXPANDED_RECORD(0); + ExpandedRecordHeader *erh = get_test_expanded_record(fcinfo, 0); int fnum = PG_GETARG_INT32(1); TupleDesc tupdesc = expanded_record_get_tupdesc(erh); Datum val; -- 2.43.0
