提交 d58f06dd 编写于 作者: T Tomáš Matoušek 提交者: GitHub

Fix race condition in EnC implementation that might cause VS crash (#19910)

Fix race condition in EnC implementation
上级 d9a45089
...@@ -20,9 +20,10 @@ public static int GetStreamForObject(object pUnk, out IntPtr stream) ...@@ -20,9 +20,10 @@ public static int GetStreamForObject(object pUnk, out IntPtr stream)
return CoMarshalInterThreadInterfaceInStream(ref s_IID_IUnknown, pUnk, out stream); return CoMarshalInterThreadInterfaceInStream(ref s_IID_IUnknown, pUnk, out stream);
} }
public static int GetObjectForStream(IntPtr stream, out object pUnk) public static object GetObjectAndRelease(IntPtr stream)
{ {
return CoGetInterfaceAndReleaseStream(stream, ref s_IID_IUnknown, out pUnk); Marshal.ThrowExceptionForHR(CoGetInterfaceAndReleaseStream(stream, ref s_IID_IUnknown, out object pUnk));
return pUnk;
} }
} }
} }
...@@ -90,9 +90,7 @@ internal sealed class VsENCRebuildableProjectImpl ...@@ -90,9 +90,7 @@ internal sealed class VsENCRebuildableProjectImpl
/// </summary> /// </summary>
private ModuleMetadata _metadata; private ModuleMetadata _metadata;
private ISymUnmanagedReader3 _pdbReader; private Lazy<ISymUnmanagedReader3> _pdbReader;
private IntPtr _pdbReaderObjAsStream;
#endregion #endregion
...@@ -348,16 +346,14 @@ public int StopDebuggingPE() ...@@ -348,16 +346,14 @@ public int StopDebuggingPE()
_activeStatementIds = null; _activeStatementIds = null;
_projectBeingEmitted = null; _projectBeingEmitted = null;
Debug.Assert(_pdbReaderObjAsStream == IntPtr.Zero || _pdbReader == null); var pdbReader = Interlocked.Exchange(ref _pdbReader, null);
if (pdbReader?.IsValueCreated == true)
if (_pdbReader != null)
{ {
if (Marshal.IsComObject(_pdbReader)) var symReader = pdbReader.Value;
if (Marshal.IsComObject(symReader))
{ {
Marshal.ReleaseComObject(_pdbReader); Marshal.ReleaseComObject(symReader);
} }
_pdbReader = null;
} }
// The HResult is ignored by the debugger. // The HResult is ignored by the debugger.
...@@ -990,11 +986,10 @@ public unsafe int BuildForEnc(object pUpdatePE) ...@@ -990,11 +986,10 @@ public unsafe int BuildForEnc(object pUpdatePE)
var updater = (IDebugUpdateInMemoryPE2)pUpdatePE; var updater = (IDebugUpdateInMemoryPE2)pUpdatePE;
if (_committedBaseline == null) if (_committedBaseline == null)
{ {
var hr = MarshalPdbReader(updater, out _pdbReaderObjAsStream, out _pdbReader); var previousPdbReader = Interlocked.Exchange(ref _pdbReader, MarshalPdbReader(updater));
if (hr != VSConstants.S_OK)
{ // PDB reader should have been nulled out when debugging stopped:
return hr; Contract.ThrowIfFalse(previousPdbReader == null);
}
_committedBaseline = EmitBaseline.CreateInitialBaseline(_metadata, GetBaselineEncDebugInfo); _committedBaseline = EmitBaseline.CreateInitialBaseline(_metadata, GetBaselineEncDebugInfo);
} }
...@@ -1114,31 +1109,20 @@ private Deltas EmitProjectDelta() ...@@ -1114,31 +1109,20 @@ private Deltas EmitProjectDelta()
private EditAndContinueMethodDebugInformation GetBaselineEncDebugInfo(MethodDefinitionHandle methodHandle) private EditAndContinueMethodDebugInformation GetBaselineEncDebugInfo(MethodDefinitionHandle methodHandle)
{ {
Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA); Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA);
return GetEditAndContinueMethodDebugInfo(_pdbReader.Value, methodHandle);
InitializePdbReader();
return GetEditAndContinueMethodDebugInfo(_pdbReader, methodHandle);
} }
private void InitializePdbReader() // Unmarshal the symbol reader (being marshalled cross thread from STA -> MTA).
private static ISymUnmanagedReader3 UnmarshalSymReader(IntPtr stream)
{ {
Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA); Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA);
try
if (_pdbReader == null)
{ {
// Unmarshal the symbol reader (being marshalled cross thread from STA -> MTA). return (ISymUnmanagedReader3)NativeMethods.GetObjectAndRelease(stream);
}
Debug.Assert(_pdbReaderObjAsStream != IntPtr.Zero); catch (Exception exception) when (FatalError.ReportWithoutCrash(exception))
var exception = Marshal.GetExceptionForHR(NativeMethods.GetObjectForStream(_pdbReaderObjAsStream, out object pdbReaderObjMta)); {
if (exception != null) throw new InvalidDataException(exception.Message, exception);
{
// likely a bug in the compiler/debugger
FatalError.ReportWithoutCrash(exception);
throw new InvalidDataException(exception.Message, exception);
}
_pdbReaderObjAsStream = IntPtr.Zero;
_pdbReader = (ISymUnmanagedReader3)pdbReaderObjMta;
} }
} }
...@@ -1309,7 +1293,7 @@ public int GetCurrentExceptionSpanPosition(uint exceptionRegionId, VsTextSpan[] ...@@ -1309,7 +1293,7 @@ public int GetCurrentExceptionSpanPosition(uint exceptionRegionId, VsTextSpan[]
} }
} }
private static int MarshalPdbReader(IDebugUpdateInMemoryPE2 updater, out IntPtr pdbReaderPointer, out ISymUnmanagedReader3 managedSymReader) private static Lazy<ISymUnmanagedReader3> MarshalPdbReader(IDebugUpdateInMemoryPE2 updater)
{ {
// ISymUnmanagedReader can only be accessed from an MTA thread, however, we need // ISymUnmanagedReader can only be accessed from an MTA thread, however, we need
// fetch the IUnknown instance (call IENCSymbolReaderProvider.GetSymbolReader) here // fetch the IUnknown instance (call IENCSymbolReaderProvider.GetSymbolReader) here
...@@ -1332,16 +1316,16 @@ private static int MarshalPdbReader(IDebugUpdateInMemoryPE2 updater, out IntPtr ...@@ -1332,16 +1316,16 @@ private static int MarshalPdbReader(IDebugUpdateInMemoryPE2 updater, out IntPtr
symbolReaderProvider.GetSymbolReader(out object pdbReaderObjSta); symbolReaderProvider.GetSymbolReader(out object pdbReaderObjSta);
if (Marshal.IsComObject(pdbReaderObjSta)) if (Marshal.IsComObject(pdbReaderObjSta))
{ {
int hr = NativeMethods.GetStreamForObject(pdbReaderObjSta, out pdbReaderPointer); int hr = NativeMethods.GetStreamForObject(pdbReaderObjSta, out IntPtr stream);
Marshal.ReleaseComObject(pdbReaderObjSta); Marshal.ReleaseComObject(pdbReaderObjSta);
managedSymReader = null; Marshal.ThrowExceptionForHR(hr);
return hr;
return new Lazy<ISymUnmanagedReader3>(() => UnmarshalSymReader(stream));
} }
else else
{ {
pdbReaderPointer = IntPtr.Zero; var managedSymReader = (ISymUnmanagedReader3)pdbReaderObjSta;
managedSymReader = (ISymUnmanagedReader3)pdbReaderObjSta; return new Lazy<ISymUnmanagedReader3>(() => managedSymReader);
return 0;
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册