vcl/win/dtrans/WinClipboard.cxx |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

New commits:
commit b3922a8d0051a656228f80aeee5360692c9bba2e
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Mon Jul 15 18:55:50 2024 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Mon Jul 15 19:14:31 2024 +0200

    Release the lock for getClipboard call to avoid deadlock
    
    The call stacks that deadlock in my testing:
    
    Thread A: CMtaOleClipboard::clipboardChangedNotifierThreadProc()
    
      win32u.dll!NtUserMsgWaitForMultipleObjectsEx()
      user32.dll!MsgWaitForMultipleObjects()
      vclplug_winlo.dll!`anonymous namespace'::Win32Condition::wait(void * 
hEvtAbort) Line 92 C++
      vclplug_winlo.dll!CMtaOleClipboard::getClipboard(IDataObject * * 
ppIDataObject) Line 353 C++
      vclplug_winlo.dll!CWinClipboard::getIDataObject() Line 158 C++
      vclplug_winlo.dll!CDOTransferable::tryToGetIDataObjectIfAbsent() Line 413 
C++
      vclplug_winlo.dll!CDOTransferable::getClipboardData(CFormatEtc & 
aFormatEtc) Line 426 C++
      vclplug_winlo.dll!CDOTransferable::getTransferData(const 
com::sun::star::datatransfer::DataFlavor & aFlavor) Line 252 C++
      vcllo.dll!TransferableDataHelper::GetAny(const 
com::sun::star::datatransfer::DataFlavor & rFlavor, const rtl::OUString & 
rDestDoc) Line 1484 C++
      vcllo.dll!TransferableDataHelper::GetSequence(const 
com::sun::star::datatransfer::DataFlavor & rFlavor, const rtl::OUString & 
rDestDoc) Line 2078 C++
      vcllo.dll!TransferableDataHelper::InitFormats() Line 1344 C++
      vcllo.dll!TransferableDataHelper::TransferableDataHelper(const 
com::sun::star::uno::Reference<com::sun::star::datatransfer::XTransferable> & 
rxTransferable) Line 1156 C++
      svtlo.dll!TransferableClipboardListener::changedContents(const 
com::sun::star::datatransfer::clipboard::ClipboardEvent & rEventObject) Line 52 
C++
      
vclplug_winlo.dll!comphelper::OInterfaceContainerHelper4<com::sun::star::datatransfer::clipboard::XClipboardListener>::NotifySingleListener<com::sun::star::datatransfer::clipboard::ClipboardEvent>::operator()(const
 
com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboardListener>
 & listener) Line 275 C++
      
vclplug_winlo.dll!comphelper::OInterfaceContainerHelper4<com::sun::star::datatransfer::clipboard::XClipboardListener>::forEach<comphelper::OInterfaceContainerHelper4<com::sun::star::datatransfer::clipboard::XClipboardListener>::NotifySingleListener<com::sun::star::datatransfer::clipboard::ClipboardEvent>>(std::unique_lock<std::mutex>
 & rGuard, const 
comphelper::OInterfaceContainerHelper4<com::sun::star::datatransfer::clipboard::XClipboardListener>::NotifySingleListener<com::sun::star::datatransfer::clipboard::ClipboardEvent>
 & func) Line 304 C++
      
vclplug_winlo.dll!comphelper::OInterfaceContainerHelper4<com::sun::star::datatransfer::clipboard::XClipboardListener>::notifyEach<com::sun::star::datatransfer::clipboard::ClipboardEvent>(std::unique_lock<std::mutex>
 & rGuard, 
void(com::sun::star::datatransfer::clipboard::XClipboardListener::*)(const 
com::sun::star::datatransfer::clipboard::ClipboardEvent &) NotificationMethod, 
const com::sun::star::datatransfer::clipboard::ClipboardEvent & Event) Line 327 
C++
      vclplug_winlo.dll!CWinClipboard::handleClipboardContentChanged() Line 302 
C++
      vclplug_winlo.dll!CWinClipboard::onClipboardContentChanged() Line 386 C++
      
vclplug_winlo.dll!CMtaOleClipboard::clipboardChangedNotifierThreadProc(void * 
pParam) Line 723 C++
      ucrtbased.dll!thread_start<unsigned int (__cdecl*)(void *),1>(void * 
const parameter) Line 97 C++
      kernel32.dll!BaseThreadInitThunk()
      ntdll.dll!RtlUserThreadStart()
    
    Thread B: CMtaOleClipboard::run()
    
      ntdll.dll!NtWaitForAlertByThreadId()
      ntdll.dll!RtlAcquireSRWLockExclusive()
      msvcp140d.dll!mtx_do_lock(_Mtx_internal_imp_t * mtx, const _timespec64 * 
target) Line 93 C++
      msvcp140d.dll!_Mtx_lock(_Mtx_internal_imp_t * mtx) Line 165 C++
      vclplug_winlo.dll!std::_Mutex_base::lock() Line 56 C++
      
vclplug_winlo.dll!std::unique_lock<std::mutex>::unique_lock<std::mutex>(std::mutex
 & _Mtx) Line 149 C++
      
vclplug_winlo.dll!CWinClipboard::onReleaseDataObject(CXNotifyingDataObject * 
theCaller) Line 363 C++
      vclplug_winlo.dll!CXNotifyingDataObject::Release() Line 77 C++
      combase.dll!CStdIdentity::ReleaseCtrlUnk::__l5::<lambda>() Line 1408 C++
      combase.dll!ObjectMethodExceptionHandlingAction<void 
<lambda>(void)>(CStdIdentity::ReleaseCtrlUnk::__l5::void <lambda>(void) action, 
ObjectMethodExceptionHandlingInfo * pExceptionHandlingInfo, 
ExceptionHandlingResult * pExceptionHandlingResult, void * __formal) Line 135 
C++
      combase.dll!CStdIdentity::ReleaseCtrlUnk(unsigned long dwDisconnectType) 
Line 1411 C++
      [Inline Frame] 
combase.dll!ObjectLibrary::ReferencedPtr<CObjectContext>::operator int 
ObjectLibrary::Details::BoolStruct::*() Line 1313 C++
      combase.dll!CStdMarshal::DisconnectWorker_ReleasesLock(unsigned long 
dwType, bool logEventIsActive, CObjectContext * explicitServerContext, bool 
performCallback, CIDObject * pIDDelayRelease) Line 4783 C++
      combase.dll!CStdMarshal::Disconnect(unsigned long dwType) Line 4452 C++
      [Inline Frame] combase.dll!CStdMarshal::HandlePendingDisconnect(HRESULT) 
Line 4285 C++
      combase.dll!CRemoteUnknown::RemReleaseWorker(unsigned short 
cInterfaceRefs, tagREMINTERFACEREF * InterfaceRefs, int fTopLevel) Line 1307 C++
      rpcrt4.dll!Invoke()
      rpcrt4.dll!Ndr64StubWorker()
      rpcrt4.dll!NdrStubCall3()
      combase.dll!CStdStubBuffer_Invoke(IRpcStubBuffer * This, tagRPCOLEMESSAGE 
* prpcmsg, IRpcChannelBuffer * pRpcChannelBuffer) Line 1479 C++
      [Inline Frame] 
combase.dll!InvokeStubWithExceptionPolicyAndTracing::__l6::<lambda_c9f3956a20c9da92a64affc24fdd69ec>::operator()()
 Line 1151 C++
      
combase.dll!ObjectMethodExceptionHandlingAction<<lambda_c9f3956a20c9da92a64affc24fdd69ec>>(InvokeStubWithExceptionPolicyAndTracing::__l6::<lambda_c9f3956a20c9da92a64affc24fdd69ec>
 action, ObjectMethodExceptionHandlingInfo * pExceptionHandlingInfo, 
ExceptionHandlingResult * pExceptionHandlingResult, void *) Line 94 C++
      [Inline Frame] 
combase.dll!InvokeStubWithExceptionPolicyAndTracing(IRpcStubBuffer * pMsg, 
tagRPCOLEMESSAGE *) Line 1149 C++
      combase.dll!DefaultStubInvoke(bool bIsAsyncBeginMethod, IServerCall * 
pServerCall, IRpcChannelBuffer * pChannel, IRpcStubBuffer * pStub, unsigned 
long * pdwFault) Line 1218 C++
      combase.dll!SyncServerCall::StubInvoke(IRpcChannelBuffer * pChannel, 
IRpcStubBuffer * pStub, unsigned long * pdwFault) Line 791 C++
      [Inline Frame] combase.dll!StubInvoke(tagRPCOLEMESSAGE * pMsg, const 
_GUID &) Line 1483 C++
      combase.dll!ServerCall::ContextInvoke(tagIPIDEntry * ipidEntry) Line 1421 
C++
      [Inline Frame] combase.dll!DefaultInvokeInApartment(ServerCall *) Line 
3257 C++
      combase.dll!ReentrantSTAInvokeInApartment(ServerCall * serverCall, 
tagIPIDEntry * ipidEntry) Line 110 C++
      combase.dll!ComInvokeWithLockAndIPID(ServerCall * pServerCall, 
tagIPIDEntry * pIPIDEntry) Line 2152 C++
      combase.dll!ThreadDispatch(ServerCall * pServerCall) Line 1637 C++
      combase.dll!ThreadWndProc(HWND__ * window, unsigned int message, unsigned 
__int64 wparam, __int64 params) Line 720 C++
      user32.dll!UserCallWinProcCheckWow()
      user32.dll!DispatchMessageWorker()
      [Inline Frame] combase.dll!CCliModalLoop::MyDispatchMessage(tagMSG *) 
Line 2959 C++
      combase.dll!CCliModalLoop::PeekRPCAndDDEMessage() Line 2563 C++
      combase.dll!CCliModalLoop::BlockFn(void * * ahEvent, unsigned long 
cEvents, unsigned long * lpdwSignaled) Line 2055 C++
      combase.dll!ModalLoop(CSyncClientCall * pClientCall) Line 169 C++
      [Inline Frame] combase.dll!ThreadSendReceive(tagRPCOLEMESSAGE *) Line 
7259 C++
      [Inline Frame] 
combase.dll!CSyncClientCall::SwitchAptAndDispatchCall(tagRPCOLEMESSAGE * 
pMessage) Line 5735 C++
      combase.dll!CSyncClientCall::SendReceive2(tagRPCOLEMESSAGE * pMessage, 
unsigned long * pstatus) Line 5297 C++
      
combase.dll!SyncClientCallRetryContext::SendReceiveWithRetry(tagRPCOLEMESSAGE * 
pMsg, unsigned long * pulStatus, ClientCall * pClientCall, bool * 
pbIsAutoRetry) Line 1502 C++
      
combase.dll!CSyncClientCall::SendReceiveInRetryContext(SyncClientCallRetryContext
 * pRetryContext, tagRPCOLEMESSAGE * pMsg, unsigned long * pulStatus) Line 582 
C++
      combase.dll!ClassicSTAThreadSendReceive(CSyncClientCall * pClientCall, 
tagRPCOLEMESSAGE * pMsg, unsigned long * pulStatus) Line 564 C++
      combase.dll!CSyncClientCall::SendReceive(tagRPCOLEMESSAGE * pMessage, 
unsigned long * pulStatus) Line 787 C++
      combase.dll!CClientChannel::SendReceive(tagRPCOLEMESSAGE * pMessage, 
unsigned long * pulStatus) Line 659 C++
      combase.dll!NdrExtpProxySendReceive(void * pThis, _MIDL_STUB_MESSAGE * 
pStubMsg) Line 1989 C++
      rpcrt4.dll!NdrpClientCall3()
      combase.dll!ObjectStublessClient(void * ParamAddress, __int64 * 
FloatRegisters, long Method) Line 366 C++
      combase.dll!ObjectStubless() Line 176
      combase.dll!CStdMarshal::RemoteAddRef(tagIPIDEntry * pIPIDEntry, 
OXIDEntry * pOXIDEntry, unsigned long cStrongNeed, unsigned long cSecureNeed, 
int fGiveToCaller) Line 8489 C++
      [Inline Frame] combase.dll!CStdMarshal::GetNeededRefs(tagSTDOBJREF *) 
Line 3654 C++
      combase.dll!CStdMarshal::ConnectCliIPIDEntry(tagSTDOBJREF * pStd, 
OXIDEntry * pOXIDEntry, tagIPIDEntry * pEntry) Line 3338 C++
      combase.dll!CStdMarshal::MakeCliIPIDEntry(const _GUID & riid, 
tagSTDOBJREF * pStd, OXIDEntry * pOXIDEntry, tagIPIDEntry * * ppEntry) Line 
3108 C++
      combase.dll!CStdMarshal::UnmarshalIPID(const _GUID & riid, tagSTDOBJREF * 
pStd, OXIDEntry * pOXIDEntry, void * * ppv) Line 2621 C++
      combase.dll!CStdMarshal::UnmarshalObjRef(tagOBJREF & objref, void * * 
ppv) Line 2479 C++
      combase.dll!UnmarshalSwitch(void * pv) Line 2112 C++
      combase.dll!UnmarshalObjRef(tagOBJREF & objref, 
EffectiveUnmarshalingPolicy policy, void * * ppv, int fBypassActLock, CBaseCall 
* callMarshalingContext, CStdMarshal * * ppStdMarshal) Line 2261 C++
      combase.dll!InternalGetWindowPropInterface2(HWND__ * hWnd, unsigned 
__int64 dwCookie, int fCallStrongNamedProcesses, const _GUID & iid, void * * 
ppv, int * pfLocal) Line 285 C++
      ole32.dll!UnmarshalFromEndpointProperty(HWND__ * hWnd, int fDragDrop, int 
fCallStrongNamedProcesses, IUnknown * * ppUnk, int * pfLocal) Line 407 C++
      ole32.dll!GetInterfaceFromWindowProp(HWND__ * hWnd, const _GUID & 
fCallStrongNamedProcesses, int ppunk, IUnknown * *) Line 440 C++
      ole32.dll!CClipDataObject::CacheDataPointer() Line 223 C++
      ole32.dll!CClipDataObject::QueryInterface(const _GUID & riid, void * * 
ppvObj) Line 886 C++
      [Inline Frame] combase.dll!IUnknown::QueryInterface(INoMarshal * *) Line 
138 C++
      combase.dll!CoMarshalInterface(IStream * pStm, const _GUID & riid, 
IUnknown * pUnk, unsigned long dwDestCtx, void * pvDestCtx, unsigned long 
mshlflags) Line 1133 C++
      combase.dll!wCoMarshalInterThreadInterfaceInStream(const _GUID & riid, 
IUnknown * pUnk, IStream * * ppStm) Line 1046 C++
      combase.dll!CoMarshalInterThreadInterfaceInStream(const _GUID & riid, 
IUnknown * pUnk, IStream * * ppStm) Line 709 C++
      vclplug_winlo.dll!MarshalIDataObjectInStream(IDataObject * pIDataObject, 
IStream * * ppStream) Line 158 C++
      vclplug_winlo.dll!CMtaOleClipboard::onGetClipboard(IStream * * ppStream) 
Line 465 C++
      vclplug_winlo.dll!CMtaOleClipboard::mtaOleReqWndProc(HWND__ * hWnd, 
unsigned int uMsg, unsigned __int64 wParam, __int64 lParam) Line 547 C++
      user32.dll!UserCallWinProcCheckWow()
      user32.dll!DispatchMessageWorker()
      vclplug_winlo.dll!CMtaOleClipboard::run() Line 656 C++
      vclplug_winlo.dll!CMtaOleClipboard::oleThreadProc(void * pParam) Line 673 
C++
      ucrtbased.dll!thread_start<unsigned int (__cdecl*)(void *),1>(void * 
const parameter) Line 97 C++
      kernel32.dll!BaseThreadInitThunk()
      ntdll.dll!RtlUserThreadStart()
    
    Thread A locks the mutex, and calls CMtaOleClipboard::getClipboard, which 
is synchronous; the call is marshaled to Thread B, which eventually tries to 
release a data object, which requires the mutex.
    
    Change-Id: I5ad8847b98ca23ad84c0595a2baad2c13f1e809e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170504
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/vcl/win/dtrans/WinClipboard.cxx b/vcl/win/dtrans/WinClipboard.cxx
index 3c9f57a1e250..be0266addd18 100644
--- a/vcl/win/dtrans/WinClipboard.cxx
+++ b/vcl/win/dtrans/WinClipboard.cxx
@@ -147,12 +147,13 @@ css::uno::Reference<css::datatransfer::XTransferable> 
CWinClipboard::getContents
 
 IDataObjectPtr CWinClipboard::getIDataObject()
 {
-    std::unique_lock aGuard(m_aMutex);
-
-    if (m_bDisposed)
-        throw lang::DisposedException("object is already disposed",
-                                      static_cast<XClipboardEx*>(this));
+    {
+        std::unique_lock aGuard(m_aMutex);
 
+        if (m_bDisposed)
+            throw lang::DisposedException("object is already disposed",
+                                          static_cast<XClipboardEx*>(this));
+    }
     // get the current dataobject from clipboard
     IDataObjectPtr pIDataObject;
     HRESULT hr = m_MtaOleClipboard.getClipboard(&pIDataObject);

Reply via email to