forked from 1b-agent/opencadstudio-upstream
fix(start): saturate the recent-limit plus step
Bug: The keep-recent-files footer on the Start page builds its [-] [count] [+] buttons eagerly while constructing the widget, and the [+] step was written as plain shown + STEP while the [-] button next to it already used saturating_sub. shown comes from the input box, whose handler keeps every ASCII digit with no length cap - so typing 18446744073709551615 (2^64-1) parses to usize::MAX and the addition overflowed during view(), before the button was ever clicked. Debug builds panic with "attempt to add with overflow"; release builds (no overflow checks) wrap to a small number and request a nonsense limit. The clamp in set_recent_limit runs only after the value is computed. Reproduce: 1. Start page -> "keep recent files" box -> type 18446744073709551615. 2. Before: the next frame panics at widget construction (on render, no click needed); release builds wrap the step silently. 3. After: no panic; pressing Enter or [+] applies the clamped limit and the box resyncs to it. Fix: Mirror the [-] button: shown.saturating_add(STEP). At usize::MAX the message carries usize::MAX, which the handler's existing clamp-and-resync treats exactly like any other over-max entry, so both step buttons are now saturating and the release-build wrap is closed as well. on_submit has no arithmetic and needs no change. The regression test calls start_page_content directly with the hostile string - it fails at the same line instead of requiring a GUI session.
This commit is contained in:
1 parent
e15d801011
commit
b19253374c
1 file changed
+26
-1
+26
-1
@@ -4257,7 +4257,7 @@ pub(super) fn recent_files_panel<'a>(
|
||||
.style(step_style),
|
||||
count_box,
|
||||
button(crate::ui::icons::themed(crate::ui::icons::PLUS, 11.0))
|
||||
.on_press(Message::SetRecentLimit(shown + STEP))
|
||||
.on_press(Message::SetRecentLimit(shown.saturating_add(STEP)))
|
||||
.padding([3, 6])
|
||||
.style(step_style),
|
||||
text(format!("/ {}", super::recent::RECENT_MAX))
|
||||
@@ -4306,4 +4306,29 @@ mod tests {
|
||||
assert_eq!(bg, tab.scene.paper_bg_color);
|
||||
assert!(crate::ui::style::common::canvas_is_light(bg));
|
||||
}
|
||||
|
||||
/// The [+] step on the keep-recent-files box is built eagerly from an
|
||||
/// uncapped user string (`RecentLimitInput` keeps every ASCII digit):
|
||||
/// `18446744073709551615` parses to `usize::MAX`, and the plain
|
||||
/// `shown + STEP` overflowed while the *widget was constructed* —
|
||||
/// i.e. during `view()`, before any click. The [−] button next to it
|
||||
/// already used `saturating_sub`.
|
||||
#[test]
|
||||
fn recent_limit_plus_step_survives_an_overflowing_input() {
|
||||
let _ = start_page_content(
|
||||
&[],
|
||||
&[],
|
||||
false,
|
||||
&std::collections::HashMap::new(),
|
||||
&[],
|
||||
false,
|
||||
&[],
|
||||
&std::collections::HashMap::new(),
|
||||
50,
|
||||
"18446744073709551615",
|
||||
800.0,
|
||||
std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0)),
|
||||
super::super::StartSection::default(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user