Bug 149251

Summary: IFrame contentWindow loses add/remove eventListener methods when its not in the DOM
Product: WebKit Reporter: AmazingJaze
Component: WebCore JavaScriptAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: ggaren
Priority: P2    
Version: Safari 8   
Hardware: Unspecified   
OS: Unspecified   

Description AmazingJaze 2015-09-17 00:45:55 PDT
Hello, 

I have found that on Safari and iOS, if I add a resize listener to the contentWindow of an Iframe, then I am unable to remove that listener if the Iframe is no longer in the DOM. I am concerned about memory leaks.

The Iframe contentWindow property returns null when it is not in the DOM and if I had previously stored a reference to the Iframe's contentWindow property before it was removed from the 
DOM, checking that reference while the iframe is not in the DOM returns a Window object that is missing all the methods from its prototype chain, such as addEventListener and removeEventListener.

I am writing a UI control that creates and uses an Iframe and its "resize" event. I try to unregister my resize listener on the Iframe contentWindow whenever a user calls my control's dispose() API, but there is no way to guarantee that the control is still in the DOM when this happens, and if its not in the DOM, an exception is thrown.

Below is a very simple repro. This does not Repro in Chrome, IE, Edge, FF, or Android browser.


                var iframe = document.createElement("IFRAME");
                var referenceToContentWindow;
                document.body.appendChild(iframe);
                setTimeout(function () {
                    
                    referenceToContentWindow = iframe.contentWindow;


                    // Evaluates to True
                    !!iframe.contentWindow.removeEventListener


                    // Evaluates to True
                    !!referenceToContentWindow.removeEventListener

                    document.body.removeChild(iframe);
                    setTimeout(function () {

                    // Throws Exception, contentWindow is null 
                    !!iframe.contentWindow.removeEventListener


                    // Evaluates to False, referenceToContentWindow is type Window, but it no longer has the function.
                    !!referenceToContentWindow.removeEventListener


                    }, 100);
                }, 100);


As a work around I tried calling: 
Object.getPrototypeOf(referenceToContentWindow).removeEventListener.call(referenceToContentWindow, "resize", boundResizeHandler); 

And while that executes without throwing a DOM exception, it doesn't actually remove the handler, as it will still fire if I re-append the iframe and resize it, but running the above line while the Iframe is already in the DOM, will remove the event listener.