Bug 207957 - Safari jetsams with repeated drawImage/getImageData
Summary: Safari jetsams with repeated drawImage/getImageData
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Images (show other bugs)
Version: Safari 13
Hardware: iPhone / iPad iOS 13
: P2 Critical
Assignee: Simon Fraser (smfr)
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-02-19 13:22 PST by Jerry Jongerius
Modified: 2020-03-23 22:05 PDT (History)
7 users (show)

See Also:


Attachments
Patch (8.59 KB, patch)
2020-03-23 18:08 PDT, Simon Fraser (smfr)
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jerry Jongerius 2020-02-19 13:22:58 PST
Tested on iPad 13.3.1
1. visit https://www.duckware.com/test/webkit/browsercrash.html
2. Play video, then immediately pause video
3. Click 'Run Test' button
4. within 5 seconds, browser crashes
Comment 1 Alexey Proskuryakov 2020-02-19 22:48:16 PST
I can reproduce on an iPhone, this test runs out of memory. I don't immediately see any leak in JS, so looks like either a leak in WebKit, or insufficiently active garbage collection.

It just does this repeatedly:

  var ctx1 = can.getContext("2d");
  ctx1.drawImage( el("video"), 0, 0, can.width, can.height );
  ctx1.getImageData( 0, 0, can.width, can.height );
