Skip to content

WaitStatusUsedAsExitCode ​

warning native off by default PHP ≥ 5.3

Group: Probable bugs

Decode the child wait status.

Example ​

php
<?php
$pid=pcntl_waitpid($child,$status); if ($status===3) { echo "exit three"; }

Reported:

  • line 2: Decode the child wait status.

Detection ​

This is an opt-in policy. Truthiness, previous-state checks, raw wait-status comparisons and dispatch acknowledgements can be intentional; enabling this rule requests explicit handling of the contract described below.

  • Track unchanged output status from preceding local pcntl_wait/pcntl_waitpid. Report direct equality/ordering against a right-hand constant integer 1 through 255. Comparisons to zero, bit masks, decoder functions, swapped operands and unknown provenance are excluded.
  • Resolve builtin functions, extension classes, method receivers, constants and named arguments. Follow unchanged locals and aliases only within the same bounded lexical scope. Require a reachable path; merge branch facts only when all incoming paths establish them.
  • Emit one finding at the violating operation, not one per evidence statement. Rebinding, writes, by-reference escape, unresolved calls that can mutate relevant state, and exhausted analysis budgets remove proof.
  • D4. The status variable counts as unchanged only when nothing between the wait call and the comparison can give it another value. Any of these removes proof: plain or compound assignment, ++/--, a position in an array or list() destructuring target, a foreach key or value target, unset(), a global or static declaration, a catch variable, an element or property write through the variable, binding it to a reference ($alias = &$status) and a by-reference closure capture. When the comparison sits in a loop that started after the wait call, a write anywhere in that loop counts too, because a later iteration compares the rewritten value. Reads, copies and by-value captures do not remove proof.

Exceptions (no report) ​

  • Exclude shadowed builtins, unresolved receivers, incomplete syntax and unknown prerequisite facts. An extension function name alone does not prove an application function is that builtin.
  • A dominating valid guard or repair described in Detection prevents the finding. Both legacy noinspection and custos-ignore forms suppress this ID.
  • No report when the status variable was rewritten as described in D4, for example pcntl_waitpid($child, $status); $status++; if ($status === 3) {} or [$pid, $status] = $result; before the comparison.

Fix ​

No automatic fix. The required repair depends on error handling, data selection, lifecycle ordering or application policy.

All edits use exact byte ranges and preserve comments and evaluation order. Offer no fix when its stated prerequisites cannot be proven or the replacement is unsupported by the configured PHP version.

PHP versions ​

Requires PHP 5.3 or later and the referenced extension API. Respect method-specific introduction versions within PHP 5.3–8.5; unsupported optional APIs cannot establish facts. Named arguments require PHP 8.0 or later.

Configure ​

In custos.json:

json
{
  "rules": {
    "WaitStatusUsedAsExitCode": {
      "enabled": true
    }
  }
}

Suppress ​

Before the statement or declaration (or the first statement of the file):

php
// @custos-ignore WaitStatusUsedAsExitCode

Released under the MIT License. Native rules and rules modeled on Php Inspections (EA Extended); independent clean-room implementation.