Bug 1028514 - Check for integer overflow when converting from floating-point number milliseconds; r=froydnj
authorBrian Birtles <birtles@gmail.com>
Wed, 25 Jun 2014 09:42:18 +0900
changeset 190605 e7ae48a8fac8ab5f94c0e29ed546a36c1f2245ec
parent 190604 3b49cfc3c734bd98e2fd6e14208e3db20d7a15a2
child 190606 b31a50d545f72c573d693643a61d2a260a298ed9
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersfroydnj
bugs1028514
milestone33.0a1
Bug 1028514 - Check for integer overflow when converting from floating-point number milliseconds; r=froydnj In TimeStamp_windows.cpp and TimeStamp_darwin.cpp, in TimeStamp::FromMilliseconds we cast the floating-point number of ticks to a 64-bit integer before passing to TimeStamp::FromTicks(int64_t). This means that we skip the check for integer overflow performed by TimeStamp::FromTicks(double). This patch simply removes that cast so that we perform overflow checking. It also adds an assertion to ElementAnimation since this is one place where the lack of overflow checking was producing a negative value where it should not.
layout/style/AnimationCommon.cpp
layout/style/crashtests/1028514-1.html
layout/style/crashtests/crashtests.list
xpcom/ds/TimeStamp_darwin.cpp
xpcom/ds/TimeStamp_windows.cpp
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -442,16 +442,24 @@ ElementAnimation::HasAnimationOfProperty
   }
   return false;
 }
 
 ComputedTiming
 ElementAnimation::GetComputedTimingAt(TimeDuration aLocalTime,
                                       const AnimationTiming& aTiming)
 {
+  // Currently we expect negative durations to be picked up during CSS
+  // parsing but when we start receiving timing parameters from other sources
+  // we will need to clamp negative durations here.
+  // For now, if we're hitting this it probably means we've overflowing
+  // integer arithmetic in mozilla::TimeStamp.
+  MOZ_ASSERT(aTiming.mIterationDuration >= TimeDuration(0),
+             "Expecting iteration duration >= 0");
+
   // Always return the same object to benefit from return-value optimization.
   ComputedTiming result;
 
   TimeDuration activeDuration = ActiveDuration(aTiming);
 
   // When we finish exactly at the end of an iteration we need to report
   // the end of the final iteration and not the start of the next iteration
   // so we set up a flag for that case.
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1028514-1.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+
+function boom()
+{
+    document.documentElement.style.animation = "137438953471s bounce";
+    document.documentElement.offsetHeight;
+    document.documentElement.style.animationIterationCount = "infinite";
+}
+
+</script>
+</head>
+
+<body onload="boom();"></body>
+</html>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -100,10 +100,11 @@ load 915440.html
 load 927734-1.html
 load 930270-1.html
 load 930270-2.html
 load 945048-1.html
 load 972199-1.html
 load 989965-1.html
 load 992333-1.html
 pref(dom.webcomponents.enabled,true) load 1017798-1.html
+load 1028514-1.html
 load large_border_image_width.html
 load border-image-visited-link.html
--- a/xpcom/ds/TimeStamp_darwin.cpp
+++ b/xpcom/ds/TimeStamp_darwin.cpp
@@ -97,17 +97,17 @@ TimeDuration::ToSecondsSigDigits() const
   valueSigDigs = sResolutionSigDigs * (valueSigDigs / sResolutionSigDigs);
   return (valueSigDigs * sNsPerTick) / kNsPerSecd;
 }
 
 TimeDuration
 TimeDuration::FromMilliseconds(double aMilliseconds)
 {
   NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early");
-  return TimeDuration::FromTicks(int64_t((aMilliseconds * kNsPerMsd) / sNsPerTick));
+  return TimeDuration::FromTicks((aMilliseconds * kNsPerMsd) / sNsPerTick);
 }
 
 TimeDuration
 TimeDuration::Resolution()
 {
   NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early");
   return TimeDuration::FromTicks(int64_t(sResolution));
 }
--- a/xpcom/ds/TimeStamp_windows.cpp
+++ b/xpcom/ds/TimeStamp_windows.cpp
@@ -420,17 +420,17 @@ TimeDuration::ToSecondsSigDigits() const
   // and chop off insignificant digits
   valueSigDigs = resolutionSigDigs * (valueSigDigs / resolutionSigDigs);
   return double(valueSigDigs) / kNsPerSecd;
 }
 
 TimeDuration
 TimeDuration::FromMilliseconds(double aMilliseconds)
 {
-  return TimeDuration::FromTicks(int64_t(ms2mt(aMilliseconds)));
+  return TimeDuration::FromTicks(ms2mt(aMilliseconds));
 }
 
 TimeDuration
 TimeDuration::Resolution()
 {
   return TimeDuration::FromTicks(int64_t(sResolution));
 }