mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-25 10:56:48 -06:00
engine: long digit strings no longer overflow object.opacityKeys
opacity_from_digits multiplied and added on every character of its input string before the one-or-two-digit check, so "9999999999" overflowed u32 on the way (panic in debug builds, wrap in release). The scan now steps n with checked_mul/checked_add and stops (None) at the first character the number cannot take, so a long digit string is refused like any other bad input. Test: opacity_digits (engine keymap) covers the ten-digit string and the command's BadParams refusal.
This commit is contained in:
@@ -803,7 +803,8 @@ pub fn opacity_from_digits(digits: &str) -> Option<f32> {
|
||||
let mut n = 0u32;
|
||||
let mut count = 0;
|
||||
for c in digits.chars() {
|
||||
n = n * 10 + c.to_digit(10)?;
|
||||
// Input-derived: a number that outgrows `u32` stops the scan (None); it never wraps.
|
||||
n = n.checked_mul(10)?.checked_add(c.to_digit(10)?)?;
|
||||
count += 1;
|
||||
}
|
||||
match count {
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::Session;
|
||||
use crate::cmd::edit::opacity_from_digits;
|
||||
use crate::keymap::{Context, GESTURES, Group, KEYS, Mods, Platform, display, lookup, matches, normalize, parse, primary};
|
||||
use crate::params::id_of;
|
||||
use crate::tools::ToolId;
|
||||
use crate::{EngineError, Session};
|
||||
use figcraft_doc::NodeId;
|
||||
|
||||
const PLATFORMS: [Platform; 2] = [Platform::Mac, Platform::Other];
|
||||
@@ -186,6 +186,7 @@ fn opacity_digits() {
|
||||
assert_eq!(opacity_from_digits("00"), Some(0.0));
|
||||
assert_eq!(opacity_from_digits(""), None);
|
||||
assert_eq!(opacity_from_digits("123"), None);
|
||||
assert_eq!(opacity_from_digits("9999999999"), None, "ten digits must not overflow u32");
|
||||
assert_eq!(opacity_from_digits("4x"), None);
|
||||
assert_eq!(opacity_from_digits("٣"), None, "ASCII digits only");
|
||||
|
||||
@@ -201,6 +202,10 @@ fn opacity_digits() {
|
||||
ex(&mut s, "edit.undo", json!({}));
|
||||
assert_eq!(op(&s, a), 0.3, "one undo step");
|
||||
assert!(s.execute("object.opacityKeys", &json!({"digits": "123"})).is_err());
|
||||
assert!(
|
||||
matches!(s.execute("object.opacityKeys", &json!({"digits": "9999999999"})), Err(EngineError::BadParams { .. })),
|
||||
"an overflowing digit string is a parameter error, not a panic"
|
||||
);
|
||||
assert!(s.execute("object.opacityKeys", &json!({})).is_err());
|
||||
ex(&mut s, "select.none", json!({}));
|
||||
assert!(s.execute("object.opacityKeys", &json!({"digits": "1"})).is_err(), "nothing selected");
|
||||
|
||||
Reference in New Issue
Block a user