Skip to content

fix(ci): stop check-threading-doc aborting on bash 3.2 when a citation misses - #1325

Merged
justinjoy merged 1 commit into
mainfrom
fix/1320-bash32-empty-array
Sep 3, 2026
Merged

fix(ci): stop check-threading-doc aborting on bash 3.2 when a citation misses#1325
justinjoy merged 1 commit into
mainfrom
fix/1320-bash32-empty-array

Conversation

@justinjoy

Copy link
Copy Markdown
Collaborator

Closes #1320. Based on main — independent of the other open PRs.

The bug

resolve_reference_source iterated "${candidates[@]}" without checking the array was
non-empty. On bash 3.2 that is an unbound-variable error under set -u; bash 4.4 changed it.
So a prose citation naming a file that does not exist under wirelog/ killed the checker
with

check-threading-doc.sh: line 65: candidates[@]: unbound variable

instead of letting the caller report which citation failed to resolve.

It cannot cause a false pass — the path is only reachable when the run was going to fail
anyway. It replaces the diagnostic with one naming an internal array.

threading_doc and threading_doc_selftest are registered in suite abi with no platform
gate; ci-pr.yml runs bare meson test on macos-latest in two jobs; those runners ship
bash 3.2.57.

Verified against real bash 3.2.57, not by reasoning

I built GNU bash 3.2 from the tarball with all 57 official patches — 3.2.57(4)-release, the
version macOS ships — and ran everything against it.

unfixed checker + self-test, bash 3.2.57  → exit 1, "candidates[@]: unbound variable"
fixed   checker + self-test, bash 3.2.57  → exit 0
fixed   checker + self-test, bash 5.3     → exit 0

Caveat worth recording for anyone repeating this: unpatched bash 3.2.0 additionally
rejects this repository's inline [[ x =~ ^([0-9]+)-([0-9]+)$ ]] as a syntax error, which
3.2.57 accepts. I initially concluded from a 3.2.0 build that the checker did not parse
on macOS at all — that was an artifact of the unpatched build, not a real CI failure. 3.2.0
is not a faithful proxy for the runner.

The change

check-threading-doc.sh — guard both empty-array iterations. The candidates loop is
the live bug. The location_list loop four lines below is the identical shape; it is
unreachable today because the driving grep -oE guarantees a non-empty post-colon part, but
it is one pattern edit from being live and the guard costs a line. Verified on 3.2.57 that
the unguarded form aborts with location_list[@]: unbound variable and the guarded form
reports intelligibly.

test-threading-doc.sh — a case asserting an unresolvable citation produces the
diagnostic and not an abort, plus every "$checker" invocation changed to
"$BASH" "$checker".

That second part is what makes the new case able to fail at all. The shebang resolves to the
first bash on PATH, which need not be the interpreter running the suite — so with the
shebang, deleting the guard leaves the new case passing under 3.2.57. My first version of
this test was decoration and I only found that by mutating it. It also makes the self-test
agree with tests/meson.build:735, which already runs the checker under
find_program('bash'); before, the self-test's inner checker used the runtime PATH bash
while the sibling test used the configure-time bash, and the two could diverge.

Review

Reviewer approved, verifying against the same 3.2.57 binary. It confirmed the "$BASH"
change is strictly more faithful rather than merely different, that return 1 on an empty
candidate set is equivalent to the old fall-through and not merely similar, and that four
independent mutations each kill the new case.

Two things it found that are fixed here: a temp-directory leak I introduced (my new case
reassigned fixture and replaced the EXIT trap, orphaning the first mktemp -d every run —
now reuses the file's own make_fixture idiom, verified 0 leftovers under a controlled
TMPDIR on both shells), and the latent location_list twin above.

It also found the same shape in scripts/ci/check-abi-manifest.sh:124, where
abi/libwirelog-1.0.suppr does not exist so the array is empty in the default
configuration — masked only by libabigail being unavailable on macOS. Filed as #1324.

Local: 304 Ok / 0 Fail / 12 Skipped, serialized, dedicated build dir.

…n misses

resolve_reference_source iterated "${candidates[@]}" without checking the array
was non-empty. On bash 3.2 that is an unbound-variable error under `set -u`;
bash 4.4 changed it. So a prose citation naming a file that does not exist under
wirelog/ killed the checker with

    check-threading-doc.sh: line 65: candidates[@]: unbound variable

instead of letting the caller report which citation failed to resolve. It cannot
cause a false pass -- the path is only reachable when the run was going to fail
anyway -- but it replaces the diagnostic with one that names an internal array.

threading_doc and threading_doc_selftest are registered in suite abi with no
platform gate, ci-pr.yml runs bare `meson test` on macos-latest in two jobs, and
those runners ship bash 3.2.57.

Guard both sites: the candidates loop, and the location_list loop four lines
below the new comment, which has the identical shape. The second is unreachable
today because the driving grep guarantees a non-empty post-colon part, but it is
one pattern edit from being live and the guard costs a line.

The self-test now invokes the checker as `"$BASH" "$checker"` rather than
through its shebang. That is the part that makes the new case able to fail: the
shebang resolves to the first bash on PATH, which need not be the interpreter
running the suite, so a portability defect only visible under the runner's bash
was masked. Verified -- with the shebang, deleting the guard leaves the new case
passing under bash 3.2.57; with "$BASH", it fails and names the abort. It also
makes the self-test agree with tests/meson.build:735, which already runs the
checker under find_program('bash').

Verified against GNU bash 3.2.57 built from source with all 57 official patches,
the version macOS ships. Note that unpatched 3.2.0 is not a faithful proxy: it
rejects this repository's inline `=~ ^([0-9]+)-([0-9]+)$` as a syntax error,
which 3.2.57 accepts.

Refs #1320
@justinjoy
justinjoy merged commit 6aa8f26 into main Sep 3, 2026
26 checks passed
@justinjoy
justinjoy deleted the fix/1320-bash32-empty-array branch September 3, 2026 02:36
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.

check-threading-doc.sh aborts with 'unbound variable' on bash 3.2 when a citation resolves to nothing

1 participant