Skip to content

Preserve quotes and decode string literal escapes - #272

Open
zakariyaghazzol wants to merge 4 commits into
fprime-community:develfrom
zakariyaghazzol:fpy-string-literals
Open

zakariyaghazzol wants to merge 4 commits into
fprime-community:develfrom
zakariyaghazzol:fpy-string-literals

Conversation

@zakariyaghazzol

@zakariyaghazzol zakariyaghazzol commented Oct 17, 2026 •

Copy link
Copy Markdown

Fixes #201.

Use literal_eval to preserve quotes and decode escapes once. Report malformed escapes, non-UTF-8 surrogate values and raw NUL bytes as source-located errors, including Python 3.10 ValueErrors. Leave SPEC.md unchanged.

Tests check parser diagnostics and exact event text/command bytes on both sequencers. Local results: 67 focused tests passed; full suite on Python 3.12: 1,766 passed, one upstream skip, one existing XPASS. Focused parser checks also passed on Python 3.10–3.13.

Small-input probes under resource limits did not reproduce DoS in either implementation. This PR does not claim a DoS fix.

Comment thread SPEC.md Outdated

String literals have type [String](#internal-types).

Single-quoted and double-quoted string literals support Python-style backslash

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

let's leave the spec unmodified for now

Comment thread src/fpy/syntax.py
from fpy.error import SyntaxErrorDuringTransform

try:
value = literal_eval(s)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Literal eval seems like a good way to do this, but the docs say:
"""
A relatively small input can lead to memory exhaustion or to C stack exhaustion, crashing the process. There is also the possibility for excessive CPU consumption denial of service on some inputs. Calling it on untrusted data is thus not recommended.
"""

Is there a way we can mitigate this? I'd recommend developing a PoC to show that this can cause denial of service in the current form, then developing a fix, then showing it no longer can DoS

@zakariyaghazzol

Copy link
Copy Markdown
Author

I’ll remove the spec changes. I’m proposing to decode string escapes directly instead of using literal_eval, then test the old and new code with the same inputs and resource limits to check the specific failure and make sure existing string behavior stays the same.
Preliminary local testing show some large inputs can also exhaust the memory before string decoding begins when the test process is capped at 192 MiB. Would you prefer that be tracked separately in another issue, so this PR can stay focused on the string decoder?

@zimri-leisher

Copy link
Copy Markdown
Collaborator

What I don't want is for small inputs to be able to cause DoS. I think it's more okay for a large input to do this. Maybe track it in another issue. Keep the description small, clear and precise.

@zakariyaghazzol

zakariyaghazzol commented Oct 26, 2026 •

Copy link
Copy Markdown
Author

I compared literal_eval with a unicode_escape-based decoder on Python 3.10–3.13 by using small malformed and escape-heavy inputs under memory and time limits. I couldn’t reproduce a small-input DoS in either approach. The nesting/expression cases I checked were rejected before string decoding or remained quoted text.

The other approach I tested was to decode the string escapes directly with unicode_escape. With literal_eval, Python first parses the quoted string into a syntax tree and then returns its value. The decoder would skip that extra parsing step and turn escapes like \n into their actual characters directly. But it wasn’t a simple replacement. I still needed code around it to preserve literal Unicode characters and handle newlines the same way. So it added more code to maintain, and these tests didn’t show that it solved a small-input DoS that was present with literal_eval.

I did find that a raw NUL byte produces an internal-error diagnostic on Python 3.10. A small ValueError handler fixes that in the local prototype I have, and the focused string-parsing tests passed on each version. Based on these results, I plan to keep literal_eval with that handler and a regression test instead of introducing a custom decoder since it would introduce more unneeded complexity, in my opinion.

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