Skip to content

preproc: fix infinite loop in paste_tokens with leading/consecutive %+ - #321

Open
agourakis82 wants to merge 3 commits into
netwide-assembler:masterfrom
agourakis82:fix/preproc-paste-tokens-hang
Open

agourakis82 wants to merge 3 commits into
netwide-assembler:masterfrom
agourakis82:fix/preproc-paste-tokens-hang

Conversation

@agourakis82

Copy link
Copy Markdown

Fixes #294.

Summary

In asm/preproc.c, paste_tokens() tracks prev_nonspace as a Token ** pointing to the preceding non-whitespace, non-paste token in the stream, which serves as the left token for explicit token pasting (%+).

Two bugs in pointer tracking caused infinite loops on malformed inputs such as %+s%+t:

  1. When a leading %+ is dropped (t == NULL), *prev_next = tok = next advances *head to the token following %+ (e.g. s). However, prev_nonspace remained NULL, failing to record that head now points to a non-space token.
  2. In the unpasted token advancement path, prev_nonspace was updated by checking whether next was non-space/non-paste, rather than whether tok was:
if (next && next->type != TOKEN_WHITESPACE && next->type != TOKEN_PASTE)
    prev_nonspace = prev_next;

Because prev_next was already advanced to &tok->next and next was the second %+, this check evaluated to false, leaving prev_nonspace as NULL.

Consequently, upon reaching the second %+, !prev_nonspace was evaluated as true again. The second %+ was mistakenly treated as another leading %+, setting nextp = head and rewinding next back to *head (s), trapping the while loop in an endless cycle.

Fix

  • When dropping a leading %+ (!t), update prev_nonspace to prev_next if the new head token is not whitespace/paste.
  • In the token advancement path, update prev_nonspace = prev_next whenever tok is not whitespace/paste before advancing prev_next = &tok->next.

Verified assembling %+s%+t and %+ts %+ts completes cleanly without hanging.

Fixes netwide-assembler#294.

In paste_tokens(), prev_nonspace tracks a pointer to the last non-space,
non-paste token to identify the left token for explicit pasting (%+).

1. When a leading %+ was dropped (t == NULL), prev_nonspace remained
   NULL even after *head was updated to point to the subsequent token.
2. In the unpasted token advancement path, prev_nonspace was conditionally
   updated by inspecting next instead of tok, so when next was another
   %+, prev_nonspace was never set to point to tok.

As a result, a sequence like "%+s%+t" caused the second %+ to also be
treated as a leading %+ (!prev_nonspace == true), resetting nextp to
head and setting next to the head of the stream (rewinding to s), creating
an infinite loop and hanging NASM.
Copilot AI lite review requested due to automatic review settings September 23, 2026 23:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Add regression fixtures covering leading/consecutive %+ inputs.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Medium severity

Open (1)
What changed in this PR

Fixes an infinite loop in preprocessor token pasting involving leading or consecutive %+ tokens.

Changes:

  • Corrects prev_nonspace tracking after dropping %+.
  • Fixes token advancement bookkeeping in paste_tokens().
File Summary
asm/​preproc.c Fixes %+ token traversal; add regression fixtures for the reported hangs.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread asm/preproc.c
@agourakis82

Copy link
Copy Markdown
Author

Follow-up regression fixture is now included in a76c3ff16: it covers leading %+, consecutive %+, and the combined leading+consecutive case that previously hung in paste_tokens(). Could you please re-review when convenient?

@agourakis82

Copy link
Copy Markdown
Author

The regression coverage update is published in b105d3a. NASM CI/CD on that exact head is still action_required. Could a maintainer approve the workflow run? The same approval hold affects my #320 and #322; their heads were not changed in this pass.

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.

Infinite loop / Hang in paste_tokens (asm/preproc.c) via malformed %+ macro syntax

2 participants