Gesture numbers are checked when the request is admitted, before it waits for a layout

This commit is contained in:
Bruno-Alumn
2026-10-30 20:14:15 +01:00
parent 7283694154
commit 8d256db7a0
3 changed files with 12 additions and 2 deletions
+2
View File
@@ -53,6 +53,8 @@ impl LightcraftApp {
if self.pending_gestures.len() >= MAX_PENDING_GESTURES {
return Err(format!("{}: {MAX_PENDING_GESTURES} control gestures are already pending", method));
}
// refused at once, without waiting for a layout or taking a pending slot
crate::control::check_gesture_numbers(&method, &params)?;
let now = self.tick_now_ms();
self.pending_gestures.push(PendingGesture {
method,
+3 -2
View File
@@ -607,8 +607,9 @@ const MAX_GESTURE_NUMBER: f64 = 1e6;
/// ±[`MAX_GESTURE_NUMBER`]. A larger one turns into an infinite or NaN `f32` position or scroll
/// delta: egui asserts on NaN positions, and a release build would hand them to every widget.
/// `count` and `steps` are clamped where they are read instead, and `ui.zoom`'s `factor` (a
/// multiplier, not a position) is checked and clamped by its own branch.
fn check_gesture_numbers(method: &str, p: &Value) -> Result<(), String> {
/// multiplier, not a position) is checked and clamped by its own branch. Checked when a request
/// is admitted and again here, for callers that resolve a gesture directly.
pub(crate) fn check_gesture_numbers(method: &str, p: &Value) -> Result<(), String> {
fn check(method: &str, key: &str, v: &Value) -> Result<(), String> {
match v {
Value::Number(n) if !matches!(key, "count" | "steps" | "factor") => match n.as_f64() {
@@ -930,6 +930,13 @@ fn gestures_refuse_numbers_that_are_not_screen_positions() {
crate::control::gesture_events(&mut app, &ctx, "ui.drag", &serde_json::json!({"x": 1.0, "toX": 999_999.0, "steps": 1e12})).unwrap();
assert!(!app.synthetic.is_empty());
// refused when the request is admitted: no pending slot, no wait for a layout
let (tx, rx) = reply_channel();
let e = app.admit_gesture(&ctx, "ui.click".into(), serde_json::json!({"x": 1e308}), tx).expect_err("refused at admission");
assert!(e.contains("between"), "{e}");
assert!(app.pending_gestures.is_empty());
drop(rx);
// through the whole control channel, as an agent sends it: an error, not a panic
let mut h = Headless::new(self::app(), [800.0, 600.0], 1.0);
h.step();