How to intercept OOM crashes in non-PartitionAlloc

1 view
Skip to first unread message

weicong yu

unread,
Jun 11, 2025, 11:51:37 PMJun 11
to memory-dev

We use CrashKey in the SetPartitionAllocOomCallback() method to collect the memory information of v8 and blink when the render process is OOM.

However, for the OOM generated by TerminateBecauseOutOfMemory()RunPartitionAllocOomCallback() will not be executed, resulting in the inability to collect relevant memory information.

Is it possible to make all OOMs call the RunPartitionAllocOomCallback() method?


For example, the OOM generated by base::DiscardableMemoryAllocator::AllocateLockedDiscardableMemoryWithRetryOrDie() below will not call the RunPartitionAllocOomCallback() method

#7 Thread 38052 [ThreadPoolForegroundWorker] (crashed)
 0  KERNELBASE.dll + 0xc9f0a!RaiseException + 0x8a
    rax = 0x000000f4d7ffdef0   rdx = 0x0000000000000000
    rcx = 0x0000000000000026   rbx = 0x000000f4d7ffe780
    rsi = 0x0000000000000001   rdi = 0x00000000e0000008
    rbp = 0x0000000000000001   rsp = 0x000000f4d7ffe660
     r8 = 0x0000000000000000    r9 = 0x0000000000000000
    r10 = 0xaaaaaaaa00000010   r11 = 0x0000000000000000
    r12 = 0x0000721c094f3a80   r13 = 0x0000000000000000
    r14 = 0x0000721c006f4180   r15 = 0x000000f4d7ffe7e8
    rip = 0x00007ffe4e5f9f0a
    Found by: given as instruction pointer in context
 1  KERNELBASE.dll + 0xc9f0a!RaiseException + 0x8a
    rsp = 0x000000f4d7ffe698   rip = 0x00007ffe4e5f9f0a
    Found by: stack scanning
 2  frame.dll + 0x7dd2821!allocator_shim::internal::PartitionFree(allocator_shim::AllocatorDispatch const*, void*, void*) [D:\0713\x64\release-native-7.44.0\base\allocator\partition_allocator\src\partition_alloc\shim\allocator_shim_default_dispatch_to_partition_alloc.cc : 375 + 0xd]
    rsp = 0x000000f4d7ffe720   rip = 0x00007ffd993a2821
    Found by: stack scanning
 3  frame.dll + 0x1567178!base::DiscardableMemoryAllocator::AllocateLockedDiscardableMemoryWithRetryOrDie(unsigned long long, base::OnceCallback<void ()>) [D:\0713\x64\release-native-7.44.0\base\memory\discardable_memory_allocator.cc : 49 + 0x8]
    rbx = 0x0000000000adb9bc   rsi = 0x000000f4d7ffecd0
    rdi = 0x00007ffd9a9053f9   rbp = 0x0000000000adb9bc
    rsp = 0x000000f4d7ffe7c0   r12 = 0x0000721c094f3a80
    r13 = 0x0000000000000000   r14 = 0x0000721c006f4180
    r15 = 0x000000f4d7ffe7e8   rip = 0x00007ffd92b37178
    Found by: call frame info
 4  frame.dll + 0xc46e30!cc::GpuImageDecodeCache::DecodeImageIfNecessary(cc::DrawImage const&, cc::GpuImageDecodeCache::ImageData*, cc::ImageDecodeCache::TaskType, bool) [D:\0713\x64\release-native-7.44.0\cc\tiles\gpu_image_decode_cache.cc : 2469 + 0x20]
    rbx = 0x0000000000000000   rsi = 0x0000721c0535eb00
    rdi = 0x0000721c006f4180   rbp = 0x0000000000adb9bc
    rsp = 0x000000f4d7ffe830   r12 = 0x0000721c014cd800
    r13 = 0x0000000000000000   r14 = 0x0000721c054394d0
    r15 = 0x0000000000000000   rip = 0x00007ffd92216e30
    Found by: call frame info
 5  frame.dll + 0x149e0ab!cc::GpuImageDecodeCache::DecodeImageAndGenerateDarkModeFilterIfNecessary(cc::DrawImage const&, cc::GpuImageDecodeCache::ImageData*, cc::ImageDecodeCache::TaskType) [D:\0713\x64\release-native-7.44.0\cc\tiles\gpu_image_decode_cache.cc : 2393 + 0x15]
 
    Found by: inline record
 6  frame.dll + 0x149e0ab!cc::GpuImageDecodeCache::DecodeImageInTask(cc::DrawImage const&, cc::ImageDecodeCache::TaskType) [D:\0713\x64\release-native-7.44.0\cc\tiles\gpu_image_decode_cache.cc : 1975 + 0x15]
 
    Found by: inline record
 7  frame.dll + 0x149e0ac!cc::GpuImageDecodeTaskImpl::RunOnWorkerThread() [D:\0713\x64\release-native-7.44.0\cc\tiles\gpu_image_decode_cache.cc : 644 + 0x16]
    rbx = 0x0000721c05439480   rsi = 0x0000721c0535eb00
    rdi = 0x000000f4d7ffefc0   rbp = 0x0000000000000000
    rsp = 0x000000f4d7ffeed0   r12 = 0x0000721c014cd850
    r13 = 0x0000721c00232e20   r14 = 0x0000721c054394d0
    r15 = 0x0000721c014cd800   rip = 0x00007ffd92a6e0ac
    Found by: call frame info
 8  frame.dll + 0x893c5b1!cc::CategorizedWorkerPoolJob::Run(base::span<const cc::TaskCategory,18446744073709551615,const cc::TaskCategory *>, base::JobDelegate*) [D:\0713\x64\release-native-7.44.0\cc\raster\categorized_worker_pool.cc : 550 + 0xc]
    rbx = 0x0000721c00232e48   rsi = 0x0000000000000002
    rdi = 0x0000000000000000   rbp = 0x0000721c00232c00
    rsp = 0x000000f4d7fff010   r12 = 0x000000f4d7fff160
    r13 = 0x0000721c00232e20   r14 = 0x0000721c00232e18
    r15 = 0x0000721c00232e30   rip = 0x00007ffd99f0c5b1
    Found by: call frame info



Yuki Shiino

unread,
Jun 13, 2025, 1:04:52 AMJun 13
to weicong yu, memory-dev, memory-s...@chromium.org

2025年6月12日(木) 12:51 weicong yu <yuweic...@gmail.com>:
--
You received this message because you are subscribed to the Google Groups "memory-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to memory-dev+...@chromium.org.
To view this discussion visit https://groups.google.com/a/chromium.org/d/msgid/memory-dev/84c73510-872a-45e6-ac8c-0f5afba0c7bfn%40chromium.org.

Stephen Nusko

unread,
Jun 13, 2025, 2:58:43 AMJun 13
to Yuki Shiino, weicong yu, memory-dev, memory-s...@chromium.org
I think at first glance it probably makes sense to reconfigure it so it always calls the callback. Doing some code search history it appears that historically there were two different TerminateBecauseOutOfMemory one in base and one in PartitionAlloc, and eventually as PartitionAlloc became the default the base one was made an alias of PartitionAlloc in (crrev.com/c/3635217), but it appears that RunPartitionAllocOomCallback is called only from OnNoMemory (or similar functions) which called both RunPartitionAllocOomCallback and TerminateBecauseOutOfMemory so all callers in base triggering OOMs don't by default trigger RunPartitionAllocOomCallback

In summary OnNoMemory  always triggers callbacks and TerminateBecauseOutOfMemory never does. OnNoMemory is in the partition_alloc::internal so effectively this callback is called ONLY when partition_alloc itself thinks an OOM has occurred.

I'm not sure that is a useful distinction, especially since there seems to be places where PartitionAlloc itself in the shim layer calls TerminateBecauseOutOfMemory and not OnNoMemory which seems to be unfortunate for consistency.  I think it would be an easy change to move RunPartitionAllocOomCallback into OnNoMemoryInternal which both paths call and then everything would trigger the callback.

Does anyone know of a case where we want to differentiate between PartitionAlloc internal's determination of OOM versus other callers? I might lack historical context so I would suggest uploading a patch and seeing if any CQ bots fail, but not sure how many OOM tests we have though.

Cheers,
Stephen

You received this message because you are subscribed to the Google Groups "memory-safety-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to memory-safety-...@chromium.org.
To view this discussion visit https://groups.google.com/a/chromium.org/d/msgid/memory-safety-dev/CAN0uC_QgD%3DZH2J3U15yqJjXtw_wrEe0vEcGCHY1YsVok%3DgDjNg%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages