Commit Graph
6 Commits
Author SHA1 Message Date
NgoQuocViet2001 9db030eb1f fix(expr-eval): make ^ right-associative
parse_power accepted a single exponent (`unary ('^' unary)?`), so a
chained power stopped after the first `^`. The remaining `^2` was left
unconsumed, and eval_to_string's embedded-expression scan then handed it
back as literal text: typing `2^3^2` into a coordinate or distance field
produced the string "8^2" rather than 512, and `2^3^2+1" produced "8^3".

Recurse into parse_power for the exponent so `2^3^2` reads as
`2^(3^2)", the standard right-associative meaning, and the whole
expression is consumed.
2026-09-03 15:32:56 +07:00
Hakan Seven 5e62da464e fix(properties): preserve literal text
Separate numeric fields from names and content so only numeric property values are evaluated as expressions.

Refs #809
2026-08-20 14:58:12 +03:00
NgoQuocViet2001 dd9ff89904 fix(expr-eval): don't evaluate identifiers found inside words
The embedded-expression rescan in eval_to_string tries every substring, so
any identifier the evaluator knows is also recognised in the middle of
ordinary text. Because `pi` needs no arguments it resolves anywhere it
appears, and names typed into property or command fields were rewritten:
`ASPIRATORE` came back as `AS3.141592653589793RATORE`.

Require a candidate whose first or last token is an identifier to start,
respectively end, on a word boundary. Leading and trailing numbers stay
unrestricted so mixed input such as `def10*10abc` still evaluates.

Fixes #809
2026-08-19 20:19:54 +07:00
Hakan SevenandClaude Opus 4.8 87232bba2c fix(expr-eval): bound eval_to_string against super-linear DoS
The recursion-depth guard fixes the parser stack overflow, but user input
actually flows through eval_to_string (command line, viewport, dynamic
input — synchronous on the UI thread). Its embedded-expression fallback
re-tokenises every (start, end) window, so cost is ≈O(n³): a few-KB paste
of non-evaluable text or deeply nested parens froze the app for seconds to
minutes even though eval_number fast-returns None in microseconds
(measured: "x"×3200 → 16 s, 4 KB of parens → 51 s).

Cap the fallback scan at MAX_EVAL_SCAN_LEN (256) — whole-string numbers
and expressions of any length still evaluate via the fast paths; only the
mixed free-text scan is bounded, returning long input unchanged. Clarify
that MAX_RECURSION counts parser frames (256 ≈ 41 nested parens, not 256
levels). Add regression tests: the 41/42 nesting boundary, unary-chain and
function-arg-nesting rejection, and an eval_to_string over-cap promptness
test (50k junk + 100k nested parens return instantly).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-28 22:41:02 +03:00
Sebastian bfb81f6658 Adding expression evaluator against stack-overflow DoS 2026-06-28 22:38:09 +03:00
Nick Ziv f890ed864c Implement Expression Evaluation for numerical inputs and the CLI 2026-06-07 13:17:46 -04:00