diff options
author | Michael Stahl <michael.stahl@allotropia.de> | 2023-06-12 20:03:14 +0200 |
---|---|---|
committer | Michael Stahl <michael.stahl@allotropia.de> | 2023-06-13 16:06:59 +0200 |
commit | ac1099443e70eefbd8fdd7dd3705fff08a9c75b8 (patch) | |
tree | 8ee752d9de435342e00009c93c3f2f0d2599a265 /winaccessibility/source/service/AccObjectWinManager.cxx | |
parent | cbb215aa20783523555185c83875ea5d5b94535b (diff) |
tdf#155794 winaccessibility: no SolarMutex in getAccObjectPtr()
MSAAServiceImpl::getAccObjectPtr() is called when processing
WM_GETOBJECT messages, and this can happen (at least when NVDA is
active) during processing SendMessages.
When loading a document on a non-main thread, WinSalFrame::SetTitle()
calls SetWindowTextW which is equivalent to SendMessage(WM_SETTEXT),
while holding SolarMutex, and if the main thread doesn't finish
processing it then that's a deadlock.
Introduce a new mutex in AccObjectWinManager and use it to guard the 2
members that getAccObjectPtr() reads, while keeping the rest of
winaccessibility with the SolarMutex, as the UNO services may be called
on any thread.
This fixes part of the problem, VCL also needs to stop using SolarMutex.
Change-Id: I6df5889fd76f59146b4b0b1e5f4513232f8ab867
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152957
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Diffstat (limited to 'winaccessibility/source/service/AccObjectWinManager.cxx')
-rw-r--r-- | winaccessibility/source/service/AccObjectWinManager.cxx | 167 |
1 files changed, 100 insertions, 67 deletions
diff --git a/winaccessibility/source/service/AccObjectWinManager.cxx b/winaccessibility/source/service/AccObjectWinManager.cxx index b0ee01525de9..c8e5c7ac936b 100644 --- a/winaccessibility/source/service/AccObjectWinManager.cxx +++ b/winaccessibility/source/service/AccObjectWinManager.cxx @@ -73,8 +73,12 @@ AccObjectWinManager::AccObjectWinManager( AccObjectManagerAgent* Agent ): */ AccObjectWinManager::~AccObjectWinManager() { - XIdAccList.clear(); - HwndXAcc.clear(); + { + std::scoped_lock l(m_Mutex); + + XIdAccList.clear(); + HwndXAcc.clear(); + } XResIdAccList.clear(); XHWNDDocList.clear(); } @@ -94,13 +98,7 @@ AccObjectWinManager::Get_ToATInterface(HWND hWnd, long lParam, WPARAM wParam) if(lParam == OBJID_CLIENT ) { - AccObject* topWindowAccObj = GetTopWindowAccObj(hWnd); - if(topWindowAccObj) - { - pRetIMAcc = topWindowAccObj->GetIMAccessible(); - if(pRetIMAcc) - pRetIMAcc->AddRef();//increase COM reference count - } + pRetIMAcc = GetTopWindowIMAccessible(hWnd); } if ( pRetIMAcc && lParam == OBJID_CLIENT ) @@ -122,6 +120,8 @@ AccObject* AccObjectWinManager::GetAccObjByXAcc( XAccessible* pXAcc) if( pXAcc == nullptr) return nullptr; + std::scoped_lock l(m_Mutex); + XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( pXAcc ); if ( pIndTemp == XIdAccList.end() ) return nullptr; @@ -134,13 +134,26 @@ AccObject* AccObjectWinManager::GetAccObjByXAcc( XAccessible* pXAcc) * @param hWnd, top window handle * @return pointer to AccObject */ -AccObject* AccObjectWinManager::GetTopWindowAccObj(HWND hWnd) +IMAccessible * AccObjectWinManager::GetTopWindowIMAccessible(HWND hWnd) { + std::scoped_lock l(m_Mutex); // tdf#155794 for HwndXAcc and XIdAccList + XHWNDToXAccHash::iterator iterResult =HwndXAcc.find(hWnd); if(iterResult == HwndXAcc.end()) return nullptr; XAccessible* pXAcc = iterResult->second; - return GetAccObjByXAcc(pXAcc); + AccObject *const pAccObject(GetAccObjByXAcc(pXAcc)); + if (!pAccObject) + { + return nullptr; + } + IMAccessible *const pRet(pAccObject->GetIMAccessible()); + if (!pRet) + { + return nullptr; + } + pRet->AddRef(); + return pRet; } /** @@ -391,6 +404,8 @@ void AccObjectWinManager::DeleteAccChildNode( AccObject* pObj ) */ void AccObjectWinManager::DeleteFromHwndXAcc(XAccessible const * pXAcc ) { + std::scoped_lock l(m_Mutex); + auto iter = std::find_if(HwndXAcc.begin(), HwndXAcc.end(), [&pXAcc](XHWNDToXAccHash::value_type& rEntry) { return rEntry.second == pXAcc; }); if (iter != HwndXAcc.end()) @@ -433,35 +448,47 @@ void AccObjectWinManager::DeleteAccObj( XAccessible* pXAcc ) { if( pXAcc == nullptr ) return; - XIdToAccObjHash::iterator temp = XIdAccList.find(pXAcc); - if( temp != XIdAccList.end() ) - { - ResIdGen.SetSub( temp->second.GetResID() ); - } - else - { - return; - } - AccObject& accObj = temp->second; - DeleteAccChildNode( &accObj ); - DeleteAccListener( &accObj ); - if( accObj.GetIMAccessible() ) + rtl::Reference<AccEventListener> pListener; + { - accObj.GetIMAccessible()->Release(); + std::scoped_lock l(m_Mutex); + + XIdToAccObjHash::iterator temp = XIdAccList.find(pXAcc); + if( temp != XIdAccList.end() ) + { + ResIdGen.SetSub( temp->second.GetResID() ); + } + else + { + return; + } + + AccObject& accObj = temp->second; + DeleteAccChildNode( &accObj ); + pListener = DeleteAccListener(&accObj); + accObj.NotifyDestroy(); + if( accObj.GetIMAccessible() ) + { + accObj.GetIMAccessible()->Release(); + } + size_t i = XResIdAccList.erase(accObj.GetResID()); + assert(i != 0); + (void) i; + DeleteFromHwndXAcc(pXAcc); + if (accObj.GetRole() == AccessibleRole::DOCUMENT || + accObj.GetRole() == AccessibleRole::DOCUMENT_PRESENTATION || + accObj.GetRole() == AccessibleRole::DOCUMENT_SPREADSHEET || + accObj.GetRole() == AccessibleRole::DOCUMENT_TEXT) + { + XHWNDDocList.erase(accObj.GetParentHWND()); + } + XIdAccList.erase(pXAcc); // note: this invalidates accObj so do it last! } - size_t i = XResIdAccList.erase(accObj.GetResID()); - assert(i != 0); - (void) i; - DeleteFromHwndXAcc(pXAcc); - if (accObj.GetRole() == AccessibleRole::DOCUMENT || - accObj.GetRole() == AccessibleRole::DOCUMENT_PRESENTATION || - accObj.GetRole() == AccessibleRole::DOCUMENT_SPREADSHEET || - accObj.GetRole() == AccessibleRole::DOCUMENT_TEXT) + if (pListener) { - XHWNDDocList.erase(accObj.GetParentHWND()); + pListener->RemoveMeFromBroadcaster(false); } - XIdAccList.erase(pXAcc); // note: this invalidates accObj so do it last! } /** @@ -469,13 +496,9 @@ void AccObjectWinManager::DeleteAccObj( XAccessible* pXAcc ) * @param pAccObj Accobject pointer. * @return */ -void AccObjectWinManager::DeleteAccListener( AccObject* pAccObj ) +rtl::Reference<AccEventListener> AccObjectWinManager::DeleteAccListener( AccObject* pAccObj ) { - AccEventListener* listener = pAccObj->getListener(); - if( listener==nullptr ) - return; - listener->RemoveMeFromBroadcaster(); - pAccObj->SetListener(nullptr); + return pAccObj->SetListener(nullptr); } /** @@ -568,29 +591,6 @@ void AccObjectWinManager::InsertAccChildNode( AccObject* pCurObj, AccObject* pPa */ bool AccObjectWinManager::InsertAccObj( XAccessible* pXAcc,XAccessible* pParentXAcc,HWND pWnd ) { - XIdToAccObjHash::iterator itXacc = XIdAccList.find( pXAcc ); - if (itXacc != XIdAccList.end() ) - { - short nCurRole =GetRole(pXAcc); - if (AccessibleRole::SHAPE == nCurRole) - { - AccObject &objXacc = itXacc->second; - AccObject *pObjParent = objXacc.GetParentObj(); - if (pObjParent && - pObjParent->GetXAccessible().is() && - pObjParent->GetXAccessible().get() != pParentXAcc) - { - XIdToAccObjHash::iterator itXaccParent = XIdAccList.find( pParentXAcc ); - if(itXaccParent != XIdAccList.end()) - { - objXacc.SetParentObj(&(itXaccParent->second)); - } - } - } - return false; - } - - Reference< XAccessibleContext > pRContext; if( pXAcc == nullptr) @@ -600,6 +600,33 @@ bool AccObjectWinManager::InsertAccObj( XAccessible* pXAcc,XAccessible* pParentX if( !pRContext.is() ) return false; + { + short nCurRole = GetRole(pXAcc); + + std::scoped_lock l(m_Mutex); + + XIdToAccObjHash::iterator itXacc = XIdAccList.find( pXAcc ); + if (itXacc != XIdAccList.end() ) + { + if (AccessibleRole::SHAPE == nCurRole) + { + AccObject &objXacc = itXacc->second; + AccObject *pObjParent = objXacc.GetParentObj(); + if (pObjParent && + pObjParent->GetXAccessible().is() && + pObjParent->GetXAccessible().get() != pParentXAcc) + { + XIdToAccObjHash::iterator itXaccParent = XIdAccList.find( pParentXAcc ); + if(itXaccParent != XIdAccList.end()) + { + objXacc.SetParentObj(&(itXaccParent->second)); + } + } + } + return false; + } + } + if( pWnd == nullptr ) { if(pParentXAcc) @@ -647,9 +674,13 @@ bool AccObjectWinManager::InsertAccObj( XAccessible* pXAcc,XAccessible* pParentX else return false; - XIdAccList.emplace(pXAcc, pObj); - XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( pXAcc ); - XResIdAccList.emplace(pObj.GetResID(),&(pIndTemp->second)); + { + std::scoped_lock l(m_Mutex); + + XIdAccList.emplace(pXAcc, pObj); + XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( pXAcc ); + XResIdAccList.emplace(pObj.GetResID(),&(pIndTemp->second)); + } AccObject* pCurObj = GetAccObjByXAcc(pXAcc); if( pCurObj ) @@ -673,6 +704,8 @@ bool AccObjectWinManager::InsertAccObj( XAccessible* pXAcc,XAccessible* pParentX */ void AccObjectWinManager::SaveTopWindowHandle(HWND hWnd, css::accessibility::XAccessible* pXAcc) { + std::scoped_lock l(m_Mutex); + HwndXAcc.emplace(hWnd,pXAcc); } |