Closed Bug 831993 Opened 11 years ago Closed 11 years ago

convert nsISupportsArray m_serversToGetNewMailFor variable from nsPop3IncomingServer.cpp to something better

Categories

(MailNews Core :: Networking: POP, defect)

defect
Not set
minor

Tracking

(Not tracked)

RESOLVED FIXED
Thunderbird 22.0

People

(Reporter: aceman, Assigned: neil)

References

Details

Attachments

(1 file, 4 obsolete files)

Defined as a variable in:

    mailnews/local/src/nsPop3IncomingServer.cpp (View Hg log or Hg annotations)
        line 46 -- nsCOMPtr <nsISupportsArray> m_serversToGetNewMailFor;
        line 676 -- m_serversToGetNewMailFor = servers;
        line 711 -- m_serversToGetNewMailFor->Count(&numServersLeft);
        line 716 -- m_serversToGetNewMailFor->RemoveElementAt(0); 

Referenced in:

    mailnews/local/src/nsPop3IncomingServer.cpp (View Hg log or Hg annotations)
        line 715 -- nsCOMPtr <nsIPop3IncomingServer> popServer (do_QueryElementAt(m_serversToGetNewMailFor, 0));
Attached patch WIP patch (obsolete) — Splinter Review
Attachment #703598 - Flags: feedback?(kent)
Attached patch WIP patch 2 (obsolete) — Splinter Review
This alternative version makes m_serversToGetNewMailFor nsIArray as it seems we do not really need to alter it. However this crashes in tests, so there is a bug somewhere.
Attachment #703637 - Flags: feedback?(kent)
Attachment #703637 - Flags: feedback?(neil)
Attached patch Alternative approach (obsolete) — Splinter Review
Note: this compiles but is otherwise untested.

Ideally I would use nsCOMArray<nsIPop3IncomingServer> throughout but that would require either a [noscript] version of downloadMailFromServers or the nsCOMArray improvements awaiting review in bug 493711.
Comment on attachment 703637 [details] [diff] [review]
WIP patch 2

