hkjiang26 opened a new issue, #2563:
URL: https://github.com/apache/age/issues/2563
**AGE Version:** apache/age master @ cfd3b634 (2026-08-14), extension 1.8.0,
on PostgreSQL 18.6
**Installation Method:** Docker
**API:** SQL (psql)
### Steps to reproduce
1. On a fresh database, run (no data required):
```sql
LOAD 'age';
SET search_path = ag_catalog, public;
SELECT ag_catalog.age_tobooleanlist('[true]');
```
All four `age_to*list` functions crash deterministically on array-shaped
literal arguments (12 shapes verified):
| Statement | Result |
|---|---|
| `age_tobooleanlist('[true]')`, `('[null]')`, `('[true, null, false]')` |
SIGSEGV |
| `age_tofloatlist('[true]')`, `('[1]')`, `('[null]')` | SIGSEGV |
| `age_tointegerlist('[true]')`, `('[null]')` | SIGSEGV |
| `age_tostringlist('[true]')`, `('[null]')`, `('[1, null, "a"]')` | SIGSEGV
|
Other array shapes (`'[1]'`, `'["a"]'`, `'[1.5]'` for the mismatched
functions) give a bogus `ERROR: toBooleanList() argument must resolve to a list
or null` instead — same root cause, non-crashing bit pattern.
### Expected behavior
The Cypher equivalents work correctly and define the expected behavior:
```sql
SELECT * FROM cypher('g', $$ RETURN toBooleanList([true]) $$) AS (r agtype);
-- r = [true]
```
The SQL form should either return the same result or raise a clean error; it
must never crash the backend.
### Actual behavior
```
psql: server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
psql: error: connection to server was lost
```
Server log (docker logs):
```
LOG: client backend (PID 14030) was terminated by signal 11: Segmentation
fault
LOG: all server processes terminated; reinitializing
```
Root cause (in `src/backend/utils/adt/agtype.c`): type confusion at the SQL
boundary. For `VARIADIC "any"` functions, PostgreSQL resolves an unknown-type
literal to `text` (verified with the same-signature builtin
`json_build_array('[true]')` → `["[true]"]`), i.e. the function receives a
`text[]` (ArrayType) datum, not agtype. The C functions read the argument with
`AG_GET_ARG_AGTYPE_P(0)` without ever checking `get_fn_expr_argtype()`, so the
`text[]` datum is reinterpreted as an agtype container. Depending on the
literal's byte pattern the garbage either passes the `AGT_ROOT_IS_ARRAY` root
check and crashes while iterating elements (the 12 shapes above), or fails it
and produces the bogus `argument must resolve to a list or null` error
(`'[1]'`, `'["a"]'`, `'[1.5]'`). Passing an explicit `::agtype` cast works
correctly — `age_tobooleanlist('[true]'::agtype)` returns `[true]` — and the
explicit `VARIADIC ARRAY[...]` form hits the same reinterpretation. `EXPLAIN
(VERBOSE)` of
a crashing call also crashes the backend.
Cypher is safe: literal lists are built through `agtype_build_list` (null
elements get real value slots) and the transform passes a typed agtype
expression, so the C code never sees a text[]; the PREPARE/EXECUTE parameter
path was verified safe as well. Trigger surface = AGE's public SQL API
(shared-instance DoS, same class as the `?` crash).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]