<html>
<head>
<base href="https://bugs.webkit.org/" />
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW - JSWrapperMap memory leak"
href="https://bugs.webkit.org/show_bug.cgi?id=165479">165479</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>JSWrapperMap memory leak
</td>
</tr>
<tr>
<th>Classification</th>
<td>Unclassified
</td>
</tr>
<tr>
<th>Product</th>
<td>WebKit
</td>
</tr>
<tr>
<th>Version</th>
<td>Other
</td>
</tr>
<tr>
<th>Hardware</th>
<td>Unspecified
</td>
</tr>
<tr>
<th>OS</th>
<td>Unspecified
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>Normal
</td>
</tr>
<tr>
<th>Priority</th>
<td>P2
</td>
</tr>
<tr>
<th>Component</th>
<td>JavaScriptCore
</td>
</tr>
<tr>
<th>Assignee</th>
<td>webkit-unassigned@lists.webkit.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>daniel.zimmerman@me.com
</td>
</tr></table>
<p>
<div>
<pre>Created <span class=""><a href="attachment.cgi?id=296299" name="attach_296299" title="The xcodeproj containing an example set up where this issue occurs">attachment 296299</a> <a href="attachment.cgi?id=296299&action=edit" title="The xcodeproj containing an example set up where this issue occurs">[details]</a></span>
The xcodeproj containing an example set up where this issue occurs
m_cachedObjCWrappers grows without bound. Even though the JSValue are autoreleased, the map continues to grow as if they were still in existence. The issue appears to be with using a weak valued NSMapTable as described here: <a href="http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/">http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/</a>
This issue isn't always reproducible - it appears that theres some sort of timing needed to somehow trick the NSMapTable to not resize at the proper time. I ran the app through the leak instrument and it claimed there were "no leaks" and indeed inspecting the live objects nothing appears to be leaking, but NSMapTable appears to continue to grow without bound for some reason (if you look at the logged `count` then you'll see that the count grows very large and then resets back down to a very small number every time the map table is resized, however this doesn't happen often enough so the map table is forced to grow unnecessarily). This does seem like a map table issue, however I think temporarily a fix can be found for JSC.
My proposed solution is to change `m_cachedObjCWrappers` to a `std::unordered_map<JSValueRef, JSValue*>` or whatever equivalent exists in WTF (I'm not very familiar with WTF) and then create a lightweight objc wrapper around JSValueRef that's then associated with the JSValue* and removes the entry in `m_cachedObjCWrappers` when `-dealloc` is called. E.g. the wrapper would look like
```
@interface JSValueRefCacheClearer : NSObject
- (instancetype)initWithValue:(JSValueRef)value;
@end
@implementation JSValueRefCacheClearer {
JSValueRef _value;
}
- (instancetype)initWithValue:(JSValueRef)value {
if ((self = [super init]) != nil) {
_value = value;
}
return self;
}
- (void)dealloc {
m_cachedObjCWrappers.remove(_value);
[super dealloc];
}
@end
```
And then `-[JSWrapperMap objcWrapperForJSValueRef:]` would change to
```
- (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value {
JSValue *wrapper = m_cachedObjCWrappers[value];
if (!wrapper) {
wrapper = [[[JSValue alloc] initWithValue:value inContext:m_context] autorelease];
m_cachedObjCWrappers[value] = wrapper;
JSValueRefCacheClearer *clearer = [[JSValueRefCacheClearer alloc] initWithValue:value];
objc_setAssociatedObject(wrapper, static_cast<void *>(clearer), clearer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// we pass ownership over to the wrapper
[clearer release];
}
return wrapper;
}
```
I'll gladly create the patch myself (following <a href="https://webkit.org/contributing-code/">https://webkit.org/contributing-code/</a>) as long as the bug is accepted as in fact a bug and the proposed change seems reasonable (albeit, it does feel a bit hacky).</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are the assignee for the bug.</li>
</ul>
</body>
</html>