Closed Bug 198531 Opened 21 years ago Closed 21 years ago

Valgrind shows nsSOAPEncoding leaks

Categories

(Core Graveyard :: Web Services, defect)

x86
Linux
defect
Not set
normal

Tracking

(Not tracked)

VERIFIED FIXED

People

(Reporter: timeless, Assigned: mozilla)

Details

(Keywords: memory-leak, valgrind)

Attachments

(2 files, 2 obsolete files)

boffo linux qt tinderbox xpcshell

compare:
mozhack@boffo:~/obj-i686-pc-linux-gnu-qt/dist/bin$ ./run-mozilla.sh
/usr/local/bin/valgrind --logfile-fd=3 ./xpcshell 3>/tmp/vg-soap.nul

Components.classes["@mozilla.org/xmlextras/soap/encoding;1"];quit()

mozhack@boffo:~/obj-i686-pc-linux-gnu-qt/dist/bin$ ./run-mozilla.sh
/usr/local/bin/valgrind --logfile-fd=3 ./xpcshell 3>/tmp/vg-soap.svc

Components.classes["@mozilla.org/xmlextras/soap/encoding;1"].getService();quit()

strip valgrind prefixes (cmd.exe):
for %a in (vg-soap*) do @perl -pi.bak -e "s/^.?==\d+==//;s/^.?--\d+--//;s/
record \d+ of \d+$/ record.../;s/   (?:at|by) 0x[\dA-F]{8}://" %a && rm %a.bak

compare them, notice that there's a lot of talk about Soap stuff. (attachment)

I set a breakpoint on nsSOAPEncoding's destructor and it wasn't hit.

getService v. createInstance was arbitrary, the leak is the same.
Attached file valgrind diff output
Ok, partial picture:

References to nsSOAPEncoding
1. nsSOAPEncoding gives itself to nsSOAPEncodingRegistry.mEncodings which holds
a reference to nsSOAPEncoding
2. As a service the component manager owns one reference to nsSOAPEncoding
3. XPConnect (testcase) gets a reference
4. -unknown-

References to nsSOAPEncodingRegistry
1. nsSOAPEncoding.mRegistry

That's enough of a loop to cause a problem.
Component: XML → Web Services
taking bug
Assignee: harishd → jgaunt
This patch changes the addref/release of nsSOAPEncoding to be handled by the
nsSOAPEncodingRegistry. The registry becomse a *-style pointer in the encoding
and the encodings are *-style pointers in the hashtable which has been switched
from nsSupportsHashtable to nsObjectHashtable. So when all the encodings have
been released completely the registry destroys the encodings and goes away.
Attachment #121457 - Flags: superreview?(harishd)
Attachment #121457 - Flags: review?(rayw)
Comment on attachment 121457 [details] [diff] [review]
break cycle between encoding and encoding registry

I'm not a super reviewer. Requesting sr= from jst. I can r= in addition to
rayw's.
Attachment #121457 - Flags: superreview?(harishd) → superreview?(jst)
Attached patch v1.01 of soap leak patch (obsolete) — Splinter Review
had 2 bad spots in the last patch, an NS_ENSURE() of a nsStringKey and I was
missing the NS_IMETHODIMP foo before the AddRef for nsSOAPEncoding.

I've also applied this patch to the new webservices directory and built it just
fine.
Attachment #121457 - Attachment is obsolete: true
Attachment #121563 - Flags: superreview?(jst)
Attachment #121563 - Flags: review?(rayw)
Attachment #121457 - Flags: superreview?(jst)
Attachment #121457 - Flags: review?(rayw)
Comment on attachment 121563 [details] [diff] [review]
v1.01 of soap leak patch

