Skip to content

test(similarity): cover the empty-graph qsort null base (#1367) - #1476

Merged
DeusData merged 1 commit into
mainfrom
test/1367-empty-graph-regression
Aug 7, 2026
Merged

test(similarity): cover the empty-graph qsort null base (#1367)#1476
DeusData merged 1 commit into
mainfrom
test/1367-empty-graph-regression

Conversation

@DeusData

@DeusData DeusData commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Why

The production guard for #1367collect_fp_entries only sorting when count > 1 — is on main, but nothing exercises it. A fix without a test is a fix that can be silently undone, and this one is unusually easy to undo: removing the guard produces no visible symptom on most lanes.

What

A graph with zero Function/Method nodes, where the entry array is never allocated and the null base would otherwise reach qsort.

Where this test binds — the interesting part

I removed the guard again and measured, rather than assuming:

lane result without the guard
macOS 25 passed — Apple libc doesn't mark qsort nonnull, so there is no UB to observe
Linux ASan/UBSan (recovering) 25 passed — prints null pointer passed as argument 1, then continues
Linux UBSan (trapping, -fno-sanitize-recover) exit 1 — process aborts. This is the RED

With the guard restored, the trapping lane is 25 passed again.

So the assertions are the behavioural half (empty graph → rc 0, no SIMILAR_TO edges), and the UB half is caught by the trap-UBSan leg alone. That split is written into the test comment deliberately: without it, a future reader checks this on a recovering lane, sees green, and concludes the null-base guard is still in place when it is not — exactly the false-guard shape.

Verification

macOS simhash suite green (25 passed); make lint-ci clean. Both directions measured on ubuntu-arm64 as tabulated above.

The production guard for #1367 — collect_fp_entries only sorting when
count > 1 — is on main, but nothing exercises it. A fix without a test is a
fix that can be silently undone, and this one is unusually easy to undo:
removing the guard produces no visible symptom on most lanes.

Adds the missing case: a graph with zero Function/Method nodes, where the
entry array is never allocated and the null base would reach qsort.

The test comment records WHERE the test binds, because that turned out to be
the interesting part. Removing the guard again:

  macOS                          25 passed  (Apple libc does not mark qsort
                                             nonnull, so there is no UB to see)
  Linux ASan/UBSan, recovering   25 passed  (prints "null pointer passed as
                                             argument 1", then keeps going)
  Linux UBSan, trapping          exit 1     (process aborts — the RED)

So the assertions here are the behavioural half (empty graph → rc 0, no
SIMILAR_TO edges), and the UB half is caught by the trap-UBSan leg alone.
Both were measured on ubuntu-arm64 in each direction. Spelling that out in
the test keeps a future reader from checking it on a recovering lane, seeing
green, and concluding the null-base guard is still there when it is not.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
@DeusData
DeusData enabled auto-merge August 6, 2026 16:42
@DeusData
DeusData merged commit ab43e75 into main Aug 7, 2026
59 of 70 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.

1 participant