LibWeb: Protect animation frame callbacks from GC while they execute

Stealing the callbacks from the AnimationFrameCallbackDriver made them
no longer safe from GC. Continue to store them on the class until we
have finished their execution.
This commit is contained in:
Timothy Flynn 2024-10-31 10:05:44 -04:00 committed by Andreas Kling
parent f6991a2955
commit d188aaf288
Notes: github-actions[bot] 2024-10-31 14:38:43 +00:00
4 changed files with 23 additions and 2 deletions

View file

@ -0,0 +1,2 @@
Collect garbage
PASS! (Didn't crash)

View file

@ -0,0 +1,14 @@
<script src="../include.js"></script>
<script>
asyncTest((done) => {
requestAnimationFrame(() => {
println("Collect garbage");
internals.gc();
});
requestAnimationFrame(() => {
println("PASS! (Didn't crash)");
done();
});
});
</script>

View file

@ -6,6 +6,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/ScopeGuard.h>
#include <LibWeb/HTML/AnimationFrameCallbackDriver.h>
namespace Web::HTML {
@ -16,6 +17,7 @@ void AnimationFrameCallbackDriver::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_callbacks);
visitor.visit(m_executing_callbacks);
}
WebIDL::UnsignedLong AnimationFrameCallbackDriver::add(Callback handler)
@ -37,8 +39,10 @@ bool AnimationFrameCallbackDriver::has_callbacks() const
void AnimationFrameCallbackDriver::run(double now)
{
auto taken_callbacks = move(m_callbacks);
for (auto& [id, callback] : taken_callbacks)
AK::ScopeGuard guard { [&]() { m_executing_callbacks.clear(); } };
m_executing_callbacks = move(m_callbacks);
for (auto& [id, callback] : m_executing_callbacks)
callback->function()(now);
}

View file

@ -34,6 +34,7 @@ private:
WebIDL::UnsignedLong m_animation_frame_callback_identifier { 0 };
OrderedHashMap<WebIDL::UnsignedLong, Callback> m_callbacks;
OrderedHashMap<WebIDL::UnsignedLong, Callback> m_executing_callbacks;
};
}