- In nsSOAPEncodingRegistry::~nsSOAPEncodingRegistry()
 {
-  /* destructor code */
-  delete mEncodings;
+  if (mEncodings)
+    delete mEncodings;

delete is null safe, i.e. that if check is redundant, remove it.

- In nsSOAPEncodingRegistry::AddEncoding():

+  if (!mEncodings) {
+    mEncodings = new nsObjectHashtable(nsnull, nsnull, DeleteEncodingEntry,
nsnull, 4);
+  }
+
+  if (!mEncodings)
+    return NS_ERROR_OUT_OF_MEMORY;

mEncodings will never be null except if the new inside the previous if fails,
therefore you should move this check inside the previous one. One less check to
make in the common case.

+nsSOAPEncoding::nsSOAPEncoding() : mEncoders(new nsSupportsHashtable()), 
+				    mDecoders(new nsSupportsHashtable()), 
+				    mMappedInternal(new nsSupportsHashtable()), 
+				    mMappedExternal(new nsSupportsHashtable())

I know this is the way we do this in the current code, so you're not adding
this, but I see no reason for any of those hashtables to be pointers, they
should be direct members of the nsSOAPEncoding class. That way we'd have less
traffic on the heap (i.e. fewer allocations) and we wouldn't need to worry
about error checking those initializers for OOM. Want to change that in this
bug, or you want to file a new bug for that?

- In nsSOAPEncoding.h:

+class nsSOAPEncodingRegistry : public nsISOAPEncodingRegistry
...
+  nsObjectHashtable *mEncodings;

Make that a dirrect reference, no need to allocate that object separately on
the heap (we even leak that hash in this code in some cases).

-  nsCOMPtr < nsISOAPEncoding > mRegistry;
+  nsISOAPEncodingRegistry *mRegistry;

Add a comment here explaining why this is a weak reference.

Fix that, and I'll have one more look.
Attachment #121563 - Flags: superreview?(jst) → superreview-
Comment on attachment 121563 [details] [diff] [review]
v1.01 of soap leak patch

It looks good.	You did a good job of cleanly redefine the registry instead of
deriving it from the encoding as I did.

You could clear up the registry constructor, as your comment points out -- what
to do if there were no associated style string.  The if that is there on
failure is just a placeholder since mEncodings was already null.  But that case
never happens.	The "new" gets called only after assigning that string.

Johnny's suggestions to avoid heap allocation are obviously good -- my errors. 
The rest looks good to me.
Attachment #121563 - Flags: review?(rayw) → review-
Attached patch v1.5Splinter Review
Switched to direct refs from pointers for all the hashtables

Added some comments about the ownership model in the .h

fixed the if() checks - they're gone, those pointers don't exist anymore
Attachment #121563 - Attachment is obsolete: true
Attachment #121750 - Flags: superreview?(jst)
Attachment #121750 - Flags: review?(rayw)
Comment on attachment 121750 [details] [diff] [review]
v1.5

requesting approval to land this leak patch in 1.4b
Attachment #121750 - Flags: approval1.4b?
Comment on attachment 121750 [details] [diff] [review]
v1.5

NS_IMETHODIMP_(nsrefcnt) 
nsSOAPEncoding::AddRef(void)
{
  if(mRegistry)
    mRegistry->AddRef();
  return 0;
}

NS_IMETHODIMP_(nsrefcnt) 
nsSOAPEncoding::Release()
{
  if(mRegistry)
    mRegistry->Release();
  return 0;
}

The one thing that's a bit shady here is the return value from these methods.
In XPCOM, you're supposed to return the resulting reference count from your
AddRef() and Release() methods, these always returns 0. It's easy enough to
make them return the return value from the call on mRegistry, and that would
fix this, for the most part, but in the case where there is no registry, then
what do we do?

It seems like there's a possible leak in this code if we fail to create a new
registry when creating new SOAP encodings, is there anything we can do about
that?

sr=jst for the patch if you make the AddRef() and Release() calls return the
registry's refcount when there's a registry, but ideally we'd have a sollution
for the remaining problem as well. Ideas?
Attachment #121750 - Flags: superreview?(jst) → superreview+
Yeah, I didn't particularly like returning 0. The problem with returning the
result from the mRegistry call is that it could be much larger than just the one
object's refcount, since you could have half a dozen encodings in the registry,
each of which reports its refcount to the registry. But, that may be better than 0. 

In the case of no registry, we're really in a lot of trouble anyway right? Since
that means the new() call failed most likely due to low memory. I could make the
registry an object. Maybe its better to replace the if() with an NS_ASSERTION
just to make it clear we really need the registry? The registry also gets
created in the constructor, which can't report failure to create it if something
should happen. Perhaps an Init() method on the encoding coupled with the
NS_ASSERTION?
Status: NEW → ASSIGNED
nsObjectHashtable is now deprecated in favor of nsClassHashtable... would it be
hard to use the new hashtable type?
Comment on attachment 121750 [details] [diff] [review]
v1.5

a=asa (on behalf of drivers) for checkin to 1.4b.
Attachment #121750 - Flags: approval1.4b? → approval1.4b+
John, the most important thing with the return from Release() is to return 0
only when the object went away (not that anyone cares in this case, but that's
what matters in some cases), so returning mRegistry's refcount should be fine.
AFAIK AddRef() should never return 0 since you should never really get into such
a case :-)

I think the right thing to do wrt the null registry is to do what you suggested,
add an Init() method and prevent the usage of SOAP encodings that we fail to
initialize.

I'm cool with making those changes at a later stage tho, if you prefere that.
Comment on attachment 121750 [details] [diff] [review]
v1.5

r=rayw
Attachment #121750 - Flags: review?(rayw) → review+
I've changed the AddRef/Release to return the value of the call to mRegisry's
AddRef/Release and the default return value to 1 (from 0). I'll file another bug
on adding the Init() method to get the call to |new nsSOAPEncodingRegistry()|
out of constructor.
Checked in!
Status: ASSIGNED → RESOLVED
Closed: 21 years ago
Resolution: --- → FIXED
vrfy fixed
Status: RESOLVED → VERIFIED
Keywords: valgrind
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: