Skip to content

--jobs with a non-integer value hangs on Bash 3.x and is silently ignored on Bash 4.3+ #873

Description

@Chemaclass

🤔 Background

src/main.sh resolves --jobs auto to an integer and carries this comment:

# "auto" caps at the detected core count; wait_for_job_slot needs an
# integer, so resolve it here rather than leaking the string downstream.

The else branch then assigns $2 verbatim, so the stated invariant is never enforced. Nothing else validates it, and BASHUNIT_PARALLEL_JOBS from the environment bypasses this code entirely.

Observed

bashunit::runner::wait_for_job_slot compares the running-job count against max_jobs with [ ... ], which errors (status 2) on a non-integer operand. The two execution paths then diverge:

Bash 3.x (polling fallback, src/runner.sh:376) — the break guard never succeeds, so the loop never exits. The run hangs, emitting the same error forever:

$ ./bashunit --jobs abc tests/     # /bin/bash 3.2.57
src/runner.sh: line 376: [: abc: integer expression expected
src/runner.sh: line 376: [: abc: integer expression expected
...                                # killed at 15s, no progress

Bash 4.3+ (wait -n path, src/runner.sh:363) — the while guard fails, the loop body never runs, and the concurrency limit is silently dropped:

$ /opt/homebrew/bin/bash ./bashunit --jobs abc tests/   # bash 5.3.15
 All tests passed
$ echo $?
0

So the same command hangs on the bash macOS ships and silently ignores the limit on a modern one.

Related

Same class as #871 (unvalidated CLI input). --output <value> is also accepted with any string and silently ignored:

$ ./bashunit --output nonsense tests/
 All tests passed     # exit 0, default format

Suggested fix

Validate at the boundary the same way bashunit::main::set_shard_or_exit already does — reject a --jobs value that is not a non-negative integer with a clear error and non-zero exit, and apply the same check when BASHUNIT_PARALLEL_JOBS comes from the environment. Worth making wait_for_job_slot fail safe rather than loop forever regardless.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions