ATL OOM Resource leaks, and inconsistent behavior?

ATL OOM Resource leaks, and inconsistent behavior?

Post by TGVvb » Sun, 01 May 2005 01:18:11


I have written an ATL OOM based Outlook addin that traverses folders and
returns certain selected appointment items. It uses both OOM and Redemption.
When traversing lots of large folders, the addin and outlook come to a
crawl and it gets to a point where I experience unexplained crashes and
failures to QueryInterface even though they worked before in a previous
iteration. I had a memory leak associated with string properties such as
Subject etc where I was not freeing after obtaining and using. I am doing
all the freeing now and even though I am using far less memory now, I still
get to a point where items stop being returned from the items collection and
QueryInterface stops working. It seems to me like the items are not being
released. Any insight is highly appreciated. Here is the abridged version
of the loop through the folder:

Redemption::ISafeAppointmentItemPtr sappt("Redemption.SafeAppointmentItem");
IDispatch *iAppt = NULL;

for (hr = items->GetFirst(&iAppt); iAppt != NULL && !FAILED(hr);
iAppt->Release(), iAppt =NULL, hr = items->GetNext(&iAppt))
{
CComQIPtr<Outlook::_AppointmentItem> appt(iAppt);
sappt->put_Item(appt);
//retrieve properties , etc.
}

Is it possible that the redemption sappt is preventing appt from getting
released?
 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by Dan Mitche » Sun, 01 May 2005 01:54:53

"=?Utf-8?B?TGVvbg==?=" < XXXX@XXXXX.COM > wrote in


I think the problem is just that you're using a raw IDispatch for iAppt
-- that gets AddRef()ed by the call to GetFirst/GetNext, but you don't
have a release() anywhere further down for it.

The CComQIPtr will add another reference, which goes away when appt
goes out of scope, that's fine, and I'd assume that the call to put_Item
is also adding a reference; somewhere further down, sappt presumably
goes out of scope and releases its reference, but you're still left with
the one for GetFirst().

(unless put_Item _doesn't_ addref() -- Dmitry would know that sort of
thing)

-- dan

 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by TGVvb » Sun, 01 May 2005 03:12:07

I am doing a release in the last part of the for loop. I changed the code as
follows, and now I get a consistent crash on a not so big folder about half
way through the appointments inside AtlComPtrAssign, probably when it's doing
the assignment on GetNext or iAppt=NULL, where (*pp)->Release() crashes.
Which means that the item is already freed or stepped on. Here is what the
updated code looks like:

Redemption::ISafeAppointmentItemPtr sappt("Redemption.SafeAppointmentItem");
CComPtr<IDispatch> iAppt = NULL;

for (hr = items->GetFirst(&iAppt); iAppt != NULL && !FAILED(hr); iAppt
=NULL, hr = items->GetNext(&iAppt))
{
CComQIPtr<Outlook::_AppointmentItem> appt(iAppt);
sappt->put_Item(appt);
//do stuff
}
}
 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by Dan Mitche » Sun, 01 May 2005 04:56:39

"=?Utf-8?B?TGVvbg==?=" < XXXX@XXXXX.COM > wrote in


Oh, so you are, sorry, I didn't read the code carefully enough, I
wasn't expecting the comma operator there.


Just to eliminate one thing, are you sure that every object in that
folder is an appointment? I can't think of an obvious reason why it
would crash just on one item differently to all the other ones; maybe
every other time through you're getting lucky and the freed memory
hasn't been reused yet, but on that one item malloc et al happen to
shuffle stuff around and finally stomp on something that you're trying
to reuse.

As a different, more annoying, thing to try, what happens if you go
back to raw IDispatch everywhere? Heck, you could presumably go with
IUnknown everywhere, as long as Redemption'll take it -- that would let
you QI things as you go through just to make sure that they're
supporting the interfaces you expect.

You'd need to remember to release() stuff by hand, but it would at
least mean you'd know for certain what was going on, and hopefully that
might reveal what's going on enough that you can put the smart pointers
back in.

(heck, if you were feeling really brave, you could do all the dispatch
stuff by hand and call GetIDsOfNames/GetTypeInfo/etc, but I don't think
that would gain you much except for a bunch of pain. Then again, it
might be easy to copy the relevant bits of code out of the tlh/tli files
that #import has generated.)

Sorry I don't have anything more specific to suggest, but maybe this'll
shake out whatever's going on.

-- dan
 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by TGVvb » Sun, 01 May 2005 07:02:05

I did as u said and stripped the loop to nothing but:

Redemption::ISafeAppointmentItemPtr sappt("Redemption.SafeAppointmentItem");
IDispatch *iAppt = NULL;
CComQIPtr<Outlook::_AppointmentItem> appt;

for (hr = items->GetFirst(&iAppt); iAppt != NULL && !FAILED(hr); hr =
items->GetNext(&iAppt)) {
appt = iAppt;
appt = (IDispatch *)NULL;
iAppt->Release();
iAppt = NULL;
}

It reliably crashes in the same place. If I remove the 2 lines: appt=iAppt,
appt=(IDispatch *)NULL; There is no more crash. It zooms right through, and
memory stays constant.

If I leave the 2 lines and remove iAppt->Release(), it does not crash.
However, if I repeatedly call this loop, the memory keeps going up.

There must be some kind of issue with QIPtr. Thoughts welcome.
 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by Dan Mitche » Sun, 01 May 2005 08:33:01

"=?Utf-8?B?TGVvbg==?=" < XXXX@XXXXX.COM > wrote in


I'm still wondering if there's anything suspicious about the message it
crashes on -- if you remove that particular one from the folder, does
the problem go away, or is it the 15th (say) message that's the problem
no matter what message number 15 is?

Can you read any properties from the message that's crashing, ie are
you sure that appt is valid at that point? (this may have been in
earlier versions of your code, but presumably in the code that got
snipped)

What if you do the QueryInterface by hand -- maybe that'll give you
something more helpful in the return codes.

Also, now that I think about it, what happens if you use the smart
pointer wrapper Outlook::AppointmentItemPtr that'll be in the #import-
generated files, rather than CComQIPtr?

At least now we know that it's nothing related to Redemption, which
definitely helps.

-- dan
 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by TGVvb » Sun, 01 May 2005 12:33:01

he problem does not appear to be specific message related. It begins to
happen after the 354th message. In the debugger, I put a breakpoint right on
this message. I could see all the properties it did fine outputing all the
info on the message and then crashed when the AppointItemPtr tried to release
it before getting assigned the next one. I re-ran stopping right on the
354th message and skipped over the iAppt->Release() call. The
AppointmenItemPtr release call did not crash and it was successfully assigned
the next message. All the props were visible and everything came out happy.
I did not skip over the iAppt->Release() call this time and sure enough it
crashed on the next message.

I think that up until this point, it still has not messed with the memory of
all the double released items and then it begins to and we get crashes. This
probably means that you cannot release both times. However, watching the
memory usage, when I don't do the iAppt->Release(). The memory definitely
keeps going up and up.

I looked through the underlying code as it is executing for
AppointmentItemPtr and during the assignment it does a QueryInterface and
then an Attach. There is a comment that says //save the interface without
AddRef()ing. Does this mean that the AppointmentItemPtr, when it is
released, releases the interface, and thereby the original iAppt?

In general, when you do a QueryInterface on a raw IDispatch *, and you get a
new pointer as a result. When you release the interface *, does that also
release the original IDispatch?



"Dan Mitchell" wrote:

 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by TGVvb » Mon, 02 May 2005 05:55:01

I FIGURED IT OUT AND THIS IS SOMETHING THAT ALL SHOULD KNOW. HERE IS HOW YOU
DO IT:

IDispatchPtr iAppt = NULL;

for (hr = items->GetFirst(&iAppt); iAppt != NULL && !FAILED(hr); iAppt =
NULL, hr = items->GetNext(&iAppt))
{
Outlook::_AppointmentItemPtr appt(iAppt);
appt.AddRef();
}

You need the extra AddRef(). WHY???? Because the standard initializer does
a QueryInterface and Attach() without doing an AddRef. WHY???? I don't
know. In this loop, iAppt does a release automatically at the end of the for
loop every time iAppt=NULL and appt gets released every time it goes out of
scope. Without the AddRef, there is an asymetry. If you use a bare iAppt,
the problem is a leak. If you use a smart pointer, there will be a crash at
some point. If u do the addRef, there is no crash and no leak.
 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by Dmitry Str » Wed, 04 May 2005 04:06:20

he number 354 is the dead giveaway :-)
Some versions of Outlook/MAPI have problems when MAPIInitialize (called by
all Redemption objects when created) and MAPIUninitialize (called by all
Redemption objects when destoyed) are called 300-400 times. To work around
this problem, create an instance of a Redemption object (any object, such as
Redemption.MAPIUtils) at your app's startip and keep it referenced until
your app terminates. This will ensure that the MAPI system will be loaded
and initialized only once.

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool

"Leon" < XXXX@XXXXX.COM > wrote in message
news: XXXX@XXXXX.COM ...


 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by TGVvb » Wed, 04 May 2005 05:10:10

idn't help. I had the call to initialize the redemption object at the
folder level, so it was being called only once per folder. I moved it up to
the initialization code so that it no longer initializes in any loop. I
completely commented out the entire loop and removed the manual AddRef calls
that I had before to test this out. Here is the code in a nutshell. It
still crashes this way after the 354th item on iAppt=NULL; execution.

IDispatchPtr iAppt = NULL;

for (hr = items->GetFirst(&iAppt); iAppt != NULL && !FAILED(hr); iAppt =
NULL, hr = items->GetNext(&iAppt))
{
Outlook::_AppointmentItemPtr appt(iAppt);
}

It crashes the same way in this loop too:

IDispatchPtr iAppt = NULL;

for (hr = items->GetFirst(&iAppt); iAppt != NULL && !FAILED(hr);
m_sappt->put_Item(NULL), iAppt = NULL, hr = items->GetNext(&iAppt))
{
m_sappt->put_Item(iAppt);
}


"Dmitry Streblechenko" wrote:

 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by TGVvb » Wed, 04 May 2005 05:19:05

orry, the second loop with the m_sappt does not crash.

"Dmitry Streblechenko" wrote:

 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by TGVvb » Wed, 04 May 2005 05:49:19

re there any functions in the OOM that can be called, to periodically
completely free and clean everything up, free all the resources, and
reinitialize?

"Dmitry Streblechenko" wrote:

 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by TGVvb » Wed, 04 May 2005 06:19:13

he crash does happen, the same way in the following loop:
IDispatchPtr iAppt = NULL;

for (hr = items->GetFirst(&iAppt); iAppt != NULL && !FAILED(hr);
m_sappt->put_Item(NULL), iAppt = NULL, hr = items->GetNext(&iAppt))
{
m_sappt->put_Item(iAppt);
DATE dtStart = 0;
dtStart = (m_sappt->GetFields(CdoPR_START_DATE)).dblVal;

}

It crashes on iAppt=NULL;



"Dmitry Streblechenko" wrote:

 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by Henry Gusa » Wed, 04 May 2005 16:13:47

ry to use Windows Debugging Tools http://www.microsoft.com/ddk/debugging.
and enable Paging Heap feature for image outlook.exe via 'gflags' utility.

You will see an early crashes if memory overrun and accessing freed memory
happens.


WBR
Henry

"Leon" < XXXX@XXXXX.COM > wrote in message
news: XXXX@XXXXX.COM ...
by
around
such as
loaded
HOW
=
initializer
don't
the
out
crash
!FAILED(hr);
zooms
crash.
up.
it
problem
#import-


 
 
 

ATL OOM Resource leaks, and inconsistent behavior?

Post by Dan Mitche » Thu, 05 May 2005 00:16:57

"=?Utf-8?B?TGVvbg==?=" < XXXX@XXXXX.COM > wrote in


I think the message here is that it's probably safest not to mix
different types of smart pointer; if you use the OOM wrappers all the
way through, you shouldn't have problems, but it looks as if the
different more basic ones don't obey the same reference counting rules
as the OOM ones.

That seems pretty bad design on Microsoft's part, you'd think they'd
all work the same way, but it looks like that's not the case. Thanks for
the info -- I'll save that away for future reference!

-- dan