>   uint32_t numServersLeft;
>-  m_serversToGetNewMailFor->Count(&numServersLeft);
>+  m_serversToGetNewMailFor->GetLength(&numServersLeft);
> 
>-  for (; numServersLeft > 0;)
>+  while (numServersLeft > 0)
>   {
>-    nsCOMPtr <nsIPop3IncomingServer> popServer (do_QueryElementAt(m_serversToGetNewMailFor, 0));
>-    m_serversToGetNewMailFor->RemoveElementAt(0);
>+    nsCOMPtr<nsIPop3IncomingServer> popServer =
>+      do_QueryElementAt(m_serversToGetNewMailFor, numServersLeft - 1);
>     numServersLeft--;
The old code ends up enumerating the servers in ascending order because it removes the first one each time. The new code enumerates the servers in descending order. This could be the cause of your problem. Or I might just be clutching at straws...
Attachment #703637 - Flags: feedback?(neil) → feedback+
Comment on attachment 703874 [details] [diff] [review]
Alternative approach

I can't say I understand what this new patch does. Passing in a nsTArray is interesting :)
Attachment #703874 - Flags: feedback?(kent)
(In reply to neil@parkwaycc.co.uk from comment #4)
> The old code ends up enumerating the servers in ascending order because it
> removes the first one each time. The new code enumerates the servers in
> descending order. This could be the cause of your problem. Or I might just
> be clutching at straws...
Sure, I can change that, probably at the cost of a new variable that runs up to the numServersLeft.
Were you able to find the problem why this version crashes?
No, and you're going to need a stack trace if you want me to look harder.
Attached patch WIP patch 2 v2 (obsolete) — Splinter Review
For some reason the tests do not crash today. So let's see which version does rkent like.
Attachment #703637 - Attachment is obsolete: true
Attachment #703637 - Flags: feedback?(kent)
Attachment #704019 - Flags: feedback?(kent)
Comment on attachment 704019 [details] [diff] [review]
WIP patch 2 v2

Overall this looks good. I prefer this approach.

Just as an aside, ironically today I was checking some old code of mine where I did exactly what I told you NOT to do yesterday, that is to pass in an nsIArray then QI to nsIMutableArray. Not sure why did did that :(
Attachment #704019 - Flags: feedback?(kent) → feedback+
Comment on attachment 703874 [details] [diff] [review]
Alternative approach

I don't really understand the value of using raw XPCOM arrays, with the need to pass count and do careful NS_IF_RELEASE() when nsIMutableArray is a perfectly valid replacement.
Attachment #703874 - Flags: feedback?(kent) → feedback-
Comment on attachment 703598 [details] [diff] [review]
WIP patch

Isn't this obsolete, or is there some reason I need to look at it as well? If the question is whether nsIArray or nsIMutableArray is used, I would only use nsIMutableArray into a method that you know is going to change the array.

(diff service is temporarily offline so I cannot easily see the changes).
Attachment #703598 - Flags: feedback?(kent)
(In reply to Kent James from comment #10)
> I don't really understand the value of using raw XPCOM arrays, with the need
> to pass count and do careful NS_IF_RELEASE() when nsIMutableArray is a
> perfectly valid replacement.
As I said, this really wants the nsCOMArray improvements in bug 493711, then there wouldn't be any need for manual refcounting. (The value comes from the array being typesafe; nsIMutableArray could contain anything.)
Typesafe is an advantage. I really appreciate how my C++ code generates compile errors when someone changes an interface, but the javascript code only fails when you try to run it.
(In reply to Kent James (:rkent) from comment #11)
> Comment on attachment 703598 [details] [diff] [review]
> WIP patch
> 
> Isn't this obsolete, or is there some reason I need to look at it as well?
> If the question is whether nsIArray or nsIMutableArray is used, I would only
> use nsIMutableArray into a method that you know is going to change the array.
> 
> (diff service is temporarily offline so I cannot easily see the changes).

The differene between "WIP patch" and "WIP patch 2 (v2)" is that in WIP patch I used mutable arrays and had to copy one array as one interface had an nsIArray in argument. The "WIP patch 2" solves it all with nsIArray as it seems we do not really need to alter the array internally (of course I can't say if there isn't any leak now). So I prefer the version 2, as it probably allows the caller to pass in mutable or immutable array as he sees fit.
Note: this version needs the patch from bug 493711 that I'll attach shortly, but I just want to show you how much cleaner the code is when you have a useful nsCOMArray API :-)
Attachment #704319 - Flags: feedback?(kent)
Comment on attachment 704319 [details] [diff] [review]
Alternative approach

So I have mixed feelings about this, Neil. The issue comes down to what you fear most, and what I fear most is refcount errors and crashes from nulls.

So I see stuff like:

sresult nsPop3GetMailChainer::GetNewMailForServers(nsIPop3IncomingServer** servers ...

then

m_serversToGetNewMailFor.AppendElements(servers, count);

and I start asking what happened to the memory that was allocated for servers. Or was it allocated? I don't know, so I would have to look in detail at the memory model issues associated with .Elements() and .AppendElements.

You'll probably tell me that one of the simplifications of this is that the memory allocation is handled automatically, but I don't know that so I would have to look at it in more detail.

I still like the type safety though.

I also see that you are not protecting for null values in calls like rv = deferredServers[0]-> so once again I would have to check in details the code for nsCOMArray to see if it does the protection.

So this forces me to learn a new set of issues associated with an object that is fairly rarely used. In my own code, I would not bother (at least for usage through XPCOM. As an internal variable in a C++ method I would use nsCOMArray.)

This of course is just my opinion, and reflects my own skill level (or lack thereof).
Attachment #704319 - Flags: feedback?(kent)
(In reply to Kent James from comment #16)
> So I see stuff like:
> 
> sresult nsPop3GetMailChainer::GetNewMailForServers(nsIPop3IncomingServer**
> servers ...
> 
> then
> 
> m_serversToGetNewMailFor.AppendElements(servers, count);
> 
> and I start asking what happened to the memory that was allocated for
> servers. Or was it allocated? I don't know, so I would have to look in
> detail at the memory model issues associated with .Elements() and
> .AppendElements.
Under the XPCOM interface contract, servers is a read-only array of pointers (to mutable objects, although that's not relevant here). AppendElements copies the array into its local mutable nsCOMArray (and also AddRefs them, so that the caller is free to Release its copies).

> I also see that you are not protecting for null values in calls like rv =
> deferredServers[0]-> so once again I would have to check in details the code
> for nsCOMArray to see if it does the protection.
No, it doesn't, but my version of GetDeferredServers only returns non-null POP3 servers, since it happens to save a call to QueryInterface. (If the old code had been using my test for a deferred server then it wouldn't have had to null-check the server either.)
So what now?
Attachment #703874 - Attachment is obsolete: true
Comment on attachment 704319 [details] [diff] [review]
Alternative approach

OK, so this uses the new improved nsCOMArray from bug 493711.

>-        nsCOMPtr <nsIMsgIncomingServer> server (do_QueryElementAt(allServers, i));
>+        nsCOMPtr<nsIPop3IncomingServer> server(do_QueryElementAt(allServers, i));
>         if (server)
This now ensures that only actual nsIPop3IncomingServer objects get added to the array. The change in nsNoIncomingServer relies on this.

>-  void downloadMailFromServers(in nsISupportsArray aServers, 
>-                              in nsIMsgWindow aMsgWindow,
>-                              in nsIMsgFolder aFolder, 
>-                              in nsIUrlListener aListener);
>+  void downloadMailFromServers(
>+    [array, size_is(count)]in nsIPop3IncomingServer aServers,
>+    in unsigned long count, in nsIMsgWindow aMsgWindow,
>+    in nsIMsgFolder aFolder, in nsIUrlListener aListener);
This means that the function is still scriptable. (But I haven't updated the callers yet.)

>-  m_serversToGetNewMailFor = servers;
>+  m_serversToGetNewMailFor.AppendElements(servers, count);
The old code used an nsISupportsArray so you just had to add a new reference to that array to make it keep its contents. The new code uses an array of XPCOM pointers so that the elements of the array have to be appended to a local array. Fortunately the new nsCOMArray makes that easy.

>+    nsCOMPtr<nsIPop3IncomingServer> popServer(m_serversToGetNewMailFor[0]);
>+    m_serversToGetNewMailFor.RemoveObjectAt(0);
>     numServersLeft--;
>     if (popServer)
I left this null-check in as the array could have come from script and therefore potentially contain null elements.
Attachment #704319 - Flags: feedback?(kent)
Blocks: 838805
Comment on attachment 704319 [details] [diff] [review]
Alternative approach

I like this approach with the new nsCOMArray. Memory management seems to be much cleaner, which is what you would hope for with a custom array type.
Attachment #704319 - Flags: feedback?(kent) → feedback+
Attachment #704319 - Flags: review?(mbanner)
rkent, would you mind reviewing this when you already saw it, or do we need to wait for standard8?

Or did Neil choose standard8 intentionally?
Flags: needinfo?(kent)
Attachment #704019 - Attachment is obsolete: true
Attachment #703598 - Attachment is obsolete: true
Assignee: acelists → neil
Status: NEW → ASSIGNED
I would be willing to review this if requested by Neil or Standard8 to do so.
Flags: needinfo?(kent)
Comment on attachment 704319 [details] [diff] [review]
Alternative approach

Review of attachment 704319 [details] [diff] [review]:
-----------------------------------------------------------------

::: mailnews/local/public/nsIPop3IncomingServer.idl
@@ -29,5 @@
>    attribute ACString deferredToAccount;
>    // whether get new mail in deferredToAccount gets
>    // new mail with this server.
>    attribute boolean deferGetNewMail;
> -  void downloadMailFromServers(in nsISupportsArray aServers, 

This file needs a uuid change.
Attachment #704319 - Flags: review?(mbanner) → review+
Pushed comm-central changeset 323851e9e786.
Status: ASSIGNED → RESOLVED
Closed: 11 years ago
Resolution: --- → FIXED
This seem to have caused failures in mail/test/mozmill/instrumentation/test-instrument-setup.js like this:
[Exception... "Not enough arguments [nsIPop3IncomingServer.downloadMailFromServers]"  nsresult: "0x80570001 (NS_ERROR_XPC_NOT_ENOUGH_ARGS)"  location: "JS frame :: chrome://messenger/conte
nt/mailWindowOverlay.js :: MsgGetMessagesForAllServers :: line 1433"  data: no]

But the test still passes, that is why it was not detected.
It seems "Get all mail" does not work for POP3 servers in TB now.
Neil, can you audit all callers of the changed DownloadMailFromServers ?
Flags: needinfo?(neil)
I just created bug 855631 for SeaMonkey because of the get all mails problem.
Depends on: 855631
Thanks for confirmation. So we can move over there.
Flags: needinfo?(neil)
Target Milestone: --- → Thunderbird 22.0
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: