diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index 4a86846a89d913..cfd973cddcf725 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -1574,7 +1574,7 @@ class DefaultCOMImpl : public T ULONG STDMETHODCALLTYPE Release() { - ULONG res = mRef--; + ULONG res = --mRef; if (res == 0) delete this; return res; diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index c4af77adc6bfa0..3ab622c50ebd23 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -443,14 +443,19 @@ ClrDataAccess::GetMethodTableSlotEnumerator(CLRDATA_ADDRESS mt, ISOSMethodEnum * else { DacMethodTableSlotEnumerator *methodTableSlotEnumerator = new (nothrow) DacMethodTableSlotEnumerator(); - *enumerator = methodTableSlotEnumerator; - if (*enumerator == NULL) + if (methodTableSlotEnumerator == NULL) { hr = E_OUTOFMEMORY; } else { hr = methodTableSlotEnumerator->Init(mTable); + + if (SUCCEEDED(hr)) + hr = methodTableSlotEnumerator->QueryInterface(__uuidof(ISOSMethodEnum), (void**)enumerator); + + if (FAILED(hr)) + delete methodTableSlotEnumerator; } } @@ -3969,7 +3974,10 @@ ClrDataAccess::Request(IN ULONG32 reqCode, } else { - *(ULONG32*)outBuffer = 9; + // Revision 10: Fixed DefaultCOMImpl::Release() to use pre-decrement (--mRef). + // Consumers that previously compensated for the broken ref counting (e.g., ClrMD) + // should check this revision to avoid double-freeing. + *(ULONG32*)outBuffer = 10; status = S_OK; } break; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 936999964d8024..7eaa45a6a9cdc6 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -1528,9 +1528,6 @@ int ISOSDacInterface.GetHandleEnum(DacComNullableByRef ppHandleE } #endif ppHandleEnum.Interface = new SOSHandleEnum(_target, supportedHandleTypes, legacyHandleEnum); - // COMPAT: In the legacy DAC, this API leaks a ref-count of the returned enumerator. - // Manually leak a refcount here to match previous behavior and avoid breaking customer code. - ComInterfaceMarshaller.ConvertToUnmanaged(ppHandleEnum.Interface); } catch (System.Exception ex) { @@ -1558,9 +1555,6 @@ int ISOSDacInterface.GetHandleEnumForTypes([In, MarshalUsing(CountElementName = IGC gc = _target.Contracts.GC; HandleType[] handleTypes = gc.GetHandleTypes(types); ppHandleEnum.Interface = new SOSHandleEnum(_target, handleTypes, legacyHandleEnum); - // COMPAT: In the legacy DAC, this API leaks a ref-count of the returned enumerator. - // Manually leak a refcount here to match previous behavior and avoid breaking customer code. - ComInterfaceMarshaller.ConvertToUnmanaged(ppHandleEnum.Interface); } catch (System.Exception ex) {