Print Page | Close Window

CXTPObservable leaks causing aborts

Printed From: Codejock Forums
Category: Codejock Products
Forum Name: Toolkit Pro
Forum Description: Topics Related to Codejock Toolkit Pro
Printed Date: 29 February 2024 at 12:10am
Software Version: Web Wiz Forums 12.04 -

Topic: CXTPObservable leaks causing aborts
Posted By: rdhd
Subject: CXTPObservable leaks causing aborts
Date Posted: 17 June 2022 at 5:17pm
I have found this code is asserting in XTPSystemHelpers.h:

template<class Owner, class Observer>
AFX_INLINE CXTPObservable<Owner, Observer>::~CXTPObservable()
    ASSERT("All observers must be unsubscribed before destruction" && 0 == m_Observers.GetSize());

This causes random crashes when closing a debug build when the user has the Win 10 OS setting to use the cursor text indicator. The crash happens when the ASSERT code does a PeekMessage call. The crash is deep in UIAutomationCore.dll during the PeekMessage call.

So why is CJ asserting? I traced this to using the CXTPRibbonOffice2013Theme which creates some CXTPMarkupColor objects (CXTPMarkUpAmbientColor and CXTPMarkUpAmbientColorBrush). Further, it looks like to me the reason is the global paint manager leaking.

I found CXTPPaintManager::SetCustomTheme calls SetGlobalPaintManager. I have found no call during XTPShutDown that releases the global paint theme. So, I get this ASSERT as there are still observables in existence. I do see SetCustomTheme will assert if I pass in null. So that is not something that should be called with null. The SetCustomTheme code spins the ref count down for the current global paint manager so it gets released when setting a new theme. But the new theme just ... remains

This happens in our app. So, I ran the RibbonMDISample in debug. After it comes up, I go to the styles and change the style from Office 2016 Word to Office 2013 Word. Then I exit. The same ASSERT is called for the same reason - 4 observables in one of the arrays of observables.

So, I ask CodeJock:

What is the correct code calls to make sure this global paint manager is properly released so its destructor runs and these observables call XTPGetApplication()->Unsubscribe() and I can avoid the ASSERT/PeekMessage/RandomCrash?

I could try to call the protected GetGlobalPaintManager/SetGlobalPaintManager and spin the ref count down like SetCustomTheme does and hope no CJ code references the nullptr after that. If, I can the code to compile. The I have to worry about what this means for the future of those calls:

    _XTP_DEPRECATED_IN_FAVOR2(GetGlobalPaintManager, SetGlobalPaintManager)

Posted By: markr
Date Posted: 20 June 2022 at 3:58pm
This happens to me as well, about half the time during app shutdown with the debugger attached.

Posted By: rdhd
Date Posted: 21 June 2022 at 1:52pm
Hi markr,

I gave up finding what I would call a good solution to this. I can't get the global paint manager and spin its count down like SetCutomTheme does.

So, here is what I had to resort too. Right before I call XTPShutdown I did this:

    if( XTPPaintManager() )

That is the default theme CJ creates in V20. Unfortunately, sometimes there is no global paint manager, which is why we don't always trap the fact there are observable leaks. So, in that case CJ creates a new theme and it will be the xtpThemeOffice2000 theme and there is no leaking. To avoid creating two of that theme, I can use this:

    if( XTPPaintManager() )
        XTPPaintTheme curTheme = XTPPaintManager()->GetCurrentTheme();
        if( xtpThemeOffice2000 != curTheme )

I dislike doing this but the alternative is risking crashes in debug when shutting down while the OS Text Cursor Indicator setting is on. And, I like a crash free shutdown of our app even in debug.

Posted By: rdhd
Date Posted: 21 June 2022 at 2:27pm

Have you turned on the OS Text Cursor Indicator? Any crashes when you do so, I'm crashing due to this paint manager leak. But I'm also crashing in docking pane code. And, now I just crashed in CXTPTabManagerItem::GetRect.

>    ToolkitPro2010vc160x64UD.dll!CXTPTabManagerItem::GetRect() Line 544    C++
     ToolkitPro2010vc160x64UD.dll!CXTPRibbonControlTab::AccessibleLocation(long *, long *, long *, long *, tagVARIANT) Line 606    C++
     ToolkitPro2010vc160x64UD.dll!CXTPAccessible::XAccessible::accLocation(long *, long *, long *, long *, tagVARIANT) Line 1289    C++
     oleacc.dll!00007fffc3bbb4b0()    Unknown
     oleacc.dll!00007fffc3bbb2b8()    Unknown
     UIAutomationCore.dll!AccUtils::accLocation()    Unknown

The code is being sent a VT_I4 with a value of 8 but the array of items is only of size 7 but CJ just goes right ahead and accesses with no checks so I can crash here too:

HRESULT CXTPRibbonControlTab::AccessibleLocation(long* pxLeft, long* pyTop, long* pcxWidth,
                                                 long* pcyHeight, VARIANT varChild)
    *pxLeft = *pyTop = *pcxWidth = *pcyHeight = 0;

    int nIndex = GetChildIndex(&varChild);

    if (!m_pParent->GetSafeHwnd())
        return S_OK;

    if (!IsVisible())
        return S_OK;

    CRect rcControl = GetRect();

    if (nIndex != CHILDID_SELF)
        rcControl = GetItem(nIndex - 1)->GetRect();

Posted By: markr
Date Posted: 21 June 2022 at 3:09pm
Hi rdhd,

> Have you turned on the OS Text Cursor Indicator?

No, but I have noticed that if I launch the Windows magnifier (I used it sometimes to align small UI facets) then I'll see debug crashes similar to what you describe.

> but CJ just goes right ahead and accesses with no checks

This type of mistake is quite common in the XTP source code, I'm afraid.

Posted By: dbrookes
Date Posted: 22 June 2022 at 2:47am
Possible unrelated, but I've seen the same asserts recently in the application I work on. In my case it was caused by some old code that was leaking manually allocated CXTPCommandBars objects. So I'm glad the assert caught that for us. In the debugger if you have a look at the CXTPApplication m_Observers array content you might be able to see what objects (if any) have not been released. I use (static) CXTPPaintManager::SetTheme in my application as well, but haven't had any issues with that. I'm using 20.3.0.

As for the accessibility crash. I have seen stuff like that before in report control and property grid components. The theory at the time was that the crashes were caused by crummy anti-malware applications poking around applications through their accessibility interfaces. I reported the crashes to XTP support but I'm not sure if anything ever got changed. We ended up deciding for our application to patch XTP to #ifdef out all the IAccessible COM interface mappings. That way we effectively disable the accessible interfaces. This is bad for any users who actually may actually want/need accessibility. But we didn't have a huge amount of choice. That was a few years ago.

Posted By: rdhd
Date Posted: 22 June 2022 at 2:05pm
I did look at the objects and found they were "ambient" color and brush objects. I set a BP in the code and found they are created when we start up and set our theme to office 2013. That let me see that theme object was "stuck" as the global paint manager. I didn't find any leaks. But, SetCustomTheme will spin down the count until the current one is released. So, I finally just set the theme back to the 2003 (default theme) CJ sets at startup. The code released the 2013 theme and the leaks went away with it. Tracking leaks is tough as there was a ref count of well over 900 on the paint manager. Guess that's why SetCustomTheme does this at the end to the global PM it grabs at the top of the code before setting it to the new theme:

        while (0 < pOldTheme->InternalRelease())

Posted By: mschumi_41
Date Posted: 06 July 2022 at 7:07am
I got the same debug assert message "All observers must be unsubscribed before destruction" at CXTPApplication destruction.
The reason was exactly as rdhd explains:
* the last theme (XTPPaintManager) is never deleted before CXTPApplication destruction
* If the last theme is the Office 2013 theme, 2 objects of type CXTPMarkupAmbientColor and 2 objects of type CXTPMarkupAmbientColorBrush are created.
* These four objects register themselves with XTPGetApplication()->Subscribe(this);
* Because the XTPPaintManager is not destructed, these four objects are also not destructed (in the destructor they would have unsubscribed themselves with XTPGetApplication()->Unsubscribe(this);)

