Skip to content

Commit

Permalink
Fix stack overflows in calc
Browse files Browse the repository at this point in the history
Fixes #827, fixes #791, fixes #611, closes #832
  • Loading branch information
devongovett committed Nov 3, 2024
1 parent 22a8b6f commit e3c8e12
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
21 changes: 21 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7847,6 +7847,27 @@ mod tests {
".foo{transform:rotateX(-40deg)rotateY(50deg)}",
);
minify_test(".foo { width: calc(10px * mod(18, 5)) }", ".foo{width:30px}");

minify_test(
".foo { width: calc(100% - 30px - 0) }",
".foo{width:calc(100% - 30px - 0)}",
);
minify_test(
".foo { width: calc(100% - 30px - 1 - 2) }",
".foo{width:calc(100% - 30px - 3)}",
);
minify_test(
".foo { width: calc(1 - 2 - 100% - 30px) }",
".foo{width:calc(-1 - 100% - 30px)}",
);
minify_test(
".foo { width: calc(2 * min(1px, 1vmin) - min(1px, 1vmin)); }",
".foo{width:calc(2*min(1px,1vmin) - min(1px,1vmin))}",
);
minify_test(
".foo { width: calc(100% - clamp(1.125rem, 1.25vw, 1.2375rem) - clamp(1.125rem, 1.25vw, 1.2375rem)); }",
".foo{width:calc(100% - clamp(1.125rem,1.25vw,1.2375rem) - clamp(1.125rem,1.25vw,1.2375rem))}",
);
}

#[test]
Expand Down
68 changes: 67 additions & 1 deletion src/values/calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -908,11 +908,31 @@ impl<V: AddInternal + std::convert::Into<Calc<V>> + std::convert::From<Calc<V>>
match (self, other) {
(Calc::Value(a), Calc::Value(b)) => (a.add(*b)).into(),
(Calc::Number(a), Calc::Number(b)) => Calc::Number(a + b),
(Calc::Sum(a, b), Calc::Number(c)) => {
if let Calc::Number(a) = *a {
Calc::Sum(Box::new(Calc::Number(a + c)), b)
} else if let Calc::Number(b) = *b {
Calc::Sum(a, Box::new(Calc::Number(b + c)))
} else {
Calc::Sum(Box::new(Calc::Sum(a, b)), Box::new(Calc::Number(c)))
}
}
(Calc::Number(a), Calc::Sum(b, c)) => {
if let Calc::Number(b) = *b {
Calc::Sum(Box::new(Calc::Number(a + b)), c)
} else if let Calc::Number(c) = *c {
Calc::Sum(Box::new(Calc::Number(a + c)), b)
} else {
Calc::Sum(Box::new(Calc::Number(a)), Box::new(Calc::Sum(b, c)))
}
}
(a @ Calc::Product(..), b) => Calc::Sum(Box::new(a), Box::new(b)),
(a, b @ Calc::Product(..)) => Calc::Sum(Box::new(a), Box::new(b)),
(Calc::Value(a), b) => (a.add(V::from(b))).into(),
(a, Calc::Value(b)) => (V::from(a).add(*b)).into(),
(Calc::Function(a), b) => Calc::Sum(Box::new(Calc::Function(a)), Box::new(b)),
(a, Calc::Function(b)) => Calc::Sum(Box::new(a), Box::new(Calc::Function(b))),
(a, b) => V::from(a).add(V::from(b)).into(),
(a @ Calc::Sum(..), b @ Calc::Sum(..)) => V::from(a).add(V::from(b)).into(),
}
}
}
Expand Down Expand Up @@ -966,6 +986,52 @@ impl<V: TrySign> TrySign for Calc<V> {
match self {
Calc::Number(v) => v.try_sign(),
Calc::Value(v) => v.try_sign(),
Calc::Product(c, v) => v.try_sign().map(|s| s * c.sign()),
Calc::Function(f) => f.try_sign(),
_ => None,
}
}
}

impl<V: TrySign> TrySign for MathFunction<V> {
fn try_sign(&self) -> Option<f32> {
match self {
MathFunction::Abs(_) => Some(1.0),
MathFunction::Max(values) | MathFunction::Min(values) => {
let mut iter = values.iter();
if let Some(sign) = iter.next().and_then(|f| f.try_sign()) {
for value in iter {
if let Some(s) = value.try_sign() {
if s != sign {
return None;
}
} else {
return None;
}
}
return Some(sign);
} else {
return None;
}
}
MathFunction::Clamp(a, b, c) => {
if let (Some(a), Some(b), Some(c)) = (a.try_sign(), b.try_sign(), c.try_sign()) {
if a == b && b == c {
return Some(a);
}
}
return None;
}
MathFunction::Round(_, a, b) => {
if let (Some(a), Some(b)) = (a.try_sign(), b.try_sign()) {
if a == b {
return Some(a);
}
}
return None;
}
MathFunction::Sign(v) => v.try_sign(),
MathFunction::Calc(v) => v.try_sign(),
_ => None,
}
}
Expand Down

0 comments on commit e3c8e12

Please sign in to comment.