Skip to content

Reject overflowing numeric literals safely - #620

Closed
logbie wants to merge 1 commit into
mainfrom
agent/reject-invalid-numeric-literals
Closed

Reject overflowing numeric literals safely#620
logbie wants to merge 1 commit into
mainfrom
agent/reject-invalid-numeric-literals

Conversation

@logbie

@logbie logbie commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • replace panic-prone numeric lexer callbacks with fallible parsing
  • reject integers outside WFL's i64 representation
  • reject non-finite decimal float literals
  • add regressions for both public lexer collection paths

Security impact

Previously, attacker-controlled WFL source containing an oversized integer reached parse::<i64>().unwrap() and could unwind CLI or LSP processing. Invalid numeric input now becomes a normal lexer error.

Validation

  • git diff --check
  • added focused lexer regression tests, including catch_unwind coverage
  • Rust tests were not run locally because this workspace has no Rust toolchain; repository CI passed on the final head
  • all GitHub CI, config lint, and review checks passed on the final head

Production readiness

Summary by CodeRabbit

  • Bug Fixes
    • Invalid or oversized integer literals are now reported as lexer errors instead of causing a crash.
    • Overflowing and non-finite floating-point literals are rejected safely as lexer errors.
    • Improved reliability when processing malformed numeric input.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Numeric literal lexing now converts integer parse failures and non-finite float values into lexer errors instead of panics. Regression tests cover both standard and position-aware lexer APIs.

Changes

Numeric lexing

Layer / File(s) Summary
Fallible numeric parsing and regression coverage
src/lexer/token.rs, src/lexer/tests.rs
Integer and float token actions use fallible parsing helpers; float parsing accepts only finite values, and tests verify overflow returns lexer errors without unwinding.

Estimated code review effort: 3 (Moderate) | ~15 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: safely rejecting overflowing numeric literals instead of panicking.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/reject-invalid-numeric-literals

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@logbie
logbie marked this pull request as ready for review July 16, 2026 18:13
Copilot AI review requested due to automatic review settings July 16, 2026 18:13

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

Open in Devin Review

Comment thread src/lexer/token.rs
Comment on lines +484 to +496
fn parse_int_literal(lex: &mut logos::Lexer<Token>) -> Option<i64> {
lex.slice().parse::<i64>().ok()
}

/// WFL numbers must be finite. Rust accepts very large decimal floats as
/// positive infinity, so reject both parse failures and non-finite results at
/// the token boundary instead of injecting an infinity value into the runtime.
fn parse_float_literal(lex: &mut logos::Lexer<Token>) -> Option<f64> {
lex.slice()
.parse::<f64>()
.ok()
.filter(|value| value.is_finite())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Behavior change ships without the required documentation or Dev Diary entry

A user-facing behavior change is introduced (parse_int_literal/parse_float_literal at src/lexer/token.rs:484-496) that now rejects out-of-range integer and non-finite float literals, but the change ships with no documentation or Dev Diary entry, so the repository's mandatory docs-with-feature rule is not met.
Impact: Contributors and users have no record that oversized numeric literals are now rejected, leaving documentation out of sync with actual runtime behavior.

Mandatory documentation policy in CLAUDE.md/AGENTS.md

CLAUDE.md states under "Documentation Development" that every change altering user-facing behavior MUST update or add corresponding documentation and add a Dev Diary entry in the same change. The PR's own description confirms a compatibility/behavior change ("out-of-range integers and non-finite float literals are now rejected instead of crashing or entering the runtime"), yet git diff for this PR touches only src/lexer/tests.rs and src/lexer/token.rs — no Docs/ update and no Dev diary/ entry.

Prompt for agents
This PR changes user-facing behavior (out-of-range integer literals and non-finite float literals are now rejected as lexer errors instead of panicking or producing infinity). Per CLAUDE.md and AGENTS.md the repository requires documentation to ship in the same change, plus a Dev Diary entry for non-trivial work. Add a short note to the relevant Docs section describing that numeric literals must fit in i64 and floats must be finite, and add a Dev Diary entry under the 'Dev diary/' folder describing this reliability/security fix and its compatibility impact.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Hardens the WFL lexer against attacker-controlled numeric literals by replacing panic-prone parsing with fallible parsing, ensuring oversized integers and non-finite floats become normal lexing errors rather than unwinding CLI/LSP execution paths.

Changes:

  • Replace parse::<i64/f64>().unwrap() lexer callbacks with fallible helpers that return Option, letting Logos surface failures as lex errors.
  • Reject integers outside i64 and reject float literals that parse to non-finite values (±inf, NaN) at the token boundary.
  • Add regression tests covering oversized integer literals (including unwind safety for public lexing entry points) and non-finite float literals.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/lexer/token.rs Switch numeric literal callbacks to safe, fallible parsing; reject non-finite float literals.
src/lexer/tests.rs Add regressions ensuring oversized integers and overflowing floats are lex errors and don’t trigger panics in lexer collection paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lexer/tests.rs
Comment on lines +183 to +188
let source = format!("{}.0", "9".repeat(400));
let mut lexer = Token::lexer(&source);
assert!(matches!(lexer.next(), Some(Err(_))));
assert!(lexer.next().is_none());
assert!(std::panic::catch_unwind(|| lex_wfl_with_positions(&source)).is_ok());
}

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 09056da318

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lexer/token.rs
/// lexer. Logos treats `None` as a normal lexing error, which the positioned
/// lexer reports with the literal's span and the parser then rejects.
fn parse_int_literal(lex: &mut logos::Lexer<Token>) -> Option<i64> {
lex.slice().parse::<i64>().ok()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Surface overflowed numeric lex errors to callers

When this callback returns None, the collection path turns the Logos Err into a stderr message and drops the span instead of giving the parser a fatal token/error. In contexts where the rest of the line is already valid, e.g. store x as 1 9223372036854775808, the checked CLI lexer produces the same token stream as store x as 1 plus EOL, so parsing/analyzing can succeed and execute the truncated program instead of rejecting the malformed literal; the same issue applies to the new non-finite float path. Please preserve a lexer error in the returned token stream/result rather than relying on a dropped Err to make the parser reject it.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/lexer/tests.rs (1)

187-187: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Include the standard lexer path in the panic regression test.

For consistency with the integer test, consider verifying that lex_wfl also handles the non-finite float without unwinding.

♻️ Proposed refactor
+    assert!(std::panic::catch_unwind(|| lex_wfl(&source)).is_ok());
     assert!(std::panic::catch_unwind(|| lex_wfl_with_positions(&source)).is_ok());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lexer/tests.rs` at line 187, Extend the panic regression test around
lex_wfl_with_positions to also invoke the standard lex_wfl path with the same
source and assert it completes without unwinding, matching the existing integer
test coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/lexer/tests.rs`:
- Line 187: Extend the panic regression test around lex_wfl_with_positions to
also invoke the standard lex_wfl path with the same source and assert it
completes without unwinding, matching the existing integer test coverage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8d509d3e-d55a-483d-8017-2bfb06233dbb

📥 Commits

Reviewing files that changed from the base of the PR and between 0f52b3a and 09056da.

📒 Files selected for processing (2)
  • src/lexer/tests.rs
  • src/lexer/token.rs

logbie commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #632, which preserves this security fix in the consolidated Rust-source hardening PR. The combined head is mergeable and all required CI checks are green.

@logbie logbie closed this Jul 17, 2026
@logbie
logbie deleted the agent/reject-invalid-numeric-literals branch August 14, 2026 04:30
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.

2 participants