Bug 233206 - [JSC] indirect eval GC/memory leak
Summary: [JSC] indirect eval GC/memory leak
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
Keywords: InRadar
Depends on:
Reported: 2021-11-16 11:42 PST by Phillip Mates
Modified: 2021-11-23 11:42 PST (History)
5 users (show)

See Also:


Note You need to log in before you can comment on or make changes to this bug.
Description Phillip Mates 2021-11-16 11:42:01 PST
While working on the Shadow Realm implementation in JSC I noticed some OOM issues related to indirect eval.

I was able to reproduce them with the following `example.js` snippet:

for (i = 0; i<50000; i++) {
    // indirect eval: has issues
    let f = (0, eval)("{x: " + Math.random() + "}"); 

    // direct eval: is fine
    // let f = eval("{x: " + Math.random() + "}");   

    // filler to prevent optimizing anything away                                                                             
    if (f.x === 0.1) {

    // issue persist even when GC is called after each allocation                                                                                                                


running this snippet in the jsc console with llint disabled results in a out-of-memory crash

$ Tools/Scripts/run-jsc --jsc-only --debug --useLLInt=false --logExecutableAllocation=1 --gcMaxHeapSize=1024 --jitMemoryReservationSize=102400 examples.js

Allocating 896 bytes of executable memory with 101248 bytes allocated, 102400 bytes reserved, and 102400 committed.
Allocating 896 bytes of executable memory with 102144 bytes allocated, 102400 bytes reserved, and 102400 committed.
Ran out of executable memory while allocating 896 bytes.
[1]    26356 abort (core dumped)  Tools/Scripts/run-jsc --jsc-only --debug --useLLInt=false
Comment 1 Joseph Griego 2021-11-16 13:34:07 PST
(poked around a bit and confirmed that adding `--useCodeCache=false` prevents the crash as long as `jitMemoryReservationSize` is large enough to hold at least one instance of the eval'd code, still reading code though)
Comment 2 Phillip Mates 2021-11-17 10:15:36 PST
I change `prune` in runtime/CodeCache.h to just be `m_map.clear()` and it stops crashing. Given this, I believe that the pruning/flushing to disk logic that clears the code cache map, and thus allows for releasing otherwise gc'able executable objects, isn't sensitive to GC/memory needs.

Not sure what the best way forward would be. Some random ideas:
 - use some sort of weak hashmap that allowed for gc'ing objects even if they appear in the code cache map. 
 - couple code cache map with the executable allocator and allow the allocator to clear the map. 
 - tweak the code cache heuristics, such as the workingSetMaxBytes parameter
Comment 3 Radar WebKit Bug Importer 2021-11-23 11:42:21 PST