Closed
Bug 1246048
Opened 9 years ago
Closed 9 years ago
Beware that GetSummaryValid(&valid) does not always set a value to valid.
Categories
(MailNews Core :: Database, defect)
MailNews Core
Database
Tracking
(thunderbird45 fixed, thunderbird46 fixed, thunderbird47 fixed)
RESOLVED
FIXED
Thunderbird 47.0
People
(Reporter: ishikawa, Assigned: ishikawa)
References
Details
Attachments
(1 file, 1 obsolete file)
950 bytes,
patch
|
ishikawa
:
review+
jorgk-bmo
:
approval-comm-aurora+
jorgk-bmo
:
approval-comm-esr45+
|
Details | Diff | Splinter Review |
I reported a bug in 1243895 that was detected by valgrind and a patch.
This bugzilla addresses two more instances where GetSummaryValid() is called, but the argument may not be set, thus may cause uninitialized memory access during run-time.
+++ This bug was initially created as a clone of Bug #1243895 +++
TB. Uninitialized memory access - nsMsgDatabase.cpp. Failure to check the return value of GetSummaryValid(&valid);
Running C-C TB under valgrind after creating a few extra IMAP accounts to look into
Bug 1203977 - Thunderbird crashes in nsImapMailFolder::ParseMsgHdrs
I hit upon an uninitialized value access (I have not seen this for a couple of years now, but
obviously my valgrind coverage is not exhaustive.)
The valgrind report is as follows.
E.g.: The line number 1255 of nsMsgDatabase.cpp is probably off from the
pristine tree since I have many local patches.
--DOMWINDOW == 26 (0x34821cf0) [pid = 14734] [serial = 28] [outer = (nil)] [url = chrome://messenger/content/msgAccountCentral.xul]
==14734== Thread 1:
==14734== Conditional jump or move depends on uninitialised value(s)
==14734== at 0xF4D84E2: nsMsgDatabase::CheckForErrors(nsresult, bool, nsMsgDBService*, nsIFile*) (nsMsgDatabase.cpp:1255)
==14734== by 0xF4D8739: nsMsgDatabase::OpenInternal(nsMsgDBService*, nsIFile*, bool, bool, bool) (nsMsgDatabase.cpp:1221)
==14734== by 0xF4D8D4D: nsMsgDatabase::Open(nsMsgDBService*, nsIFile*, bool, bool) (nsMsgDatabase.cpp:1188)
==14734== by 0xF4CE8A0: nsMailDatabase::Open(nsMsgDBService*, nsIFile*, bool, bool) (nsMailDatabase.cpp:52)
==14734== by 0xF4D7145: nsMsgDBService::OpenMailDBFromFile(nsIFile*, nsIMsgFolder*, bool, bool, nsIMsgDatabase**) (nsMsgDatabase.cpp:356)
==14734== by 0xF3BE13A: nsMsgDBFolder::OpenBackupMsgDatabase() (nsMsgDBFolder.cpp:317)
==14734== by 0xF56B699: nsImapMailFolder::UpdateImapMailboxInfo(nsIImapProtocol*, nsIMailboxSpec*) (nsImapMailFolder.cpp:2748)
==14734== by 0xF5D7A14: (anonymous namespace)::SyncRunnable2<nsIImapMailFolderSink, nsIImapProtocol*, nsIMailboxSpec*>::Run() (nsSyncRunnableHelpers.cpp:146)
==14734== by 0xF7EB33F: nsThread::ProcessNextEvent(bool, bool*) (nsThread.cpp:997)
==14734== by 0xF82FCD8: NS_ProcessNextEvent(nsIThread*, bool) (nsThreadUtils.cpp:297)
==14734== by 0x12CC2495: nsXULWindow::ShowModal() (nsXULWindow.cpp:400)
==14734== by 0x12CBB3C1: nsContentTreeOwner::ShowAsModal() (nsContentTreeOwner.cpp:577)
==14734==
mailnews/db/msgdb/src/nsMsgDatabase.cpp with my local line numbers.
1255 of nsMsgDatabase.cpp
1250 {
1251 if (!newFile && summaryFileExists)
1252 {
1253 bool valid;
1254 GetSummaryValid(&valid);
1255 if (!valid)
1256 err = NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE;
1257 }
1258 // compare current version of db versus filed out version info.
1259 uint32_t version;
So this only means that GetSummaryValid() is returning an error without touching
passed argument.
Checking GetSummaryValid() using mxr.mozilla.org, I find a few implementations,
and one of them certainly looks returning an error without setting the argument.
Ugh...
The characteristics of C-C TB code not to check the return value of lower-level code. Sigh.
Patch attached.
PS: I have no idea if I have hit into a bug of many IMAP account or something. I cannot even send an e-mail after the creation of a few extra imap accounts. /tmp/nsmail.tmp cannot be created !?
Stay tuned.
Assignee | ||
Updated•9 years ago
|
Summary: Be aware that GetSummaryValid(&valid) does not always set a value to valid. → Beware that GetSummaryValid(&valid) does not always set a value to valid.
Assignee | ||
Comment 1•9 years ago
|
||
Here is the patch. I have decided not to check the return value but simply set the variable passed GetSummaryValid() per https://bugzilla.mozilla.org/show_bug.cgi?id=1243895#c4
(bug 1243895 comment 4)
TIA
Attachment #8716138 -
Flags: review?(mkmelin+mozilla)
Assignee | ||
Updated•9 years ago
|
Assignee: nobody → ishikawa
Comment on attachment 8716138 [details] [diff] [review]
GetSummaryValid-returns-without-setting-valid.patch
Review of attachment 8716138 [details] [diff] [review]:
-----------------------------------------------------------------
This seems fine as a robustness measure, but shouldn't we actually fix the function? Or actualy check the return value in addition to the 'valid' return argument? The function can return via NS_ENSURE_ARG_POINTER() without setting the argument as you noticed. Checking the nsresult return value would catch these cases.
Assignee | ||
Comment 3•9 years ago
|
||
(In reply to :aceman from comment #2)
> Comment on attachment 8716138 [details] [diff] [review]
> GetSummaryValid-returns-without-setting-valid.patch
>
> Review of attachment 8716138 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> This seems fine as a robustness measure, but shouldn't we actually fix the
> function? Or actualy check the return value in addition to the 'valid'
> return argument? The function can return via NS_ENSURE_ARG_POINTER()
> without setting the argument as you noticed. Checking the nsresult return
> value would catch these cases.
Let me see.
There are three implementations of GetSummary Valid() in C-C tree:
(1) This one sets a value to the argument always.
http://mxr.mozilla.org/comm-central/source/mailnews/db/msgdb/src/nsImapMailDatabase.cpp#25
25 NS_IMETHODIMP nsImapMailDatabase::GetSummaryValid(bool *aResult)
26 {
27 NS_ENSURE_ARG_POINTER(aResult);
28 if (m_dbFolderInfo)
29 {
30 uint32_t version;
31 m_dbFolderInfo->GetVersion(&version);
32 *aResult = (GetCurVersion() == version);
33 }
34 else
35 *aResult = false;
36
37 return NS_OK;
38 }
(2) This one definitely does not set a value to the argument on its
early return cases.
I am not even sure if the last call
msgStore->IsSummaryFileValid(m_folder, this, aResult)
sets a value to *aResult when IsSummaryFileValid() returns an error.
http://mxr.mozilla.org/comm-central/source/mailnews/db/msgdb/src/nsMailDatabase.cpp#102
This misses !aResult check. Should be there. NEW BUG.
NS_IMETHODIMP nsMailDatabase::GetSummaryValid(bool *aResult)
103 {
104 uint32_t version;
105 m_dbFolderInfo->GetVersion(&version);
106 if (GetCurVersion() != version)
107 {
108 *aResult = false;
109 return NS_OK;
110 }
111 nsCOMPtr<nsIMsgPluggableStore> msgStore;
112 if (!m_folder)
113 return NS_ERROR_NULL_POINTER;
114 nsresult rv = m_folder->GetMsgStore(getter_AddRefs(msgStore));
115 NS_ENSURE_SUCCESS(rv, rv);
116 return msgStore->IsSummaryFileValid(m_folder, this, aResult);
117 }
(3) This one is easy.
This always return a value as long as aResult is not nullptr.
http://mxr.mozilla.org/comm-central/source/mailnews/db/msgdb/src/nsMsgDatabase.cpp#4050
4050 NS_IMETHODIMP nsMsgDatabase::GetSummaryValid(bool *aResult)
4051 {
4052 NS_ENSURE_ARG_POINTER(aResult);
4053 *aResult = true;
4054 return NS_OK;
4055 }
Well, I can certainly check the return values.
Did you read the comment of rkent in the quoted place?
> I have decided not to check the return value but simply set the variable passed > GetSummaryValid() per https://bugzilla.mozilla.org/show_bug.cgi?id=1243895#c4
> (bug 1243895 comment 4)
TIA
PS: I am more disturbed now how IsSummaryFileValid() are written. There seem to be
a few checks missing in there, too (!)
(In reply to ISHIKAWA, Chiaki from comment #3)
> There are three implementations of GetSummary Valid() in C-C tree:
>
> (1) This one sets a value to the argument always.
> http://mxr.mozilla.org/comm-central/source/mailnews/db/msgdb/src/
> nsImapMailDatabase.cpp#25
>
> 25 NS_IMETHODIMP nsImapMailDatabase::GetSummaryValid(bool *aResult)
> 26 {
> 27 NS_ENSURE_ARG_POINTER(aResult);
> 28 if (m_dbFolderInfo)
> 29 {
> 30 uint32_t version;
> 31 m_dbFolderInfo->GetVersion(&version);
> 32 *aResult = (GetCurVersion() == version);
> 33 }
> 34 else
> 35 *aResult = false;
> 36
> 37 return NS_OK;
> 38 }
>
> (2) This one definitely does not set a value to the argument on its
> early return cases.
Yes, on the other hand in this case if it returns on NS_ENSURE_ARG_POINTER() then it can't set the argument as it is nullptr ;)
> I am not even sure if the last call
> msgStore->IsSummaryFileValid(m_folder, this, aResult)
> sets a value to *aResult when IsSummaryFileValid() returns an error.
For safety I would assume it does not.
> http://mxr.mozilla.org/comm-central/source/mailnews/db/msgdb/src/
> nsMailDatabase.cpp#102
>
> This misses !aResult check. Should be there. NEW BUG.
Yes, please do.
> NS_IMETHODIMP nsMailDatabase::GetSummaryValid(bool *aResult)
> 103 {
> 104 uint32_t version;
> 105 m_dbFolderInfo->GetVersion(&version);
> 106 if (GetCurVersion() != version)
> 107 {
> 108 *aResult = false;
> 109 return NS_OK;
> 110 }
> 111 nsCOMPtr<nsIMsgPluggableStore> msgStore;
> 112 if (!m_folder)
> 113 return NS_ERROR_NULL_POINTER;
> 114 nsresult rv = m_folder->GetMsgStore(getter_AddRefs(msgStore));
> 115 NS_ENSURE_SUCCESS(rv, rv);
> 116 return msgStore->IsSummaryFileValid(m_folder, this, aResult);
> 117 }
I probably meant the !m_folder case, where aResult is untouched.
> 111 NS_ENSURE_STATE(m_folder);
> 112 nsCOMPtr<nsIMsgPluggableStore> msgStore;
> Well, I can certainly check the return values.
> Did you read the comment of rkent in the quoted place?
> > I have decided not to check the return value but simply set the variable passed > GetSummaryValid() per https://bugzilla.mozilla.org/show_bug.cgi?id=1243895#c4
> > (bug 1243895 comment 4)
Thanks for pointing this out. But I think that comment only applies in cases where we then do the same whether we got an error or the summary is invalid.
There may be cases where we want to do different action (e.g. 1) report the error in case of NS_FAILED(rv) and 2) delete .msf file if it is invalid (but not if we don't know))
But yes, it seems the cases you patch are of the first type so using just the 'valid' variable seems fine. It just hides if there is an error and we do not report it now, it may blow up later in the code.
In the case where we intentionally do not check the return value we use the convention of prepending (void) '(void) db->GetSummaryValid(&valid)' so that it is clear and prevents the itching of somebody else to add the checking :)
Comment on attachment 8716138 [details] [diff] [review]
GetSummaryValid-returns-without-setting-valid.patch
Review of attachment 8716138 [details] [diff] [review]:
-----------------------------------------------------------------
::: mailnews/local/src/nsLocalMailFolder.cpp
@@ +2051,5 @@
> // this will kick off a reparse if the db is out of date.
> rv = localInbox->GetDatabaseWithReparse(nullptr, aWindow, getter_AddRefs(db));
> if (NS_SUCCEEDED(rv))
> {
> + valid = false; // GetSummaryValid may return without setting valid
Does this actually do anything? Isn't 'valid' set to false above at line 2049 (doesn't seem to be touched since that line)?
@@ +3483,5 @@
> if (mFlags & nsMsgFolderFlags::Inbox)
> {
> if (mDatabase && mCheckForNewMessagesAfterParsing)
> {
> + bool valid = false; // GetSummaryValid may return without setting valid.
Isn't false the default value that the compiler initializes all bool variables? But yes, maybe it is undefined by C++ and may not be guaranteed with all compilers.
Assignee | ||
Comment 6•9 years ago
|
||
(In reply to :aceman from comment #5)
> Comment on attachment 8716138 [details] [diff] [review]
> GetSummaryValid-returns-without-setting-valid.patch
>
> Review of attachment 8716138 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> ::: mailnews/local/src/nsLocalMailFolder.cpp
> @@ +2051,5 @@
> > // this will kick off a reparse if the db is out of date.
> > rv = localInbox->GetDatabaseWithReparse(nullptr, aWindow, getter_AddRefs(db));
> > if (NS_SUCCEEDED(rv))
> > {
> > + valid = false; // GetSummaryValid may return without setting valid
>
> Does this actually do anything? Isn't 'valid' set to false above at line
> 2049 (doesn't seem to be touched since that line)?
Aha, you are right. But then, due to the distance, I obviously missed it.
I would like the initialization to be near where the use is.
Let me think about it.
>
> @@ +3483,5 @@
> > if (mFlags & nsMsgFolderFlags::Inbox)
> > {
> > if (mDatabase && mCheckForNewMessagesAfterParsing)
> > {
> > + bool valid = false; // GetSummaryValid may return without setting valid.
>
> Isn't false the default value that the compiler initializes all bool
> variables? But yes, maybe it is undefined by C++ and may not be guaranteed
> with all compilers.
No, I don't think so. If it were the case, then the original bug 1243895
would not have been reported by valgrind.
===
(In reply to :aceman from comment #4)
> (In reply to ISHIKAWA, Chiaki from comment #3)
> > There are three implementations of GetSummary Valid() in C-C tree:
> >
> > (1) This one sets a value to the argument always.
> > http://mxr.mozilla.org/comm-central/source/mailnews/db/msgdb/src/
> > nsImapMailDatabase.cpp#25
> >
> > 25 NS_IMETHODIMP nsImapMailDatabase::GetSummaryValid(bool *aResult)
> > 26 {
> > 27 NS_ENSURE_ARG_POINTER(aResult);
> > 28 if (m_dbFolderInfo)
> > 29 {
> > 30 uint32_t version;
> > 31 m_dbFolderInfo->GetVersion(&version);
> > 32 *aResult = (GetCurVersion() == version);
> > 33 }
> > 34 else
> > 35 *aResult = false;
> > 36
> > 37 return NS_OK;
> > 38 }
> >
> > (2) This one definitely does not set a value to the argument on its
> > early return cases.
>
> Yes, on the other hand in this case if it returns on NS_ENSURE_ARG_POINTER()
> then it can't set the argument as it is nullptr ;)
>
> > I am not even sure if the last call
> > msgStore->IsSummaryFileValid(m_folder, this, aResult)
> > sets a value to *aResult when IsSummaryFileValid() returns an error.
>
> For safety I would assume it does not.
I agree.
>
> > http://mxr.mozilla.org/comm-central/source/mailnews/db/msgdb/src/
> > nsMailDatabase.cpp#102
> >
> > This misses !aResult check. Should be there. NEW BUG.
>
> Yes, please do.
>
Another bug then.
> > NS_IMETHODIMP nsMailDatabase::GetSummaryValid(bool *aResult)
> > 103 {
> > 104 uint32_t version;
> > 105 m_dbFolderInfo->GetVersion(&version);
> > 106 if (GetCurVersion() != version)
> > 107 {
> > 108 *aResult = false;
> > 109 return NS_OK;
> > 110 }
> > 111 nsCOMPtr<nsIMsgPluggableStore> msgStore;
> > 112 if (!m_folder)
> > 113 return NS_ERROR_NULL_POINTER;
> > 114 nsresult rv = m_folder->GetMsgStore(getter_AddRefs(msgStore));
> > 115 NS_ENSURE_SUCCESS(rv, rv);
> > 116 return msgStore->IsSummaryFileValid(m_folder, this, aResult);
> > 117 }
>
> I probably meant the !m_folder case, where aResult is untouched.
>
> > 111 NS_ENSURE_STATE(m_folder);
> > 112 nsCOMPtr<nsIMsgPluggableStore> msgStore;
>
> > Well, I can certainly check the return values.
> > Did you read the comment of rkent in the quoted place?
> > > I have decided not to check the return value but simply set the variable passed > GetSummaryValid() per https://bugzilla.mozilla.org/show_bug.cgi?id=1243895#c4
> > > (bug 1243895 comment 4)
>
> Thanks for pointing this out. But I think that comment only applies in cases
> where we then do the same whether we got an error or the summary is invalid.
>
> There may be cases where we want to do different action (e.g. 1) report the
> error in case of NS_FAILED(rv) and 2) delete .msf file if it is invalid (but
> not if we don't know))
>
> But yes, it seems the cases you patch are of the first type so using just
> the 'valid' variable seems fine. It just hides if there is an error and we
> do not report it now, it may blow up later in the code.
> In the case where we intentionally do not check the return value we use the
> convention of prepending (void) '(void) db->GetSummaryValid(&valid)' so that
> it is clear and prevents the itching of somebody else to add the checking :)
Placing "(void)" would be a good idea.
Currently, there are so many lo-level function calls that exist but without
being checked of their return values.
It is probably OK to disregard the return values of some such calls, but
it is NOT OBVIOUS to people who want to maintain the code whether ignoring the value
is OK or not.
Maybe a student summer project can do such a rewrite.
Comment 7•9 years ago
|
||
Comment on attachment 8716138 [details] [diff] [review]
GetSummaryValid-returns-without-setting-valid.patch
Review of attachment 8716138 [details] [diff] [review]:
-----------------------------------------------------------------
Stealing another review. The first line you added, we don't need. The second one: Yes, please. r+ with this fixed.
::: mailnews/local/src/nsLocalMailFolder.cpp
@@ +2051,5 @@
> // this will kick off a reparse if the db is out of date.
> rv = localInbox->GetDatabaseWithReparse(nullptr, aWindow, getter_AddRefs(db));
> if (NS_SUCCEEDED(rv))
> {
> + valid = false; // GetSummaryValid may return without setting valid
Please remove this. As Aceman said, this is set to false a few lines above, so we don't need this.
@@ +3483,5 @@
> if (mFlags & nsMsgFolderFlags::Inbox)
> {
> if (mDatabase && mCheckForNewMessagesAfterParsing)
> {
> + bool valid = false; // GetSummaryValid may return without setting valid.
Good practise to initialise "out" variables. The compiler won't initialise local variables. So, yes, please.
Attachment #8716138 -
Flags: review?(mkmelin+mozilla) → review+
Assignee | ||
Comment 8•9 years ago
|
||
Thank you for the review. I will create a patch over the weekend along the line of the suggestions.
Assignee | ||
Comment 9•9 years ago
|
||
I updated the description and added r=mozila@jorgk.com
Attachment #8716138 -
Attachment is obsolete: true
Attachment #8721684 -
Flags: review+
Assignee | ||
Comment 10•9 years ago
|
||
I will put the checkin-needed keyword, tomorrow if there is no objection.
TIA
Comment 11•9 years ago
|
||
OK, I can check it in, it needs to read: r=jorgk.
Don't worry, no new patch required, we'll fix it upon check-in.
![]() |
||
Comment 12•9 years ago
|
||
Status: ASSIGNED → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Target Milestone: --- → Thunderbird 47.0
Updated•9 years ago
|
status-thunderbird45:
--- → affected
status-thunderbird46:
--- → affected
status-thunderbird47:
--- → fixed
Comment 13•9 years ago
|
||
Comment on attachment 8721684 [details] [diff] [review]
GetSummaryValid-returns-without-setting-valid.patch carrying over mozilla@jorgk.com
[Approval Request Comment]
Regression caused by (bug #): No regression.
User impact if declined: Who knows.
I've dug through the code and there are paths (error cases) where the output parameter is not populated. So for general safety I approve/request uplift.
Also, I think we should appreciate the work of Chiaki who works in the underwood to make TB better by weeding out possible sources of error like this one.
Attachment #8721684 -
Flags: approval-comm-beta?
Attachment #8721684 -
Flags: approval-comm-aurora+
Assignee | ||
Comment 14•9 years ago
|
||
(In reply to Jorg K (GMT+1) from comment #11)
> OK, I can check it in, it needs to read: r=jorgk.
> Don't worry, no new patch required, we'll fix it upon check-in.
Thank you for fixing the approval signature. Also, thank you for the nice words in comment 13: witout valgrind/memcheck I could not have realized the issue. Strange, though, the error cropped up only now. I have been running valgrind/memcheck quite sometime, and so it must be that the code change elsewhere has caused the issue surface lately.
I vaguely recall that there was an obscure issue caused by GetSummaryValid() returning strange value (maybe not returning it) after compaction. I will dig into it again.
TIA
Comment 15•9 years ago
|
||
Aurora (TB 46):
https://hg.mozilla.org/releases/comm-aurora/rev/e41c21e476da
Comment 16•9 years ago
|
||
Comment on attachment 8721684 [details] [diff] [review]
GetSummaryValid-returns-without-setting-valid.patch carrying over mozilla@jorgk.com
http://hg.mozilla.org/releases/comm-esr45/rev/c82da2901ce8
Attachment #8721684 -
Flags: approval-comm-beta? → approval-comm-beta+
Updated•9 years ago
|
Updated•9 years ago
|
Attachment #8721684 -
Flags: approval-comm-beta+ → approval-comm-esr45+
You need to log in
before you can comment on or make changes to this bug.
Description
•