You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG] Division by zero panic in ResizablePanelGroup #894
In �pps/desktop/src/components/resizable.rs:71-79, the drag fraction calculation divides by bounds width/height without checking for zero:
ust let fraction = match self.orientation { Orientation::Horizontal => { (event.event.position.x - bounds.left()) / (bounds.right() - bounds.left()) // Can be 0 } Orientation::Vertical => { (event.event.position.y - bounds.top()) / (bounds.bottom() - bounds.top()) // Can be 0 } };
If the panel group has zero width or height (e.g., during window initialization, minimized state, or layout edge cases), this causes a division by zero panic.
Expected Behavior
The calculation should guard against zero-size bounds and return a safe default fraction.
Steps To Reproduce
Run the desktop app
Resize window to minimum size or trigger a layout where panel bounds collapse to zero
Attempt to drag the resizable handle
Recurrence Probability
Sometimes - depends on window state and layout timing
Additional Context
Critical bug - causes immediate panic/crash. Should be fixed before any PRs are accepted.
When the resizable panel group collapses or has zero width/height during window initialization or layout edge cases, (offset) / (bounds.right() - bounds.left()) results in 0.0 / 0.0 = NaN or +/-inf. Passing this to self.clamp_fraction(fraction) triggers f32::clamp's internal assertion !self.is_nan(), causing an immediate panic crash.
Changes
Guard against non-positive span (span <= px(0.0)) in ResizablePanelGroup::resize, early-returning without modifying fraction or notifying listeners.
Ensure fraction.is_finite() before updating self.fraction.
Harden clamp_fraction and minimum_fraction with .is_finite() checks so non-finite floats safely resolve to boundaries instead of panicking.
Added unit test panel_fraction_handles_nan_and_infinities covering NaN, +/-inf, and invalid minimums.
All existing and new tests pass cleanly (cargo test --manifest-path apps/desktop/Cargo.toml).
Given that direct PRs are currently closed during the rewrite, happy to open a PR or let maintainers cherry-pick this commit whenever appropriate!
I dug into this one while deciding whether to fix it, and the "division by zero panic" framing doesn't quite hold. Worth recording before someone writes a PR against the wrong theory.
px is float-backed, so this is floating-point division, not integer division. Rust does not panic for f32 / 0.0; the quotient is inf, or NaN when the numerator is also zero. I reproduced both paths by extracting clamp_fraction and the resize arithmetic into a standalone program (rustc 1.98.1):
numerator=50 denominator=0 -> raw fraction = inf
after clamp_fraction(_, 0.1) = 0.9
numerator=0 denominator=0 -> raw fraction = NaN
after clamp_fraction(_, 0.1) = NaN (NaN survives clamp)
So the real consequences are:
inf clamps to 0.9, so the panel silently snaps to 90%.
NaN survives f32::clamp (which propagates NaN rather than clamping it), gets stored in self.fraction, and reaches .w(relative(NaN)) in render, corrupting the layout.
A third case the issue doesn't mention: inverted bounds, where end < start gives a negative span and the fraction clamps to the minimum_fraction floor.
So it's a genuine bug and the fix is worth having, but it presents as layout corruption plus a panel snapping open, not as a crash. That matters for triage: "immediate panic/crash" would reasonably jump the queue, and this isn't that.
Patch
Guarding on the span and ignoring the drag when the group is collapsed:
let(position, start, end) = matchself.orientation{Orientation::Horizontal => (event.event.position.x, bounds.left(), bounds.right()),Orientation::Vertical => (event.event.position.y, bounds.top(), bounds.bottom()),};// A collapsed panel group (zero width or height, e.g. before the window// is laid out) divides by zero. `px` is float-backed, so this yields inf// or NaN rather than panicking, but both then reach `relative(..)` and// corrupt the layout. Ignore the drag instead of storing a bad fraction.let span = end - start;if span <= 0.0{return;}self.fraction = self.clamp_fraction((position - start) / span);
span <= 0.0 covers the zero and inverted cases together. rustfmt --check is clean, and I asserted the fraction stays finite and inside the clamp range across zero-width, zero-height, normal, and inverted spans.
Full branch — this also includes the apps/desktop/README.md Windows/MSVC correction reported in #892, since that was a one-line doc fix and fit naturally on the same branch:
I wasn't able to open a PR: GitHub returns rollroyces does not have the correct permissions to execute CreatePullRequest, and REST returns 404, so PR creation appears gated to collaborators. I know from the README and #811 that the architecture is still being designed and outside contributions aren't open yet, so I'm not going to force it. Happy to land it however is easiest — direct commit, cherry-pick, or opening the PR myself once the gate lifts.
One caveat stated plainly: ResizablePanelGroup isn't instantiated anywhere yet. It's exported from components/mod.rs, but shell.rs doesn't mount it, so this is groundwork hardening rather than a crash someone can hit today.
Activity
killer1panda commentedon Sep 8, 2026
I've investigated this issue, verified the root cause, and put together a fix with unit tests on my fork:
fix/resizable-panel-zero-bound-panic821aabfRoot Cause
When the resizable panel group collapses or has zero width/height during window initialization or layout edge cases,
(offset) / (bounds.right() - bounds.left())results in0.0 / 0.0 = NaNor+/-inf. Passing this toself.clamp_fraction(fraction)triggersf32::clamp's internal assertion!self.is_nan(), causing an immediate panic crash.Changes
span <= px(0.0)) inResizablePanelGroup::resize, early-returning without modifying fraction or notifying listeners.fraction.is_finite()before updatingself.fraction.clamp_fractionandminimum_fractionwith.is_finite()checks so non-finite floats safely resolve to boundaries instead of panicking.panel_fraction_handles_nan_and_infinitiescoveringNaN,+/-inf, and invalid minimums.All existing and new tests pass cleanly (
cargo test --manifest-path apps/desktop/Cargo.toml).Given that direct PRs are currently closed during the rewrite, happy to open a PR or let maintainers cherry-pick this commit whenever appropriate!
rollroyces commentedon Oct 23, 2026
Correction on the failure mode — and an offer
I dug into this one while deciding whether to fix it, and the "division by zero panic" framing doesn't quite hold. Worth recording before someone writes a PR against the wrong theory.
pxis float-backed, so this is floating-point division, not integer division. Rust does not panic forf32 / 0.0; the quotient isinf, orNaNwhen the numerator is also zero. I reproduced both paths by extractingclamp_fractionand theresizearithmetic into a standalone program (rustc 1.98.1):So the real consequences are:
infclamps to0.9, so the panel silently snaps to 90%.NaNsurvivesf32::clamp(which propagates NaN rather than clamping it), gets stored inself.fraction, and reaches.w(relative(NaN))inrender, corrupting the layout.end < startgives a negative span and the fraction clamps to theminimum_fractionfloor.So it's a genuine bug and the fix is worth having, but it presents as layout corruption plus a panel snapping open, not as a crash. That matters for triage: "immediate panic/crash" would reasonably jump the queue, and this isn't that.
Patch
Guarding on the span and ignoring the drag when the group is collapsed:
span <= 0.0covers the zero and inverted cases together.rustfmt --checkis clean, and I asserted the fraction stays finite and inside the clamp range across zero-width, zero-height, normal, and inverted spans.Full branch — this also includes the
apps/desktop/README.mdWindows/MSVC correction reported in #892, since that was a one-line doc fix and fit naturally on the same branch:https://github.com/rollroyces/OpenCut/tree/fix/resizable-zero-span
On submitting
I wasn't able to open a PR: GitHub returns
rollroyces does not have the correct permissions to execute CreatePullRequest, and REST returns 404, so PR creation appears gated to collaborators. I know from the README and #811 that the architecture is still being designed and outside contributions aren't open yet, so I'm not going to force it. Happy to land it however is easiest — direct commit, cherry-pick, or opening the PR myself once the gate lifts.One caveat stated plainly:
ResizablePanelGroupisn't instantiated anywhere yet. It's exported fromcomponents/mod.rs, butshell.rsdoesn't mount it, so this is groundwork hardening rather than a crash someone can hit today.