Bug 149251 - IFrame contentWindow loses add/remove eventListener methods when its not in the DOM
Summary: IFrame contentWindow loses add/remove eventListener methods when its not in t...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore JavaScript (show other bugs)
Version: Safari 8
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-09-17 00:45 PDT by AmazingJaze
Modified: 2015-09-17 22:29 PDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
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.