Skip to content

agtype: fix substring() backend crash when start-offset is SQL NULL and length is supplied#2401

Merged
MuhammadTahaNaveed merged 1 commit into
apache:masterfrom
SAY-5:fix/substring-null-start-crash-2386
Apr 20, 2026
Merged

agtype: fix substring() backend crash when start-offset is SQL NULL and length is supplied#2401
MuhammadTahaNaveed merged 1 commit into
apache:masterfrom
SAY-5:fix/substring-null-start-crash-2386

Conversation

@SAY-5
Copy link
Copy Markdown
Contributor

@SAY-5 SAY-5 commented Apr 20, 2026

Fixes #2386.

age_substring() reads the null map produced by extract_variadic_args() and rejects null offset/length with this guard:

if ((nargs == 2 && nulls[1]) ||
    (nargs == 3 && nulls[2]))
{
    ereport(ERROR, ..., errmsg("substring() offset or length cannot be null"));
}

The condition only checks nulls[1] in the 2-argument form. When the caller passes substring(str, null, len) the function takes nargs = 3, nulls[1] = true, but the guard above does not fire. Execution reaches the numeric-parameter loop below, which reads args[1] through DatumGetInt32 / DATUM_GET_AGTYPE_P without ever re-checking nulls[i]. The Datum in that slot is undefined, the dereference segfaults, and the PostgreSQL backend terminates — not a query error but a connection-level crash.

This widens the guard to nargs >= 2 && nulls[1] so it catches start-is-null in both the 2-arg and 3-arg forms. nulls[2] is still only checked when nargs == 3. No behaviour change on any non-null path; the connection-crash case is now reported as a normal query error, matching the intent the existing error message already implies.

…nd length is supplied

age_substring() reads the null map produced by extract_variadic_args()
and rejects null offset/length with this guard:

    if ((nargs == 2 && nulls[1]) ||
        (nargs == 3 && nulls[2]))
    {
        ereport(ERROR, ..., errmsg("substring() offset or length cannot be null"));
    }

The condition only checks nulls[1] in the 2-argument form. When the
caller passes `substring(str, null, len)` the function takes nargs = 3,
nulls[1] = true, but the guard above does not fire. Execution reaches
the numeric-parameter loop below, which reads args[1] through
DatumGetInt32 / DATUM_GET_AGTYPE_P without ever re-checking nulls[i].
The Datum in that slot is undefined, the dereference segfaults, and
the PostgreSQL backend terminates - not a query error but a
connection-level crash (apache#2386).

Widen the guard to nargs >= 2 && nulls[1] so it catches start-is-null
in both the 2-arg and 3-arg forms. nulls[2] is still only checked
when nargs == 3. No behaviour change on any non-null path; the
connection-crash case is now reported as a normal query error,
matching the intent the existing error message already implies.

Fixes apache#2386
@MuhammadTahaNaveed MuhammadTahaNaveed merged commit 6c40838 into apache:master Apr 20, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

substring() may crash Apache AGE when its start-offset argument is null.

2 participants