I consider using the same work-around (setting the theme back to 2003 where the MarkupAmbientColor objects are not created.

However this is only a work-around...

Dear codejock team, could you please have a look at this problem and maybe fix it in one of the next versions?

Best regards,

Posted By: astoyan
Date Posted: 10 July 2022 at 4:48pm
Thanks everyone for debugging this issue and sharing your feedbacks. The issue have been confirmed and investigated, however fixing it does not seem possible as the root cause is in not releasing command bar control references initially by UIAutomation.dll. That in its turn causes lots of other resources not being release properly, including theme and markup object references.

The conclusion is that the issue is caused by an injected UI automation module and hence it cannot be fixed properly on ToolkitPro side. If you find that the suggested workaround works well in your project then please keep using it. 


Posted By: astoyan
Date Posted: 18 July 2022 at 10:21am
As the latest update, the workaround has been found and added to ToolkitPro. It's not ideal and will result in a small number of small memory leaks due to unreleased COM references held by UIAutomation.dll, however all related crashes and assertions were fixed. The fix is quite large and lots of source files have been affected, so sharing it here or sending patches to the affected users is not possible, thus the fix will be available in the next version.

If you need the fix urgently and you have an active subscription please submit a support ticket and describe your situation.


Posted By: rdhd
Date Posted: 18 July 2022 at 3:02pm
Hi Astoyan,

How can I verify UIAutomation ref leaks? Have you posted on the MSDN forums regarding them? I have posted on the forums stating that the text cursor indicator setting is crashing our app. But, about all I got back was "how to repro" it. If you can mock up a sample, or modify one of your samples, that show the leaks, that would be good to use as a post. And, I would gladly post it.

Or ... we pay big, big bucks for MS support. If I have a sample, or can even point to the code where you know a ref leak is created, I can send MS our application and instructions on what code is calling into the application so MS can examine the issue and hopefully provide a fix.

I would love to be able to point to the docking pane code as UIAutomation appears to be causing our customers the most pain (i.e., user crashes).

We have crashes where the customer isn't using the Text Cursor Indicator but we get crashes in the docking pane code and the dump files show UIAutomation is injected. Yet, on my box, I can only find it injected into the app if I use the cursor indicator setting.

Posted By: rdhd
Date Posted: 18 July 2022 at 3:14pm
Hi again Astoyan,

I posted a reply and then had a thought. I wonder if UIAutomation is .NET based. If MS is using .NET, I have found in the past that they do a terrible job of releasing COM objects/interfaces. They have been relying on .NET Garbage Collection to do so. Even calling CoDisconnectObject has no effect because .NET doesn't "play that game".

I had to resort to drastic measures when .NET came about and users started using VB .NET or C# or other .NET languages to automate our application. First I resorted to running GC directly (both 2.0 and later 2.0 and 4.0) by examining the process to see if the .NET core(s) were present.

Later, I had to totally rewrite our automation and give out my own light weight automation wrappers so that .NET holding onto them didn't cause us issues with our "real" objects. When a real object goes away, I set a flag in the wrapper and leave it in memory. Then, when any subsequent call that might come in other than AddRef or Release, say QueryInterface or an API call on the Dispatch interface, I returned the COM error code RPC_E_DISCONNECTED. After that, I didn't have to run GC.

And, running GC to completely get rid of all objects is tricky to do. I wrote a .NET object that exposed a method for each runtime and working with Microsoft, came up with this:

        void DotNetEdge.Refuse.CollectAllGenerations()
            // TODO:  Add DotNetFefuse.DotNetEdge.Refuse.Collect implementation

            if( false == m_Collecting )
                m_Collecting = true;

                // Get the max generation. Usually two but not guranteed to always be two.
                int MaxGeneration = GC.MaxGeneration;
                // Wait for finalizers to be run
                // Force collection of freachable objects made so by first call

                m_Collecting = false;

Posted By: HamRadioDeluxe
Date Posted: 22 July 2022 at 12:26pm
Is it possible to get the update urgently?

I have an active subscription and ticket on the support. I haven't get a reply yet.

Posted By: astoyan
Date Posted: 24 July 2022 at 2:57pm
Originally posted by HamRadioDeluxe HamRadioDeluxe wrote:

Is it possible to get the update urgently?
I have an active subscription and ticket on the support. I haven't get a reply yet.
The ticket has been addressed. Please check the response for details.

Print Page | Close Window

Forum Software by Web Wiz Forums® version 12.04 -
Copyright ©2001-2021 Web Wiz Ltd. -