Security: cap the perspective grid's line-loop bounds at 121 a way

This commit is contained in:
bflatastic
2026-10-24 04:34:18 +07:00
parent 1bb904c147
commit 0ecef703ef
2 changed files with 16 additions and 3 deletions
+6 -3
View File
@@ -562,14 +562,17 @@ impl PerspectiveGrid {
s
};
let (su, sv) = (step(w), step(h_len));
// Counted, not summed: a count in whole lines (at most 121 a way).
for i in 0..=((w + 1e-9) / su).floor() as usize {
// Counted, not summed: a count in whole lines (at most 121 a way). The fixed 1e-9
// tolerance can inflate the count when the whole domain is far smaller than it, so the
// bound is capped on its own, before any loop runs.
let count = |len: f64, s: f64| ((len + 1e-9) / s).floor().clamp(0.0, 120.0) as usize;
for i in 0..=count(w, su) {
let u = i as f64 * su;
if let (Some(a), Some(b)) = (h.apply(Point::new(u, 0.0)), h.apply(Point::new(u, h_len))) {
out.push((a, b));
}
}
for i in 0..=((h_len + 1e-9) / sv).floor() as usize {
for i in 0..=count(h_len, sv) {
let v = i as f64 * sv;
if let (Some(a), Some(b)) = (h.apply(Point::new(0.0, v)), h.apply(Point::new(w, v))) {
out.push((a, b));
@@ -123,6 +123,16 @@ mod tests {
assert_eq!(g.snap_offset(b, Vec2::new(18.0, 0.0)), Vec2::new(18.0, 0.0), "nothing within reach");
}
#[test]
fn a_tiny_stored_grid_draws_a_bounded_number_of_lines() {
// A stored grid can carry extreme values: the loop bound must not depend on a fixed
// tolerance swallowing the whole domain.
let g = PerspectiveGrid { cell: 1e-18, extent: 1e-18, height: 1e-18, ..PerspectiveGrid::normal(2, Rect::new(0.0, 0.0, 800.0, 600.0)) };
for pl in Plane::ALL {
assert!(g.lines(pl).len() <= 121 + 121, "at most 121 lines a way on {pl:?}");
}
}
#[test]
fn colours_and_rulers_come_from_the_definition() {
let mut g = grid();