Skip to content

read the error after the call that sets it - #3

Merged
tamnd merged 1 commit into
mainfrom
error-slot
Aug 22, 2026
Merged

tamnd merged 1 commit into
mainfrom
error-slot

Conversation

@tamnd

@tamnd tamnd commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Every fallible call in the header reads

checked(zu_something(..., &err), err, "zu_something")

and the order a compiler evaluates those two arguments in is unspecified. On one that reads err first, it reads it before the call beside it has run, which is to say it reads the null it was initialised to. Everything went on throwing and everything thrown was empty: the right status, no code, no condition, no position, and the name of the C function where the engine's sentence should have been. GCC picks that order. Clang picks the other one, which is why a header that has never been anything but wrong here has looked fine.

Through the wrapper, before this:

threw [MATCH (p:Person RETURN p] what=zu_query status=3 code=(none) message=zu_query

and through the C ABI with the same library, at the same moment:

status=3 err=yes  42001: line 1, column 17: ...

The fix is not to hoist the call into a variable at forty three call sites, because that leaves the mistake available to the forty fourth. checked takes the slot by address now. What may be evaluated early is then where err lives rather than what it holds, and what it holds is read inside the call, after the call that fills it has certainly returned. It also clears the slot, so a caller who looks afterwards finds nothing to free twice.

test_errors already had a case for this and was failing on it. It has one more now that says the whole sentence: a statement that does not parse carries a five character code, a position, a severity and a message that is not the name of the C function. The case above it allows a missing position, because a variable that is not defined has no token to point at, and an allowance is how this got through.

Measured on Linux with gcc 13 against libzu at the engine's HEAD: test_errors and test_errors_cxx20 go from 7 of 11 to 11 of 12, and test_statement goes green.

The failures left over are the engine having moved to ABI 0.14 and having reserved two more words, and they are the next PR.

Every fallible call in the header reads

  checked(zu_something(..., &err), err, "zu_something")

and the order a compiler evaluates those two arguments in is
unspecified. On one that reads err first, it reads it before the call
beside it has run, which is to say it reads the null it was
initialised to. Everything went on throwing and everything thrown was
empty: the right status, no code, no condition, no position, and the
name of the C function where the engine's sentence should have been.
GCC picks that order. Clang picks the other one, which is why a header
that has never been anything but wrong here has looked fine.

The fix is not to hoist the call into a variable at forty three call
sites, because that leaves the mistake available to the forty fourth.
checked takes the slot by address now. What may be evaluated early is
then where err lives rather than what it holds, and what it holds is
read inside the call, after the call that fills it has certainly
returned. It also clears the slot, so a caller who looks afterwards
finds nothing to free twice.

test_errors already had a case for this and was failing on it. It has
one more now that says the whole sentence: a statement that does not
parse carries a five character code, a position, a severity and a
message that is not the name of the C function. The case above it
allows a missing position, because a variable that is not defined has
no token to point at, and an allowance is how this got through.

The other failures on this branch are the engine having moved to ABI
0.14 and having reserved two more words, and are the next commit.
@tamnd
tamnd merged commit 8ec1bdc into main Aug 22, 2026
1 of 5 checks passed
@tamnd
tamnd deleted the error-slot branch August 22, 2026 13:13
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.

1 participant