Thread: [Ieleak-commit] SF.net SVN: ieleak: [82] trunk/sieve/src/JSHook.cpp
Brought to you by:
matthiasmiller
From: <cor...@us...> - 2006-06-21 15:27:23
|
Revision: 82 Author: cordys-os Date: 2006-06-21 08:19:43 -0700 (Wed, 21 Jun 2006) ViewCVS: http://svn.sourceforge.net/ieleak/?rev=82&view=rev Log Message: ----------- Don't register nodes with type NODE_TEXT; They will never leak. The automatic rescan of objects added all nodetypes but the background clean-up was again deleteing all un-used nodes with refcount=0; Modified Paths: -------------- trunk/sieve/src/JSHook.cpp Modified: trunk/sieve/src/JSHook.cpp =================================================================== --- trunk/sieve/src/JSHook.cpp 2006-06-21 14:50:12 UTC (rev 81) +++ trunk/sieve/src/JSHook.cpp 2006-06-21 15:19:43 UTC (rev 82) @@ -217,6 +217,8 @@ // its current document. // void JSHook::addElement(MSHTML::IHTMLDOMNode* elem) { + if ( elem->nodeType == NODE_TEXT ) + return; // No need to register NODE_TEXT; They never leak; MSHTML::IHTMLDOMNode2Ptr node= elem; MSHTML::IHTMLDocument2Ptr doc = node->ownerDocument; MSHTML::IHTMLWindow2Ptr wnd = doc ? doc->parentWindow : NULL; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cor...@us...> - 2006-06-22 15:43:32
|
Revision: 84 Author: cordys-os Date: 2006-06-22 08:43:24 -0700 (Thu, 22 Jun 2006) ViewCVS: http://svn.sourceforge.net/ieleak/?rev=84&view=rev Log Message: ----------- - fixed bug in hookElement - improved leak reporting (fixed bug in coloring) - added counting of leaks and hiddenElements due to 'clear in use' button - free nodeName when releasing an element Modified Paths: -------------- trunk/sieve/src/JSHook.cpp Modified: trunk/sieve/src/JSHook.cpp =================================================================== --- trunk/sieve/src/JSHook.cpp 2006-06-22 15:39:43 UTC (rev 83) +++ trunk/sieve/src/JSHook.cpp 2006-06-22 15:43:24 UTC (rev 84) @@ -259,7 +259,7 @@ cachedElem.docElem = docElem; } m_elements.insert(std::pair<IUnknown*,Elem>(unkElem,cachedElem)); - //hookNewElement(elem,doc); //???????? + hookNewElement(elem,doc); } else { @@ -276,29 +276,32 @@ void JSHook::hookNewElement(MSHTML::IHTMLDOMNodePtr elem, MSHTML::IHTMLDocument2Ptr doc ) { - // Create a parameter list containing the hook, then invoke the - // temporary function to attach it to the document. - // - VARIANT vHook; - VariantInit(&vHook); - vHook.vt = VT_DISPATCH; - vHook.pdispVal = elem; - this->AddRef(); + if ( elem->nodeType != NODE_TEXT ) + { + // Create a parameter list containing the hook, then invoke the + // temporary function to attach it to the document. + // + VARIANT vHook; + VariantInit(&vHook); + vHook.vt = VT_DISPATCH; + vHook.pdispVal = elem; + elem->AddRef(); - DISPPARAMS params; - memset(¶ms, 0, sizeof(DISPPARAMS)); - params.cArgs = 1; - params.rgvarg = &vHook; - - CComPtr<IDispatch> scriptObj = doc->Script; - - DISPID dispId; - OLECHAR *name = SysAllocString(L"__sIEve_overloadCloneNode"); - scriptObj->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &dispId); - SysFreeString(name); - scriptObj->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); - - VariantClear(&vHook); + DISPPARAMS params; + memset(¶ms, 0, sizeof(DISPPARAMS)); + params.cArgs = 1; + params.rgvarg = &vHook; + + CComPtr<IDispatch> scriptObj = doc->Script; + + DISPID dispId; + OLECHAR *name = SysAllocString(L"__sIEve_overloadCloneNode"); + scriptObj->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &dispId); + SysFreeString(name); + scriptObj->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + + VariantClear(&vHook); + } } // This method is called when a document is finished loading. It will hook the @@ -460,9 +463,9 @@ // Only show all leaks if ( !elem.docElem->running && refCount > 1) { - dlg->addElement(unk, &elem, refCount - 1, false, 0, elem.reported ); + dlg->addElement(unk, &elem, refCount - 1, false, 0, elem.leakReported ); + elem.leakReported = refCount - 1; } - elem.reported = refCount - 1; } else { @@ -493,9 +496,9 @@ // Only show all leaks if ( !elem.docElem->running && refCount > 1) { - dlg->addElement(unk, &elem, refCount - 1, false, 0, elem.reported ); + dlg->addElement(unk, &elem, refCount - 1, false, 0, elem.leakReported ); + elem.leakReported = refCount - 1; } - elem.reported = refCount - 1; } else { @@ -507,10 +510,52 @@ } } -// Returns true if the hook contains any elements. -// -bool JSHook::hasElements() { - return (m_elements.size() > 0); +void JSHook::countElements(MSHTML::IHTMLWindow2Ptr wnd, int& leakedItems, int& hiddenItems) { + // Free non-leaked nodes + // + leakedItems = 0; + hiddenItems = 0; + releaseExtraReferences(wnd); + + for (std::map<IUnknown*,Elem>::iterator it = m_elements.begin(); it != m_elements.end(); ++it) { + IUnknown *unk = it->first; + Elem &elem = it->second; + + unk->AddRef(); + int refCount = unk->Release(); + + // If any references (other than the one that we hold) are outstanding, then + // the element has been leaked. + // + + if ( !elem.docElem->running && refCount > 1) + { + leakedItems++; + } + if ( elem.hide || refCount <= 1 ) + { + hiddenItems++; + } + } + + for (std::map<IUnknown*,Elem>::iterator it = m_runningDocs.begin(); it != m_runningDocs.end(); ++it) { + IUnknown *unk = it->first; + Elem &elem = it->second; + + unk->AddRef(); + int refCount = unk->Release(); + + // If any references (other than the one that we hold) are outstanding, then + // the element has been leaked. + if ( !elem.docElem->running && refCount > 1) + { + leakedItems++; + } + if ( elem.hide || refCount <= 1 ) + { + hiddenItems++; + } + } } // Clear all unused elements and documents in the hook. @@ -591,7 +636,7 @@ // Ensure that all garbage collection is completed so that elements will // be released. // - wnd->execScript(L"window.CollectGarbage()", L"javascript"); + if ( wnd ) wnd->execScript(L"window.CollectGarbage()", L"javascript"); // Release extra references for all elements // @@ -622,7 +667,8 @@ int i = unk->Release(); if (i == 1) { // If this is the only outstanding reference, free it. - SysFreeString(node.url); + if ( node.url ) SysFreeString(node.url); + if ( node.nodeName ) SysFreeString(node.nodeName); VERIFY(unk->Release() == 0); m_itNextNode = m_elements.erase(m_itNextNode); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cor...@us...> - 2006-08-29 10:35:46
|
Revision: 125 Author: cordys-os Date: 2006-08-29 03:35:36 -0700 (Tue, 29 Aug 2006) ViewCVS: http://svn.sourceforge.net/ieleak/?rev=125&view=rev Log Message: ----------- Upload of all changes for sIEve-0.0.5: - Renamed Element to Node - Api change for addElement in LeakDlg. - Leak dialog doesn't longer hold references to elements shown in the dialog. - remove registration of #document and #window elements - Remove memory leaks in sIEve - Minor UI changes - Code cleanup - Notification of released nodes or detected leaks and cycles in open leak dialog Modified Paths: -------------- trunk/sieve/src/JSHook.cpp Modified: trunk/sieve/src/JSHook.cpp =================================================================== --- trunk/sieve/src/JSHook.cpp 2006-08-29 10:35:19 UTC (rev 124) +++ trunk/sieve/src/JSHook.cpp 2006-08-29 10:35:36 UTC (rev 125) @@ -6,13 +6,14 @@ #include "MainBrowserDlg.hpp" JSHook::JSHook() { - m_itNextNode = m_elements.begin(); + m_itNextNode = m_nodes.begin(); + m_leakDlg = NULL; } JSHook::~JSHook() { - // When the hook is destroyed, make sure all elements are released. + // When the hook is destroyed, make sure all nodes are released. // - clearElements(); + clearNodes(); } void JSHook::setMainBrowserDlg(CMainBrowserDlg* dlg) @@ -35,15 +36,15 @@ } STDMETHODIMP JSHook::GetIDsOfNames(REFIID iid, OLECHAR **names, UINT nameCount, LCID lcid, DISPID *dispIds) { - // members are 'logElement' and 'unloadWindow' and 'rescanForElements' + // members are 'logNode' and 'unloadWindow' and 'rescanForNodes' // bool failed = false; for (int i = 0; i < (int)nameCount; ++i) { - if (!wcscmp(names[i], L"logElement")) + if (!wcscmp(names[i], L"logNode")) dispIds[i] = 0; else if (!wcscmp(names[i], L"unloadWindow")) dispIds[i] = 1; - else if (!wcscmp(names[i], L"rescanForElements")) + else if (!wcscmp(names[i], L"rescanForNodes")) dispIds[i] = 2; else if (!wcscmp(names[i], L"logDetectedCycle")) dispIds[i] = 3; @@ -64,7 +65,7 @@ if ( dispId == 0 ) { - // logElement() takes one argument, elem + // logNode() takes one argument, elem // if (dispParams->cArgs != 1) return DISP_E_BADPARAMCOUNT; @@ -72,44 +73,30 @@ if (dispParams->rgvarg[0].vt != VT_DISPATCH) return DISP_E_BADVARTYPE; - // Get the element, and add the element to the list. + // Get the node, and add the node to the list. // - MSHTML::IHTMLDOMNodePtr elem = dispParams->rgvarg[0].pdispVal; - addElement(elem); + MSHTML::IHTMLDOMNodePtr node = dispParams->rgvarg[0].pdispVal; + addNode(node); return S_OK; } else if ( dispId == 1 ) { // unloadWindow MSHTML::IHTMLDocument2Ptr doc = dispParams->rgvarg[0].pdispVal; - Elem* docElem = getDocument(doc); - if ( docElem ) - { - unloadWindow(doc); - } - else - { - IUnknown *unkDoc; - doc->QueryInterface(IID_IUnknown, (void**)&unkDoc); - unkDoc->Release(); - - TCHAR msg[128]; - wsprintf(msg,L"Document not found %s unkptr = 0x%x trid=0x%x",doc->url,unkDoc, GetCurrentThreadId()); - AfxMessageBox(msg); - } + unloadWindow(doc); return S_OK; } else if ( dispId == 2 ) { - // rescanForElements + // rescanForNodes if (dispParams->cArgs == 1) { MSHTML::IHTMLDocument2Ptr doc = dispParams->rgvarg[0].pdispVal; - rescanForElements(doc); + rescanForNodes(doc); } else { - rescanForElements(NULL); + rescanForNodes(NULL); } return S_OK; } @@ -123,13 +110,13 @@ if (dispParams->rgvarg[0].vt != VT_DISPATCH) return DISP_E_BADVARTYPE; - // Get the element, and add the element to the list. + // Get the node, and add the node to the list. // - MSHTML::IHTMLDOMNodePtr elem = dispParams->rgvarg[0].pdispVal; - Elem* cachedElem = getElement(elem); - if ( cachedElem ) + MSHTML::IHTMLDOMNodePtr node = dispParams->rgvarg[0].pdispVal; + Elem* elem = getElement(node); + if ( elem ) { - cachedElem->cycleDetected = true; + elem->cycleDetected = true; } return S_OK; } @@ -137,184 +124,81 @@ return DISP_E_MEMBERNOTFOUND; } -static int docId = 0; - -Elem* JSHook::addDocument(MSHTML::IHTMLDocument2* doc, MSHTML::IHTMLWindow2* wnd) -{ - Elem* docElem = getDocument(doc); - if ( doc && ! docElem ) - { - BSTR nodeName = NULL; - BSTR url = NULL;//SysAllocString(doc->url); - IUnknown *unkDoc; - - doc->QueryInterface(IID_IUnknown, (void**)&unkDoc); - GetPropertyValueByName((CComQIPtr<IDispatchEx>)doc, L"nodeName", &nodeName); - if (!wnd || ! GetLibraryURL((CComQIPtr<IDispatchEx>)wnd, &url) ) // Cordys Specific test - { - url = SysAllocString(doc->url); - } - Elem cachedElem(url, nodeName); - cachedElem.docId = docId++; - m_runningDocs.insert(std::pair<IUnknown*,Elem>(unkDoc,cachedElem)); - // Don't unkDoc->Release() because reference is inserted in map; - - docElem = getDocument(doc); - docElem->docElem = docElem; // Point to itself; - } - return docElem; -} - -Elem* JSHook::getDocument(MSHTML::IHTMLDocument2* doc) -{ - if ( doc ) - { - IUnknown *unkDoc; - doc->QueryInterface(IID_IUnknown, (void**)&unkDoc); - std::map<IUnknown*,Elem>::iterator pair = m_runningDocs.find(unkDoc); - unkDoc->Release(); - - if ( pair == m_runningDocs.end() ) return NULL; - Elem& docElem = pair->second; - return &docElem; - } - return NULL; -} - -Elem* JSHook::addWindow(MSHTML::IHTMLDocument2* doc, MSHTML::IHTMLWindow2* wnd) -{ - Elem* docElem = getDocument(doc); - Elem* wndElem = getWindow(wnd); - if ( wnd && ! wndElem ) - { - IUnknown *unkWnd; - - wnd->QueryInterface(IID_IUnknown, (void**)&unkWnd); - BSTR nodeName = SysAllocString(L"#window"); - - Elem cachedElem(NULL, nodeName); - if ( docElem ) - { - cachedElem.docElem = docElem; - } - m_elements.insert(std::pair<IUnknown*,Elem>(unkWnd,cachedElem)); - // Don't unkWnd->Release() because reference is inserted in map; - wndElem = getWindow(wnd); - } - if ( wndElem ) - { - if ( wndElem->docElem != docElem ) - { - // 'window' objects are recycled; so the document 'ie docElem' can change ! - // Just reset the properties and deal with this window object as being a new object - TCHAR msg[256]; - wsprintf(msg,L"window doc changed: %s -> %s", wndElem->docElem->url, docElem->url); -// AfxMessageBox(msg); - wndElem->docElem = docElem; - wndElem->reported = 0; - wndElem->hide = false; - } - } - return wndElem; -} - - -Elem* JSHook::getWindow(MSHTML::IHTMLWindow2* wnd) -{ - if ( wnd ) - { - IUnknown *unkWnd; - wnd->QueryInterface(IID_IUnknown, (void**)&unkWnd); - std::map<IUnknown*,Elem>::iterator pair = m_elements.find(unkWnd); - unkWnd->Release(); - - if ( pair == m_elements.end() ) return NULL; - Elem& wndElem = pair->second; - return &wndElem; - } - return NULL; -} - -// Add an element to the hook's list. The element's URL will be retrieved from +// Add an node to the hook's list. The node's URL will be retrieved from // its current document. // -void JSHook::addElement(MSHTML::IHTMLDOMNode* elem) { - if ( elem->nodeType == NODE_TEXT ) +void JSHook::addNode(MSHTML::IHTMLDOMNode* node) { + + if ( node->nodeType == NODE_TEXT ) return; // No need to register NODE_TEXT; They never leak; - MSHTML::IHTMLDOMNode2Ptr node= elem; - MSHTML::IHTMLDocument2Ptr doc = node->ownerDocument; + MSHTML::IHTMLDOMNode2Ptr node2= node; + MSHTML::IHTMLDocument2Ptr doc = node2->ownerDocument; MSHTML::IHTMLWindow2Ptr wnd = doc ? doc->parentWindow : NULL; - // In order to ensure that we maintain a durable reference to the element (as + // In order to ensure that we maintain a durable reference to the node (as // opposed to a tear-off interface), we have to query for IUnknown. // - IUnknown* unkElem = NULL; - Elem* docElem = NULL; + IUnknown* unkNode = NULL; - // Do not register the element twice; doing so will cause it to be incorrectly reported as a leak. - // This happens when an element is created by createElement and is added to the DOM before the DOM + // Do not register the node twice; doing so will cause it to be incorrectly reported as a leak. + // This happens when an node is created by createElement and is added to the DOM before the DOM // is traversed. (Note that the createElement hook must be in place immediately in case the caller - // saves a references to the element and adds it to the DOM after the page is loaded.) + // saves a references to the node and adds it to the DOM after the page is loaded.) // - if ( elem ) elem->QueryInterface(IID_IUnknown, (void**)&unkElem); - if ( doc ) - { - docElem = addDocument(doc,wnd); - } + if ( node ) node->QueryInterface(IID_IUnknown, (void**)&unkNode); - if ( wnd ) + if ( unkNode ) { - addWindow(doc,wnd); - } - - if ( unkElem ) - { BSTR nodeName = NULL; - if (m_elements.find(unkElem) == m_elements.end()) + int docId = getDocumentId(doc); + + if (m_nodes.find(unkNode) == m_nodes.end()) { - GetPropertyValueByName((CComQIPtr<IDispatchEx>)elem, L"nodeName", &nodeName); + GetPropertyValueByName((CComQIPtr<IDispatchEx>)node, L"nodeName", &nodeName); if ( doc ) { - Elem cachedElem(NULL, nodeName); - if ( docElem ) + BSTR url = NULL; + if (!wnd || ! GetLibraryURL((CComQIPtr<IDispatchEx>)wnd, &url) ) // Cordys Specific test { - cachedElem.docElem = docElem; + url = SysAllocString(doc->url); } - m_elements.insert(std::pair<IUnknown*,Elem>(unkElem,cachedElem)); - hookNewElement(elem,doc); + Elem *cachedElem = new Elem(unkNode, url, nodeName); + cachedElem->docId = docId; + cachedElem->running = true; + m_nodes.insert(std::pair<IUnknown*,Elem*>(unkNode,cachedElem)); + hookNewNode(node,doc); } else { - Elem cachedElem(SysAllocString(L"N/A"), nodeName); - m_elements.insert(std::pair<IUnknown*,Elem>(unkElem,cachedElem)); + Elem* cachedElem = new Elem(unkNode, SysAllocString(L"N/A"), nodeName); + m_nodes.insert(std::pair<IUnknown*,Elem*>(unkNode,cachedElem)); } } else { - unkElem->Release(); + unkNode->Release(); } } } -Elem* JSHook::getElement(MSHTML::IHTMLDOMNodePtr elem) +Elem* JSHook::getElement(MSHTML::IHTMLDOMNodePtr node) { - if ( elem ) + if ( node ) { - IUnknown *unkElem; - elem->QueryInterface(IID_IUnknown, (void**)&unkElem); - std::map<IUnknown*,Elem>::iterator pair = m_elements.find(unkElem); - unkElem->Release(); + IUnknown *unkNode; + node->QueryInterface(IID_IUnknown, (void**)&unkNode); + std::map<IUnknown*,Elem*>::iterator pair = m_nodes.find(unkNode); + unkNode->Release(); - if ( pair == m_elements.end() ) return NULL; - Elem& cachedElem = pair->second; - return &cachedElem; + if ( pair == m_nodes.end() ) return NULL; + return pair->second; } return NULL; } -void JSHook::hookNewElement(MSHTML::IHTMLDOMNodePtr elem, MSHTML::IHTMLDocument2Ptr doc ) { +void JSHook::hookNewNode(MSHTML::IHTMLDOMNodePtr node, MSHTML::IHTMLDocument2Ptr doc ) { - if ( elem->nodeType != NODE_TEXT ) + if ( node->nodeType != NODE_TEXT ) { // Create a parameter list containing the hook, then invoke the // temporary function to attach it to the document. @@ -322,8 +206,8 @@ VARIANT vHook; VariantInit(&vHook); vHook.vt = VT_DISPATCH; - vHook.pdispVal = elem; - elem->AddRef(); + vHook.pdispVal = node; + node->AddRef(); DISPPARAMS params; memset(¶ms, 0, sizeof(DISPPARAMS)); @@ -347,35 +231,33 @@ int i = 0; TCHAR buttonTxt[50]; TCHAR oldButtonTxt[50]; + int docId = getDocumentId(doc); + if ( button ) button->GetWindowTextW(oldButtonTxt,50); - Elem* docElem = getDocument(doc); // Search for registered document - for (std::map<IUnknown*,Elem>::iterator it = m_elements.begin(); it != m_elements.end(); ++it) { - IUnknown *unk = it->first; - Elem& elem = it->second; + for (std::map<IUnknown*,Elem*>::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { + IUnknown *unkNode = it->first; + Elem* elem = it->second; - - MSHTML::IHTMLDOMNode2Ptr element = unk; - MSHTML::IHTMLDOMNodePtr node = unk; - - if ( element ) + MSHTML::IHTMLDOMNodePtr node = unkNode; + if ( node ) { - // If 'doc' is NULL then Scan all elements of all documents - // Otherwise only scan the elements of a specified doc; - if ( (doc == NULL || elem.docElem == docElem) && elem.docElem->running && node->nodeType != NODE_TEXT) + // If 'doc' is NULL then Scan all nodes of all documents + // Otherwise only scan the nodes of a specified doc; + if ( (doc == NULL || elem->docId == docId) && elem->running && node->nodeType != NODE_TEXT) { if ( button ) { wsprintf(buttonTxt,L"Scan: %d",++i); button->SetWindowTextW(buttonTxt); } - crossRefScanElement(node); + crossRefScanNode(node); } } } if ( button ) button->SetWindowTextW(oldButtonTxt); } -void JSHook::crossRefScanElement(MSHTML::IHTMLDOMNode2Ptr elem) +void JSHook::crossRefScanNode(MSHTML::IHTMLDOMNode2Ptr node) { // Create a parameter list containing the hook, then invoke the // temporary function to attach it to the document. @@ -383,8 +265,8 @@ VARIANT vHook; VariantInit(&vHook); vHook.vt = VT_DISPATCH; - vHook.pdispVal = elem; - elem->AddRef(); + vHook.pdispVal = node; + node->AddRef(); DISPPARAMS params; memset(¶ms, 0, sizeof(DISPPARAMS)); @@ -392,7 +274,7 @@ params.rgvarg = &vHook; - MSHTML::IHTMLDocument2Ptr doc = elem->ownerDocument; + MSHTML::IHTMLDocument2Ptr doc = node->ownerDocument; CComPtr<IDispatch> scriptObj = doc->Script; DISPID dispId; @@ -405,7 +287,7 @@ } // This method is called when a document is finished loading. It will hook the -// document's createElement() method, passing all dynamically-created elements +// document's createElement() method, passing all dynamically-created nodes // to the hook as they are created. // void JSHook::hookNewPage(MSHTML::IHTMLDocument2Ptr doc) { @@ -450,74 +332,99 @@ } } -// Add all elements recursively from a given root element. +// Add all nodes recursively from a given root node. // -void JSHook::addElementRecursively(MSHTML::IHTMLDOMNode* elem) { - addElement(elem); +void JSHook::addNodeRecursively(MSHTML::IHTMLDOMNode* node) { + addNode(node); - MSHTML::IHTMLDOMNodePtr node = elem; MSHTML::IHTMLDOMNodePtr child = node->firstChild; while (child) { - addElementRecursively(child); + addNodeRecursively(child); child = child->nextSibling; } } -// Add all elements within a window, starting with its document's body. +// Add all nodes within a window, starting with its document's body. // -void JSHook::addStaticElements(MSHTML::IHTMLDocument2Ptr doc) { +void JSHook::addStaticNodes(MSHTML::IHTMLDocument2Ptr doc) { MSHTML::IHTMLWindow2Ptr wnd = doc->parentWindow; if ( wcscmp(doc->url,L"about:blank") ) { MSHTML::IHTMLDocument3Ptr document = doc; MSHTML::IHTMLDOMNodePtr documentElementNode = document->documentElement; - addElementRecursively(documentElementNode); + addNodeRecursively(documentElementNode); } } void JSHook::unloadWindow(MSHTML::IHTMLDocument2Ptr doc) { - Elem* docElem = getDocument(doc); - if ( docElem ) + MSHTML::IHTMLWindow2Ptr wnd = doc->parentWindow; + int docId = getDocumentId(doc); + + rescanForNodes(doc); + if ( m_mainBrowserDlg->m_check_cycle_detection ) { - rescanForElements(doc); - if ( m_mainBrowserDlg->m_check_cycle_detection ) + crossRefScan(doc,(CButton*)(m_mainBrowserDlg->GetDlgItem(IDC_CROSSREF_SCAN))); + } + + std::map<IUnknown*,Elem*>::iterator it = m_nodes.begin(); + while (it != m_nodes.end()) + { + std::map<IUnknown*,Elem*>::iterator next = it; next++; // Save the next one. + Elem* elem = it->second; + if ( elem->docId == docId ) { + elem->running = false; + } + it = next; + } +} + +int JSHook::getDocumentId(MSHTML::IHTMLDocument2Ptr doc) +{ + BSTR __sieve_documentId = NULL; + int docId = 0; + if ( doc ) + { + MSHTML::IHTMLWindow2Ptr wnd = doc->parentWindow; + if ( GetPropertyValueByName((CComQIPtr<IDispatchEx>)wnd, L"__sieve_documentId", &__sieve_documentId) ) { - crossRefScan(doc,(CButton*)(m_mainBrowserDlg->GetDlgItem(IDC_CROSSREF_SCAN))); + docId = _wtoi(__sieve_documentId); + SysFreeString(__sieve_documentId); } - docElem->running = false; // Invalidate the running state } + return docId; } -void JSHook::rescanForElements(MSHTML::IHTMLDocument2Ptr doc) +void JSHook::rescanForNodes(MSHTML::IHTMLDocument2Ptr doc) { - Elem* docElem = getDocument(doc); // Search for registered document - std::map<IUnknown*,Elem>::iterator end = m_elements.end(); - for (std::map<IUnknown*,Elem>::iterator it = m_elements.begin(); it != end; ++it) { - IUnknown *unk = it->first; - MSHTML::IHTMLElementPtr element = unk; + int docId = getDocumentId(doc); - if ( element ) + std::map<IUnknown*,Elem*>::iterator end = m_nodes.end(); + for (std::map<IUnknown*,Elem*>::iterator it = m_nodes.begin(); it != end; ++it) { + IUnknown *unkNode = it->first; + MSHTML::IHTMLElementPtr node = unkNode; + + if ( node ) { - Elem& elem = it->second; + Elem* elem = it->second; - // If 'doc' is NULL then Scan all elements of all documents - // Otherwise only scan the elements of a specified doc; - if ( (doc == NULL || elem.docElem == docElem) && elem.docElem->running ) + // If 'doc' is NULL then Scan all nodes of all documents + // Otherwise only scan the nodes of a specified doc; + if ( (doc == NULL || elem->docId == docId) && elem->running ) { - unk->AddRef(); - int refCount = unk->Release(); + unkNode->AddRef(); + int refCount = unkNode->Release(); - // Only rescan the elements which are still in use (ie having references besides our own reference) + // Only rescan the nodes which are still in use (ie having references besides our own reference) if ( refCount > 1 ) { - // Only scan the elements without having a parent Element + // Only scan the nodes without having a parent Element (Not parent Node; because they will have a parentNode (the documentElement node will have the document as parentNode) // Otherwise all we do way too much redundant scanning - if ( element->parentElement == NULL ) + if ( node->parentElement == NULL ) { - MSHTML::IHTMLDOMNodePtr node = unk; - addElementRecursively(node); + MSHTML::IHTMLDOMNodePtr node = unkNode; + addNodeRecursively(node); } } else @@ -526,243 +433,162 @@ } } - MSHTML::IHTMLDocument2Ptr iFrameDoc = GetContentDocument((CComQIPtr<IDispatchEx>)element); + // Search for "contentWindow" property; In that case it is a "iframe" or "frame" node + MSHTML::IHTMLDocument2Ptr iFrameDoc = GetContentDocument((CComQIPtr<IDispatchEx>)node); if ( iFrameDoc ) { - MSHTML::IHTMLWindow2Ptr iFrameWnd = iFrameDoc ? iFrameDoc->parentWindow : NULL; - if ( getDocument(iFrameDoc) == NULL ) + // If it is an frame object then check if the document is already hooked; + // The reason to check again for 'unhooked' documents is that some documents are loaded + // in a synchroneous with document.write("..."); Thus not downloaded from a backend ! + // These documents will not fire the Event_NavigateComplete2Explorer + + int docId = getDocumentId(iFrameDoc); + if ( docId == 0 ) { -// AfxMessageBox(L"new IframeDoc found"); -// AfxMessageBox(iFrameDoc->url); - addDocument(iFrameDoc,iFrameWnd); - addStaticElements(iFrameDoc); + // Not yet hooked it is a new Document in an IFrame; hookNewPage(iFrameDoc); + addStaticNodes(iFrameDoc); } } } - else - { - // Document or window type - } } } size_t JSHook::getNodeCount() const { - return m_elements.size(); + return m_nodes.size(); } -// Collect all leaked elements, passing them to the specified leak dialog. +// Collect all leaked nodes, passing them to the specified leak dialog. // void JSHook::showLeaks(MSHTML::IHTMLWindow2Ptr wnd, CLeakDlg* dlg, bool showLeaks) { // Free non-leaked nodes // + m_leakDlg = dlg; releaseExtraReferences(wnd); - for (std::map<IUnknown*,Elem>::iterator it = m_elements.begin(); it != m_elements.end(); ++it) { - IUnknown *unk = it->first; - Elem &elem = it->second; + for (std::map<IUnknown*,Elem*>::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { + IUnknown *unkNode = it->first; + Elem* elem = it->second; - // For each element, AddRef() and Release() it. The latter method will return + // For each node, AddRef() and Release() it. The latter method will return // the current ref count. // - unk->AddRef(); - int refCount = unk->Release(); + unkNode->AddRef(); + int refCount = unkNode->Release(); + elem->refCountSample = refCount -1; // Sample taken just before reporting in the leakDlg (excluding our own reference) // If any references (other than the one that we hold) are outstanding, then - // the element has been leaked. + // the node has been leaked. // if ( showLeaks ) { // Only show all leaks (And thus also the detected cycles) - if ( (!elem.docElem->running && refCount > 1) || elem.cycleDetected ) + if ( (!elem->running && refCount > 1) || elem->cycleDetected ) { - dlg->addElement(unk, &elem, refCount - 1, false, 0, elem.leakReported ); - elem.leakReported = refCount - 1; + dlg->addElement(elem); } } else { - // Show elements in use together with leaks - if ( (refCount - 1) > elem.reported ) elem.hide = false; - if ( refCount > 1 && ! elem.hide ) - dlg->addElement(unk, &elem, refCount - 1, false, 0, elem.reported ); - elem.reported = refCount - 1; + // Show nodes in use together with leaks + if ( (refCount - 1) > elem->reported ) elem->hide = false; + if ( refCount > 1 && ! elem->hide ) + dlg->addElement(elem); } } - - for (std::map<IUnknown*,Elem>::iterator it = m_runningDocs.begin(); it != m_runningDocs.end(); ++it) { - IUnknown *unk = it->first; - Elem &elem = it->second; - - // For each element, AddRef() and Release() it. The latter method will return - // the current ref count. - // - unk->AddRef(); - int refCount = unk->Release(); - - // If any references (other than the one that we hold) are outstanding, then - // the element has been leaked. - // - - if ( showLeaks ) - { - // Only show all leaks - if ( !elem.docElem->running && refCount > 1) - { - dlg->addElement(unk, &elem, refCount - 1, false, 0, elem.leakReported ); - elem.leakReported = refCount - 1; - } - } - else - { - if ( (refCount - 1) > elem.reported ) elem.hide = false; - if ( refCount > 1 && ! elem.hide ) - dlg->addElement(unk, &elem, refCount - 1, false, 0, elem.reported ); - elem.reported = refCount - 1; - } - } } -void JSHook::countElements(MSHTML::IHTMLWindow2Ptr wnd, int& leakedItems, int& hiddenItems) { +void JSHook::countNodes(MSHTML::IHTMLWindow2Ptr wnd, int& leakedItems, int& hiddenItems) { // Free non-leaked nodes // leakedItems = 0; hiddenItems = 0; releaseExtraReferences(wnd); - for (std::map<IUnknown*,Elem>::iterator it = m_elements.begin(); it != m_elements.end(); ++it) { - IUnknown *unk = it->first; - Elem &elem = it->second; + for (std::map<IUnknown*,Elem*>::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { + IUnknown *unkNode = it->first; + Elem* elem = it->second; - unk->AddRef(); - int refCount = unk->Release(); + unkNode->AddRef(); + int refCount = unkNode->Release(); // If any references (other than the one that we hold) are outstanding, then - // the element has been leaked. + // the node has been leaked. // OR if we detected a cycle - if ( (!elem.docElem->running && refCount > 1) || elem.cycleDetected ) + if ( (!elem->running && refCount > 1) || elem->cycleDetected ) { leakedItems++; } - if ( elem.hide || refCount <= 1 ) + if ( elem->hide || refCount <= 1 ) { hiddenItems++; } } - - for (std::map<IUnknown*,Elem>::iterator it = m_runningDocs.begin(); it != m_runningDocs.end(); ++it) { - IUnknown *unk = it->first; - Elem &elem = it->second; - - unk->AddRef(); - int refCount = unk->Release(); - - // If any references (other than the one that we hold) are outstanding, then - // the element has been leaked. - if ( !elem.docElem->running && refCount > 1) - { - leakedItems++; - } - if ( elem.hide || refCount <= 1 ) - { - hiddenItems++; - } - } } -// Clear all unused elements and documents in the hook. +// Clear all unused nodes and documents in the hook. // -void JSHook::clearElements() { - // Clear unused elements +void JSHook::clearNodes() { + // Clear unused nodes - std::map<IUnknown*,Elem>::iterator it = m_elements.begin(); - while (it != m_elements.end()) + std::map<IUnknown*,Elem*>::iterator it = m_nodes.begin(); + while (it != m_nodes.end()) { - std::map<IUnknown*,Elem>::iterator next = it; next++; // Save the next one. - IUnknown *unk = it->first; - unk->AddRef(); - int refCount = unk->Release(); + std::map<IUnknown*,Elem*>::iterator next = it; next++; // Save the next one. + IUnknown *unkNode = it->first; + unkNode->AddRef(); + int refCount = unkNode->Release(); - Elem& elem = it->second; - elem.hide = true; // Hide the element for the user interface - elem.reported = refCount - 1; // reported counter at the moment element is hidden. If recFount increases Element will be showed again - if ( ! elem.docElem->running ) + Elem* elem = it->second; + elem->hide = true; // Hide the node for the user interface + elem->reported = refCount - 1; // reported counter at the moment node is hidden. If recFount increases Node will be showed again + if ( ! elem->running ) { - // Only erase the elements which are not longer in use (ie having references besides our own reference) + // Only erase the nodes which are not longer in use (ie having references besides our own reference) if ( refCount == 1 ) { - if ( elem.url ) SysFreeString(elem.url); - if ( elem.nodeName ) SysFreeString(elem.nodeName); - m_elements.erase(it); - unk->Release(); // Relase our own reference + // If this is the only outstanding reference, free it. + delete elem; + m_nodes.erase(it); + VERIFY(unkNode->Release() == 0); // Relase our own reference } - else - { - elem.docElem->documentHasLeaks = true; // Protect docElem from normal cleanUp; - } } it = next; } - - // Clear unused documents - it = m_runningDocs.begin(); - while (it != m_runningDocs.end()) - { - std::map<IUnknown*,Elem>::iterator next = it; next++; // Save the next one. - IUnknown *unk = it->first; - unk->AddRef(); - int refCount = unk->Release(); - - Elem& elem = it->second; - elem.hide = true; // Hide the element for the user interface - elem.reported = refCount - 1; // reported counter at the moment element is hidden. If recFount increases Element will be showed again - if ( ! elem.docElem->running && ! elem.docElem->documentHasLeaks ) - { - // Only erase the elements which are not longer in use (ie having references besides our own reference) - if ( refCount == 1 ) - { - if ( elem.url ) SysFreeString(elem.url); - if ( elem.nodeName ) SysFreeString(elem.nodeName); - m_runningDocs.erase(it->first); - unk->Release(); - } - } - it = next; - } - // It is very important to update m_itNextNode whenever items are removed from the nodes list // - m_itNextNode = m_elements.begin(); + m_nodes.clear(); + m_itNextNode = m_nodes.begin(); } -// Free up any non-leaked elements +// Free up any non-leaked nodes // void JSHook::releaseExtraReferences(MSHTML::IHTMLWindow2Ptr wnd) { - // Make as many passes as necessary to clean up elements. Some elements such + // Make as many passes as necessary to clean up nodes. Some nodes such // as hidden table cells may not be cleaned up on the first pass. // size_t count = 0; - while (count != m_elements.size()) { - count = m_elements.size(); + while (count != m_nodes.size()) { + count = m_nodes.size(); - // Ensure that all garbage collection is completed so that elements will + // Ensure that all garbage collection is completed so that nodes will // be released. // if ( wnd ) wnd->execScript(L"window.CollectGarbage()", L"javascript"); - // Release extra references for all elements + // Release extra references for all nodes // - m_itNextNode = m_elements.begin(); - while (m_itNextNode != m_elements.end()) + m_itNextNode = m_nodes.begin(); + while (m_itNextNode != m_nodes.end()) backgroundReleaseExtraReferences(); } } void JSHook::backgroundReleaseExtraReferences() { - if (m_itNextNode == m_elements.end()) { - if (m_itNextNode == m_elements.begin()) { + if (m_itNextNode == m_nodes.end()) { + if (m_itNextNode == m_nodes.begin()) { // There are no nodes to collect. // return; @@ -770,23 +596,30 @@ else { // Restart the garbage collection // - m_itNextNode = m_elements.begin(); + m_itNextNode = m_nodes.begin(); } } - IUnknown *unk = m_itNextNode->first; - Elem const& node = m_itNextNode->second; + IUnknown *unkNode = m_itNextNode->first; + Elem* elem = m_itNextNode->second; - unk->AddRef(); - int i = unk->Release(); - if (i == 1) { + unkNode->AddRef(); + int refCount = unkNode->Release(); + elem->refCountSample = refCount - 1; + if (refCount == 1) { // If this is the only outstanding reference, free it. - if ( node.url ) SysFreeString(node.url); - if ( node.nodeName ) SysFreeString(node.nodeName); - VERIFY(unk->Release() == 0); - m_itNextNode = m_elements.erase(m_itNextNode); + if ( m_leakDlg ) m_leakDlg->notifyElement(elem); // To update the dialog + delete elem; + VERIFY(unkNode->Release() == 0); + m_itNextNode = m_nodes.erase(m_itNextNode); } else { + if ( m_leakDlg && (!elem->running || elem->cycleDetected) && (!elem->leakReported || elem->reported != elem->refCountSample) ) + { + // There is a new detected leak or cycle which is not yet reported. + // It is necessary to inform the user about the leak ASAP. + m_leakDlg->notifyElement(elem); + } m_itNextNode++; } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cor...@us...> - 2006-09-14 11:48:51
|
Revision: 142 http://svn.sourceforge.net/ieleak/?rev=142&view=rev Author: cordys-os Date: 2006-09-14 04:48:42 -0700 (Thu, 14 Sep 2006) Log Message: ----------- - The 'Clear in Use' button was not working poperly. It was clearing the whole m_nodes list in stead of only hiding the elements from the UI. The rescan for new nodes was not working after pressing the 'Clear in Use' button. Although nodes will be hided from the UI after pressing this button new nodes (For example new child nodes from hidden nodes) should be detected. The 'releaseExtraReferences()' already takes care of clearing the m_nodes list if nodes are freed by IE. Modified Paths: -------------- trunk/sieve/src/JSHook.cpp Modified: trunk/sieve/src/JSHook.cpp =================================================================== --- trunk/sieve/src/JSHook.cpp 2006-09-13 09:22:22 UTC (rev 141) +++ trunk/sieve/src/JSHook.cpp 2006-09-14 11:48:42 UTC (rev 142) @@ -597,11 +597,9 @@ } } -// Clear all unused nodes and documents in the hook. +// Hide all nodes for the UI (Show in Use Button clicked). // void JSHook::clearNodes() { - // Clear unused nodes - std::map<IUnknown*,Elem*>::iterator it = m_nodes.begin(); while (it != m_nodes.end()) { @@ -613,23 +611,8 @@ Elem* elem = it->second; elem->hide = true; // Hide the node for the user interface elem->reported = refCount - 1; // reported counter at the moment node is hidden. If recFount increases Node will be showed again - if ( ! elem->running ) - { - // Only erase the nodes which are not longer in use (ie having references besides our own reference) - if ( refCount == 1 ) - { - // If this is the only outstanding reference, free it. - delete elem; - m_nodes.erase(it); - VERIFY(unkNode->Release() == 0); // Relase our own reference - } - } it = next; } - // It is very important to update m_itNextNode whenever items are removed from the nodes list - // - m_nodes.clear(); - m_itNextNode = m_nodes.begin(); } // Free up any non-leaked nodes This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cor...@us...> - 2006-09-20 15:02:00
|
Revision: 150 http://svn.sourceforge.net/ieleak/?rev=150&view=rev Author: cordys-os Date: 2006-09-20 08:01:44 -0700 (Wed, 20 Sep 2006) Log Message: ----------- - Don't show cycles as a leak in the dialog before page is closed. (Cycles can become a leaks if not handled properly on page close) - Don't show leaks in the 'show in use' dialog anymore only show the leaks in the 'show leaks' dialog Modified Paths: -------------- trunk/sieve/src/JSHook.cpp Modified: trunk/sieve/src/JSHook.cpp =================================================================== --- trunk/sieve/src/JSHook.cpp 2006-09-20 15:00:06 UTC (rev 149) +++ trunk/sieve/src/JSHook.cpp 2006-09-20 15:01:44 UTC (rev 150) @@ -412,6 +412,7 @@ Elem* elem = it->second; if ( elem->docId == docId ) { elem->running = false; + elem->hide = true; } it = next; } @@ -552,16 +553,16 @@ if ( showLeaks ) { - // Only show all leaks (And thus also the detected cycles) - if ( (!elem->running && refCount > 1) || elem->cycleDetected ) + // Only show leaks + if ( !elem->running && refCount > 1 ) { dlg->addElement(elem); } } else { - // Show nodes in use together with leaks - if ( (refCount - 1) > elem->reported ) elem->hide = false; + // Show nodes in use + if ( elem->running && (refCount - 1) > elem->reported ) elem->hide = false; if ( refCount > 1 && ! elem->hide ) dlg->addElement(elem); } @@ -584,12 +585,12 @@ // If any references (other than the one that we hold) are outstanding, then // the node has been leaked. - // OR if we detected a cycle - if ( (!elem->running && refCount > 1) || elem->cycleDetected ) + if ( !elem->running && refCount > 1 ) { leakedItems++; } + if ( elem->hide || refCount <= 1 ) { hiddenItems++; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |