Skip to content

StrtokStateClobbered ​

warning native on by default

Group: Probable bugs

Detect starting a second two-argument strtok sequence between an initial sequence call and its one-argument continuation on the same reachable path.

Example ​

php
<?php
$first=strtok($a,','); strtok($b,':'); $next=strtok(',');

Reported:

  • line 2: Keep strtok sequences separate.

Detection ​

  • Report starting a second two-argument strtok sequence between an initial sequence call and its one-argument continuation on the same reachable path.
  • Resolve builtin calls and named arguments before checking the contract. Project-local callees are considered only when their bodies or immutable summaries establish the required facts. The default is enabled, with positive proof required.
  • The path is searched backwards from the continuation over the statements that precede it in the same statement list. The newest start is the closest statement that is a two-argument strtok call, bare or as the assigned value; the initial start is the next such statement before it. Statements in between need not be adjacent to either call.
  • D4. A statement crossed by the search must be unable to start a sequence: it contains no function, method or static call, object creation, include, eval, yield, closure or arrow function. Between the newest start and the continuation, one-argument strtok calls are also accepted, since they only advance the current sequence. Any other statement ends the search without a report.
  • When the statement list is the body of a while, foreach or for loop, or the main branch of an if, the search continues with the statements before that construct, provided its header (the condition, the iterated expression, or the for initializers and conditions) satisfies D4. This covers the nested tokenizer shape, where an inner sequence is started and consumed inside the loop that continues the outer one. Other enclosing constructs (else/elseif branches, do, switch, try, function bodies) end the search.

Exceptions (no report) ​

  • Completion/restart of the same intended sequence, no later continuation, or a wrapper known not to invoke strtok are excluded. Two starts on the same string expression are a restart.
  • Unresolved targets, incomplete required facts, suppressed findings and PHP versions lacking the referenced API or language feature produce no report. User declarations shadowing builtin names are not builtin contracts.
  • The continuation belongs to the newest sequence: all three delimiter arguments are plain string literals, the continuation's delimiter equals the newest start's and differs from the initial start's. The initial call then only took a leading token ($scheme = strtok($url, ':'); $name = strtok($file, '.'); $ext = strtok('.');). When a delimiter is not a literal, or both starts share the delimiter, the owner is ambiguous and the report is kept.

Fix ​

No automatic fix: independent tokenizer state requires restructuring.

PHP versions ​

Apply only on PHP versions supporting the referenced APIs and syntax (within PHP 5.3–8.5). Builtin behavior and argument contracts follow the configured PHP version. Extension-specific calls require resolved extension API symbols; do not treat same-named application functions as extension calls.

Options ​

None. Enable or disable this rule through normal rule configuration.

Configure ​

In custos.json:

json
{
  "rules": {
    "StrtokStateClobbered": {
      "enabled": false
    }
  }
}

Suppress ​

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

php
// @custos-ignore StrtokStateClobbered

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