Skip to content

The Guard's Wait-Loop Rule Misses a Loop Keyword Glued to $' or a Backtick #2138

Closed as not planned

Description

@ptr727

Problem

The guard's wait-loop rule never finds a loop keyword that its tokenizer glues to the syntax before it. Two shapes reach that on develop, and bash runs the loop in each of them.

  • ANSI-C and locale quoting. The outer lex reads $'...' and $"..." as a $ glued to the quoted text, so the payload begins with $while, which is not a loop keyword. _marked_lex notices ANSI-C quoting, but that changes only which quote mask is used, not the tokens.
  • A loop inside a backtick substitution. The tokenizer yields `while, which does not match while. The $(...) form of the same loop is denied.

Reproduce (constructed)

Each of these is allowed:

bash -c $'while true; do sleep 1; done'
eval $'while true; do sleep 1; done'
echo `while true; do sleep 1; done`

x=$(while true; do sleep 1; done) is denied.

Done looks like

A $'...' or $"..." word reads as the text bash gives it, and a backtick substitution's body is scanned as commands the way a $(...) body is. All three commands above are denied, and self-test rows pin them.

Found by the local strict review of the #2080 fix (handoff #2137). Each shape predates that fix, and the eval form reaches it once the fix reads eval payloads.

Activity

  1. added
    bugSomething isn't working
    agentsAgents instructions
    pre-existingReview finding classed pre-existing per local-strict-review Disposing of Findings
    on Sep 30, 2026
  2. ptr727 commented on Oct 6, 2026

    @ptr727
    OwnerAuthor

    A command substitution in backticks hides a wrapper or an eval the same way. Both of these are allowed on develop, and bash runs the loop:

    x=`eval 'until false; do sleep 1; done'`
    echo ` bash -c 'until false; do sleep 1; done'`

    Found by a local strict review pass on the #2080 branch.

  3. ptr727 commented on Oct 8, 2026

    @ptr727
    OwnerAuthor

    Closed: Folded into #1959 per #2517, approved by the maintainer. This is a case of the guard's lexer splitting a command differently from bash, and #1959's single bash-aware scanner fixes the class, with this shape kept as a self-test row there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agentsAgents instructionsbugSomething isn't workingpre-existingReview finding classed pre-existing per local-strict-review Disposing of Findings

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions