Closed Bug 1134538 Opened 9 years ago Closed 2 years ago

Assertion failure ('Infinity + -Infinity' and '-Infinity + Infinity' are undefined or multiplication of infinity) with CSS transition/animations

Categories

(Core :: XPCOM, defect)

x86_64
macOS
defect
Not set
critical

Tracking

()

RESOLVED FIXED
105 Branch
Tracking Status
firefox-esr91 --- wontfix
firefox-esr102 --- wontfix
firefox103 --- wontfix
firefox104 --- wontfix
firefox105 --- fixed

People

(Reporter: jruderman, Assigned: boris)

References

Details

(Keywords: assertion, regression, testcase, Whiteboard: qa-not-actionable)

Attachments

(2 files, 3 obsolete files)

Attached file testcase (obsolete) —
Assertion failure: (aA != 9223372036854775807LL || aB != (-9223372036854775807LL-1)) && (aA != (-9223372036854775807LL-1) || aB != 9223372036854775807LL) ('Infinity + -Infinity' and '-Infinity + Infinity' are undefined), at StickyTimeDuration.h:38

This assertion is part of a file added in bug 1039924.
Attached file stack (obsolete) —
This is likely exposed by bug 1133375 which adds the transition duration and delay together.
The duration '2199023255552s' causes another assertion at http://hg.mozilla.org/mozilla-central/file/29d5a4175c8b/xpcom/ds/StickyTimeDuration.h#l149 in case of CSS animations.  We should handle it as well.
Summary: Assertion failure ('Infinity + -Infinity' and '-Infinity + Infinity' are undefined) with CSS transition → Assertion failure ('Infinity + -Infinity' and '-Infinity + Infinity' are undefined or multiplication of infinity) with CSS transition/animations
I'm checking this assertion recently, and I think the root cause is:

We are trying to create a transition with a super large duration: "2199023255552s" and a super large delay: "140737488355s". In nsTransitionManager.cpp[1], we convert the duration/delay into a TimeDuration/StickyTimeDuration type:

  float duration; // duration = 2199023255552.
  float delay;    // delay = 140737488355.
  ...
  timing.mDuration.emplace(StickyTimeDuration::FromMilliseconds(duration)); // an overflow happens
  timing.mDelay = TimeDuration::FromMilliseconds(delay); // an overflow happens

StickyTimeDuration::FromMilliseconds() converts duration into ticks, and the formula in OSX[2] is:

  double result = (aMilliseconds * kNsPerMsd) / sNsPerTick; // kNsPerMsd = 1000000, sNsPerTick = 1.0 (in my OSX environment)

The result is larger than INT64_MAX: (2199023255552 * 1000000 / 1.0) > 9223372036854775807, so we got an Infinity for duration, and another Infinity for delay in attachment 8566412 [details].

I think the unit of |BaseTimeDuration::mValue| is "tick", so using the super large duration&delay makes this undefined behavior. I don't have any good idea about this bug now. Changing the unit of |BaseTimeDuration::mValue| might be a solution, but we might lose the precision.