Comment 2 Radar WebKit Bug Importer 2020-02-19 22:48:29 PST
<rdar://problem/59619922>
Comment 3 Jerry Jongerius 2020-02-23 08:03:11 PST
Once the bug is understood, if would be very helpful if 'workaround' code could be designed to allow my WebApp to run on Apple systems (with the bug) -- until a fix is pushed out.
Comment 4 Simon Fraser (smfr) 2020-03-23 14:56:40 PDT
Growth is apparent on macOS too.
Comment 5 Simon Fraser (smfr) 2020-03-23 15:36:44 PDT
Looks like SubimageCacheWithTimer holds onto every frame!

    frame #0: 0x00000004a3859a7f WebCore`WebCore::CVPixelBufferReleaseInfoCallback(refcon=0x0000600001354c30) at PixelBufferConformerCV.cpp:128:5
    frame #1: 0x00007fff3543d930 CoreGraphics`data_provider_finalize + 64
    frame #2: 0x00007fff3540306e CoreGraphics`data_provider_retain_count + 74
    frame #3: 0x00007fff350c5847 CoreFoundation`_CFRelease + 460
    frame #4: 0x00007fff3546ae47 CoreGraphics`image_finalize + 103
    frame #5: 0x00007fff350c5769 CoreFoundation`_CFRelease + 238
    frame #6: 0x00000004a01d6b69 WebCore`WTF::RetainPtr<CGImage*>::~RetainPtr(this=0x00007ff9a2144010) at RetainPtr.h:170:9
    frame #7: 0x00000004a01cf275 WebCore`WTF::RetainPtr<CGImage*>::~RetainPtr(this=0x00007ff9a2144010) at RetainPtr.h:168:1
  * frame #8: 0x00000004a384284f WebCore`WebCore::SubimageCacheWithTimer::SubimageCacheEntry::~SubimageCacheEntry(this=0x00007ff9a2144010) at SubimageCacheWithTimer.h:48:12
    frame #9: 0x00000004a3840aa5 WebCore`WebCore::SubimageCacheWithTimer::SubimageCacheEntry::~SubimageCacheEntry(this=0x00007ff9a2144010) at SubimageCacheWithTimer.h:48:12
    frame #10: 0x00000004a3846f61 WebCore`WTF::HashTable<WebCore::SubimageCacheWithTimer::SubimageCacheEntry, WebCore::SubimageCacheWithTimer::SubimageCacheEntry, WTF::IdentityExtractor, WebCore::SubimageCacheWithTimer::SubimageCacheHash, WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits, WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits>::deallocateTable(table=0x00007ff9a2144010) at HashTable.h:1224:27
    frame #11: 0x00000004a3846e3b WebCore`WTF::HashTable<WebCore::SubimageCacheWithTimer::SubimageCacheEntry, WebCore::SubimageCacheWithTimer::SubimageCacheEntry, WTF::IdentityExtractor, WebCore::SubimageCacheWithTimer::SubimageCacheHash, WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits, WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits>::clear(this=0x00007ff9d1c39658) at HashTable.h:1371:9
    frame #12: 0x00000004a38408a5 WebCore`WTF::HashSet<WebCore::SubimageCacheWithTimer::SubimageCacheEntry, WebCore::SubimageCacheWithTimer::SubimageCacheHash, WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits>::clear(this=0x00007ff9d1c39658) at HashSet.h:313:12
    frame #13: 0x00000004a38407ae WebCore`WebCore::SubimageCacheWithTimer::invalidateCacheTimerFired(this=0x00007ff9d1c39640) at SubimageCacheWithTimer.cpp:86:13
    frame #14: 0x00000004a3846617 WebCore`decltype(__f=0x00007ff9d1c376a8, __a0=0x00007ff9d1c376b8)).*fp()) std::__1::__invoke<void (WebCore::SubimageCacheWithTimer::*&)(), WebCore::SubimageCacheWithTimer*&, void>(void (WebCore::SubimageCacheWithTimer::*&)(), WebCore::SubimageCacheWithTimer*&) at type_traits:4366:1
    frame #15: 0x00000004a3846590 WebCore`std::__1::__bind_return<void (WebCore::SubimageCacheWithTimer::*)(), std::__1::tuple<WebCore::SubimageCacheWithTimer*>, std::__1::tuple<>, __is_valid_bind_return<void (WebCore::SubimageCacheWithTimer::*)(), std::__1::tuple<WebCore::SubimageCacheWithTimer*>, std::__1::tuple<> >::value>::type std::__1::__apply_functor<void (__f=0x00007ff9d1c376a8, __bound_args=size=1, (null)=__tuple_indices<0> @ 0x00007ffeec6e62b8, __args=size=0)(), std::__1::tuple<WebCore::SubimageCacheWithTimer*>, 0ul, std::__1::tuple<> >(void (WebCore::SubimageCacheWithTimer::*&)(), std::__1::tuple<WebCore::SubimageCacheWithTimer*>&, std::__1::__tuple_indices<0ul>, std::__1::tuple<>&&) at functional:2716:12
    frame #16: 0x00000004a3846549 WebCore`std::__1::__bind_return<void (WebCore::SubimageCacheWithTimer::*)(), std::__1::tuple<WebCore::SubimageCacheWithTimer*>, std::__1::tuple<>, __is_valid_bind_return<void (WebCore::SubimageCacheWithTimer::*)(), std::__1::tuple<WebCore::SubimageCacheWithTimer*>, std::__1::tuple<> >::value>::type std::__1::__bind<void (this=0x00007ff9d1c376a8)(), WebCore::SubimageCacheWithTimer*>::operator()<>() at functional:2749:20
    frame #17: 0x00000004a38464ee WebCore`WTF::Detail::CallableWrapper<std::__1::__bind<void (WebCore::SubimageCacheWithTimer::*&)(), WebCore::SubimageCacheWithTimer*>, void>::call(this=0x00007ff9d1c376a0) at Function.h:52:39
    frame #18: 0x00000004a0017692 WebCore`WTF::Function<void ()>::operator(this=0x00007ff9d1c39698)() const at Function.h:84:35
    frame #19: 0x00000004a24e0a56 WebCore`WebCore::DeferrableOneShotTimer::fired(this=0x00007ff9d1c39670) at Timer.h:189:9
    frame #20: 0x00000004a360af64 WebCore`WebCore::ThreadTimers::sharedTimerFiredInternal(this=0x00007ff9c1c2c800) at ThreadTimers.cpp:127:23
    frame #21: 0x00000004a3612be1 WebCore`WebCore::ThreadTimers::setSharedTimer(this=0x00007ff9c1c2c838)::$_0::operator()() const at ThreadTimers.cpp:67:80
Comment 6 Simon Fraser (smfr) 2020-03-23 16:40:31 PDT
SubimageCacheWithTimer only clears itself if you haven't put anything in for 1 second, which never happens if you touch the cache every frame. So it just accumulates images.
Comment 7 Simon Fraser (smfr) 2020-03-23 18:08:55 PDT
Created attachment 394335 [details]
Patch
Comment 8 Simon Fraser (smfr) 2020-03-23 18:59:44 PDT
(In reply to Jerry Jongerius from comment #3)
> Once the bug is understood, if would be very helpful if 'workaround' code
> could be designed to allow my WebApp to run on Apple systems (with the bug)
> -- until a fix is pushed out.

The workaround, I think, would be to avoid putting the <video> inside a <table>. Make the video element 960x540.
Comment 9 EWS 2020-03-23 22:05:56 PDT
Committed r258908: <https://trac.webkit.org/changeset/258908>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 394335 [details].