vividy163 opened a new pull request, #2488:
URL: https://github.com/apache/age/pull/2488
## Root cause
`agtype_access_operator` is declared `VARIADIC agtype[]`. Every other call
site in `cypher_expr.c` packs its arguments into a single `agtype[]`
`ArrayExpr` via `make_agtype_array_expr()` and sets `funcvariadic = true` on
the resulting `FuncExpr` (see `transform_cypher_map_projection`,
`transform_cypher_indirection`).
`transform_cypher_param()` — the path that turns a Cypher `$param` reference
into an AGE function call — was the only exception. It passed the bound Param
and the key-name Const directly as separate `FuncExpr` arguments without
wrapping them and without setting `funcvariadic`.
With the Simple Query protocol PostgreSQL implicitly assembles the variadic
array from separate arguments at execution time, which masked the bug. Under
the **Extended Query protocol (Parse/Bind/Execute prepared statements)** the
executor does not perform that implicit assembly, so `agtype_access_operator`
read past its single `agtype` argument and treated adjacent memory as
additional array elements. The resulting out-of-bounds read surfaced as
corrupted relation names in "relation does not exist" error responses (random
bytes mixed with fragments of in-flight query text / property values such as
"November", "customer", "communication", and control bytes like `0x01`).
Drivers that UTF-8 decode the server error then raised:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x9e in position 51:
invalid start byte
The bug reproduces with any Open/asyncpg/JDBC driver that uses prepared
statements with bound `agtype` parameters against a Cypher query that
references `$param` (for example `MERGE (n:base {entity_id: $entity_id})` or
`MATCH (s:base {id: $src_id}), (t:base {id: $tgt_id}) CREATE (s)-[r:DIRECTED
{…}]->(t)`, the shape used by LightRAG). The error content is unrelated to the
payload — edges with pure-ASCII property values failed identically.
## Fix
Pack the two arguments in `make_agtype_array_expr()` and set
`func_expr->funcvariadic = true`, exactly matching every other call site.
```c
newa = make_agtype_array_expr(args);
func_expr = makeFuncExpr(func_access_oid, AGTYPEOID, list_make1(newa),
InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
func_expr->funcvariadic = true;
Regression test
Added p_create_edge to regress/sql/cypher_create.sql, which PREPAREs a MATCH
… {id: $src_id}, … {id: $tgt_id} CREATE ()-[:e {id: $edge_id}]->() statement
(the exact shape used by LightRAG/asyncpg) and EXECUTEs it repeatedly. The
expected output file (regress/expected/cypher_create.out) needs to be
regenerated by running make installcheck against a built extension.
--
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]