[1] http://searchfox.org/mozilla-central/rev/51aa673e28802fe6ea89f4793721fc55334a6ac8/layout/style/nsTransitionManager.cpp#918-919
[2] http://searchfox.org/mozilla-central/rev/51aa673e28802fe6ea89f4793721fc55334a6ac8/mozglue/misc/TimeStamp_darwin.cpp#105
(In reply to Boris Chiou [:boris] from comment #4)
> StickyTimeDuration::FromMilliseconds() converts duration into ticks, and the
> formula in OSX[2] is:
> 
>   double result = (aMilliseconds * kNsPerMsd) / sNsPerTick; // kNsPerMsd =
> 1000000, sNsPerTick = 1.0 (in my OSX environment)
> 
> The result is larger than INT64_MAX: (2199023255552 * 1000000 / 1.0) >
> 9223372036854775807, so we got an Infinity for duration, and another
> Infinity for delay in attachment 8566412 [details].

Sorry, the result should be (2199023255552000 * 1000000 / 1.0) > 9223372036854775807. the unit of the duration is millisecond.
Attached file Testcase from bug 1070759 (obsolete) —
This testcase triggers:
Assertion failure: (aA != (9223372036854775807L) && aA != (-9223372036854775807L-1)) || aA != aB ('Infinity - Infinity' and '-Infinity - -Infinity' are undefined), at mozilla/StickyTimeDuration.h:62

Presumably because of the "transition-delay: 18446744073709551584s".
Maybe could fix all these issues if we clamp the 'transition-delay' value in stylo
to some reasonable value?

Bug 1271788 and bug 1341795 seems like the same underlying issue.
Flags: needinfo?(emilio)
Whiteboard: qa-not-actionable

This still repros. Maybe it is reasonable to do that? But these are also exposed to JS so maybe we need a deeper fix. Boris, do you know what the right thing to do here would be?

Flags: needinfo?(emilio) → needinfo?(boris.chiou)

OK. I assign this to myself for now so I won't miss this bug.

Assignee: nobody → boris.chiou
Flags: needinfo?(boris.chiou)
Attached file Simplified test case
Attachment #8566412 - Attachment is obsolete: true
Attachment #8566413 - Attachment is obsolete: true
Attachment #8984621 - Attachment is obsolete: true

my call stack

#01: mozilla::dom::Animation::IntervalEndTime(mozilla::BaseTimeDuration<mozilla::StickyTimeDurationValueCalculator> const&) const[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x1425dd8]
#02: mozilla::dom::CSSTransition::QueueEvents(mozilla::BaseTimeDuration<mozilla::StickyTimeDurationValueCalculator> const&)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x142c058]
#03: mozilla::dom::CSSTransition::Tick()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x142c714]
#04: mozilla::dom::AnimationTimeline::Tick()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x1428f68]
[Child 14600, Main Thread] WARNING: NS_ENSURE_TRUE(Preferences::InitStaticMembers()) failed: file /Users/boris/Projects/firefox/gecko-dev/modules/libpref/Preferences.cpp:4595
#05: mozilla::dom::DocumentTimeline::MostRecentRefreshTimeUpdated()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x142e270]
#06: nsRefreshDriver::Tick(mozilla::layers::BaseTransactionId<mozilla::VsyncIdType>, mozilla::TimeStamp, nsRefreshDriver::IsExtraTick)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x4521dc8]
#07: mozilla::RefreshDriverTimer::TickRefreshDrivers(mozilla::layers::BaseTransactionId<mozilla::VsyncIdType>, mozilla::TimeStamp, nsTArray<RefPtr<nsRefreshDriver> >&)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x452ad7c]
#08: mozilla::RefreshDriverTimer::Tick(mozilla::layers::BaseTransactionId<mozilla::VsyncIdType>, mozilla::TimeStamp)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x452ac64]
#09: mozilla::VsyncRefreshDriverTimer::RunRefreshDrivers(mozilla::layers::BaseTransactionId<mozilla::VsyncIdType>, mozilla::TimeStamp)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x452a91c]
#10: mozilla::VsyncRefreshDriverTimer::TickRefreshDriver(mozilla::layers::BaseTransactionId<mozilla::VsyncIdType>, mozilla::TimeStamp)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x4529f4c]
#11: mozilla::VsyncRefreshDriverTimer::RefreshDriverVsyncObserver::NotifyVsyncTimerOnMainThread()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x45294e0]
#12: mozilla::dom::VsyncMainChild::RecvNotify(mozilla::VsyncEvent const&, float const&)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x3b681e0]
#13: mozilla::dom::PVsyncChild::OnMessageReceived(IPC::Message const&)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x3d1082c]
#14: mozilla::ipc::PBackgroundChild::OnMessageReceived(IPC::Message const&)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0xbf6afc]
#15: mozilla::ipc::MessageChannel::DispatchAsyncMessage(mozilla::ipc::ActorLifecycleProxy*, IPC::Message const&)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0xbba038]
#16: mozilla::ipc::MessageChannel::DispatchMessage(mozilla::ipc::ActorLifecycleProxy*, mozilla::UniquePtr<IPC::Message, mozilla::DefaultDelete<IPC::Message> >)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0xbb7e7c]
#17: mozilla::ipc::MessageChannel::RunMessage(mozilla::ipc::ActorLifecycleProxy*, mozilla::ipc::MessageChannel::MessageTask&)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0xbb85c8]
#18: mozilla::ipc::MessageChannel::MessageTask::Run()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0xbb9120]
#19: mozilla::RunnableTask::Run()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x2de4a4]
#20: mozilla::TaskController::DoExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x2b6830]
#21: mozilla::TaskController::ExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x2b55ec]
#22: mozilla::TaskController::ProcessPendingMTTask(bool)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x2b5898]
#23: mozilla::detail::RunnableFunction<mozilla::TaskController::InitializeInternal()::$_0>::Run()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x2e3b4c]
#24: nsThread::ProcessNextEvent(bool, bool*)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x2ca504]
#25: NS_ProcessNextEvent(nsIThread*, bool)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x2d0c60]
#26: mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0xbbdf38]
#27: MessageLoop::Run()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0xb40bf8]
#28: nsBaseAppShell::Run()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x4225134]
#29: nsAppShell::Run()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x4297f28]
#30: XRE_RunAppShell()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x59b61d4]
#31: mozilla::ipc::MessagePumpForChildProcess::Run(base::MessagePump::Delegate*)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0xbbe9e8]
#32: MessageLoop::Run()[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0xb40bf8]
#33: XRE_InitChildProcess(int, char**, XREChildData const*)[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/toolkit/library/build/XUL +0x59b5a20]
#34: main[/Users/boris/Projects/firefox/gecko-dev/objdirs/obj-browser-debug/dist/NightlyDebug.app/Contents/MacOS/plugin-container.app/Contents/MacOS/plugin-container +0x6d4]

The calculation in question is actually;

EffectEnd() - mEffect->NormalizedTiming().Delay()

In most cases, EffectEnd() is including the Delay() so that theoretically we can skip the subtraction in question. That's said, I am not sure whether it's good or not in terms of spec compliance.

So basically, this is an undefined part. I just checked the implementation in WebKit and Chromium, they just let C++ compiler decide the result. For example, in WebKit:
intervalEnd = std::max(0_s, Seconds::fromMilliseconds(std::min(timing.endTime - timing.delay, timing.activeDuration)));

If both endTime and delay are inf, I guess the result in WebKit is something like this:
=> std::max(0_s, Seconds::fromMilliseconds(std::min(inf - inf, timing.activeDuration)))
=> std::max(0_s, Seconds::fromMilliseconds(std::min(NaN, timing.activeDuration)))
=> std::max(0_s, Seconds::fromMilliseconds(NaN))
=> 0

Note: Seconds use double to store the value. Any comparison involving NaNs is false, and so in the implementation of std::min the comparison fails and the first argument is returned, because the standard wants the first argument if the arguments are equivalent. (See GCC bug 47706).

In any case, I think there is no better way to fix this and so I guess the spec just leaves this as a undefined part. Perhaps we can just return zero duration if both are inf.

If both end time and start delay are Infinity, the result of interval
end time is undefined, so now we return zero duration to avoid the
assertion in StickyTimeDuration.

Pushed by bchiou@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/041ab0732725
Avoid the computation of inf - inf for the interval end time. r=birtles
Status: NEW → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → 105 Branch
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: