Start investigating an UIA object leak

This commit is contained in:
Leonard Hecker 2025-12-09 01:05:20 +01:00
parent 224ac9de47
commit 62312a8943
10 changed files with 108 additions and 23 deletions

View File

@ -1,3 +1,38 @@
# LMAO
`NonDelegatingAddRef` in `base.h` line 7576.
```cpp
{
std::string trace;
const auto process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
void* stack[100];
const auto frames = CaptureStackBackTrace(0, 100, stack, NULL);
const auto symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
for (int i = 0; i < frames; i++)
{
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
trace.append(symbol->Name);
trace.append("\n");
}
free(symbol);
if (trace.find("XamlUiaTextRange") != std::string::npos)
{
trace.append("\n");
OutputDebugStringA(trace.c_str());
}
}
```
![terminal-logos](https://github.com/microsoft/terminal/assets/91625426/333ddc76-8ab2-4eb4-a8c0-4d7b953b1179)
[![Terminal Build Status](https://dev.azure.com/shine-oss/terminal/_apis/build/status%2FTerminal%20CI?branchName=main)](https://dev.azure.com/shine-oss/terminal/_build/latest?definitionId=1&branchName=main)

View File

@ -616,7 +616,7 @@ namespace
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
LONG index{ 0 };
auto indexBstr{ wil::make_bstr(indexString.c_str()) };
(void)SafeArrayPutElement(safeArray, &index, indexBstr.release());
(void)SafeArrayPutElement(safeArray, &index, indexBstr.get());
*ppData = safeArray;
return S_OK;
}
@ -669,7 +669,7 @@ namespace
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
LONG index{ 0 };
auto dataNameBstr{ wil::make_bstr(L"index") };
(void)SafeArrayPutElement(safeArray, &index, dataNameBstr.release());
(void)SafeArrayPutElement(safeArray, &index, dataNameBstr.get());
*names = safeArray;
return S_OK;
}

View File

@ -189,8 +189,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
return nullptr;
}
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parent.as<IAutomationPeerProtected>().ProviderFromPeer(parent));
return xutr.as<XamlAutomation::ITextRangeProvider>();
return winrt::make<XamlUiaTextRange>(returnVal, parent.as<IAutomationPeerProtected>().ProviderFromPeer(parent));
};
// Method Description:

View File

@ -29,14 +29,28 @@ namespace XamlAutomation
using winrt::Windows::UI::Xaml::Automation::Text::TextUnit;
}
static std::atomic<int64_t> refCount_XamlUiaTextRange;
namespace winrt::Microsoft::Terminal::Control::implementation
{
XamlUiaTextRange::XamlUiaTextRange(::ITextRangeProvider* uiaProvider, Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple parentProvider) :
_parentProvider{ std::move(parentProvider) }
{
_uiaProvider.attach(uiaProvider);
refCount_XamlUiaTextRange.fetch_add(1, std::memory_order_relaxed);
}
XamlUiaTextRange::~XamlUiaTextRange()
{
_uiaProvider.reset();
refCount_XamlUiaTextRange.fetch_sub(1, std::memory_order_relaxed);
}
XamlAutomation::ITextRangeProvider XamlUiaTextRange::Clone() const
{
UIA::ITextRangeProvider* pReturn;
THROW_IF_FAILED(_uiaProvider->Clone(&pReturn));
auto xutr = winrt::make_self<XamlUiaTextRange>(pReturn, _parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
return winrt::make<XamlUiaTextRange>(pReturn, _parentProvider);
}
bool XamlUiaTextRange::Compare(XamlAutomation::ITextRangeProvider pRange) const
@ -85,8 +99,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
THROW_IF_FAILED(_uiaProvider->FindText(queryText.get(), searchBackward, ignoreCase, &pReturn));
auto xutr = winrt::make_self<XamlUiaTextRange>(pReturn, _parentProvider);
return *xutr;
return winrt::make<XamlUiaTextRange>(pReturn, _parentProvider);
}
winrt::Windows::Foundation::IInspectable XamlUiaTextRange::GetAttributeValue(int32_t textAttributeId) const
@ -175,10 +188,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::com_array<double> result{ vec };
returnValue = std::move(result);
THROW_IF_FAILED(SafeArrayUnaccessData(pReturnVal));
THROW_IF_FAILED(SafeArrayDestroy(pReturnVal));
}
catch (...)
{
}
CATCH_LOG();
}
XamlAutomation::IRawElementProviderSimple XamlUiaTextRange::GetEnclosingElement()

View File

@ -30,11 +30,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
public winrt::implements<XamlUiaTextRange, Windows::UI::Xaml::Automation::Provider::ITextRangeProvider>
{
public:
XamlUiaTextRange(::ITextRangeProvider* uiaProvider, Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple parentProvider) :
_parentProvider{ parentProvider }
{
_uiaProvider.attach(uiaProvider);
}
XamlUiaTextRange(::ITextRangeProvider* uiaProvider, Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple parentProvider);
~XamlUiaTextRange();
#pragma region ITextRangeProvider
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider Clone() const;

View File

@ -322,9 +322,11 @@ std::vector<wil::com_ptr<T>> SafeArrayToOwningVector(SAFEARRAY* safeArray)
std::vector<wil::com_ptr<T>> result{ gsl::narrow<std::size_t>(count) };
for (int i = 0; i < count; i++)
{
result[i].attach(pVals[i]);
result[i] = pVals[i];
}
THROW_IF_FAILED(SafeArrayUnaccessData(safeArray));
THROW_IF_FAILED(SafeArrayDestroy(safeArray));
return result;
}

View File

@ -126,7 +126,7 @@ namespace
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
LONG index{ 0 };
auto indexBstr{ wil::make_bstr(indexString.c_str()) };
(void)SafeArrayPutElement(safeArray, &index, indexBstr.release());
(void)SafeArrayPutElement(safeArray, &index, indexBstr.get());
*ppData = safeArray;
return S_OK;
}
@ -179,7 +179,7 @@ namespace
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
LONG index{ 0 };
auto dataNameBstr{ wil::make_bstr(L"index") };
(void)SafeArrayPutElement(safeArray, &index, dataNameBstr.release());
(void)SafeArrayPutElement(safeArray, &index, dataNameBstr.get());
*names = safeArray;
return S_OK;
}

View File

@ -234,7 +234,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
UiaTracing::TextProvider::GetSelection(*this, *range.Get());
LONG currentIndex = 0;
hr = SafeArrayPutElement(*ppRetVal, &currentIndex, range.Detach());
hr = SafeArrayPutElement(*ppRetVal, &currentIndex, range.Get());
if (FAILED(hr))
{
SafeArrayDestroy(*ppRetVal);
@ -278,7 +278,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetVisibleRanges(_Outptr_result_mayben
UiaTracing::TextProvider::GetVisibleRanges(*this, *range.Get());
LONG currentIndex = 0;
hr = SafeArrayPutElement(*ppRetVal, &currentIndex, range.Detach());
hr = SafeArrayPutElement(*ppRetVal, &currentIndex, range.Get());
if (FAILED(hr))
{
SafeArrayDestroy(*ppRetVal);
@ -328,6 +328,11 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::get_DocumentRange(_COM_Outptr_result_m
RETURN_IF_FAILED(utr->ExpandToEnclosingUnit(TextUnit::TextUnit_Document));
RETURN_IF_FAILED(utr.CopyTo(ppRetVal));
UiaTracing::TextProvider::get_DocumentRange(*this, *utr.Get());
utr.Reset();
assert((*ppRetVal)->AddRef() == 2);
assert((*ppRetVal)->Release() == 1);
return S_OK;
}

View File

@ -134,6 +134,16 @@ try
}
CATCH_RETURN();
static std::atomic<int64_t> refCount_UiaTextRangeBase;
Microsoft::Console::Types::UiaTextRangeBase::UiaTextRangeBase() {
refCount_UiaTextRangeBase.fetch_add(1, std::memory_order_relaxed);
}
Microsoft::Console::Types::UiaTextRangeBase::~UiaTextRangeBase() {
refCount_UiaTextRangeBase.fetch_sub(1, std::memory_order_relaxed);
}
til::point UiaTextRangeBase::GetEndpoint(TextPatternRangeEndpoint endpoint) const noexcept
{
switch (endpoint)

View File

@ -70,7 +70,31 @@ namespace Microsoft::Console::Types
UiaTextRangeBase(UiaTextRangeBase&&) = delete;
UiaTextRangeBase& operator=(const UiaTextRangeBase&) = delete;
UiaTextRangeBase& operator=(UiaTextRangeBase&&) = delete;
~UiaTextRangeBase() = default;
UiaTextRangeBase();
~UiaTextRangeBase();
STDMETHOD_(ULONG, AddRef)()
{
return InternalAddRef();
}
STDMETHOD_(ULONG, Release)()
{
ULONG ref = InternalRelease();
if (ref == 0)
{
delete this;
auto modulePtr = ::Microsoft::WRL::GetModuleBase();
if (modulePtr != nullptr)
{
modulePtr->DecrementObjectCount();
}
}
return ref;
}
til::point GetEndpoint(TextPatternRangeEndpoint endpoint) const noexcept;
bool SetEndpoint(TextPatternRangeEndpoint endpoint, const til::point val) noexcept;
@ -115,7 +139,6 @@ namespace Microsoft::Console::Types
IFACEMETHODIMP GetChildren(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal) noexcept override;
protected:
UiaTextRangeBase() = default;
Render::IRenderData* _pData{ nullptr };
IRawElementProviderSimple* _pProvider{ nullptr };