Bug 991791 - Fix some timing-dependent edge cases in nsMemoryReporterManager child handling. r=njn

The patch for bug 946407 changed the state space of
nsMemoryReporterManager in a subtle way: if we're using
MinimizeMemoryUsage with our report, then it's possible for all of
the child processes to finish (or for the timeout to expire) before
the parent has started reporting on itself.  This could cause us to
dereference a null pointer to the state struct in StartGettingReports().

To fix this, we keep track of whether the parent has actually done its
report, and defer finishing the report until then.
This commit is contained in:
Jed Davis
2014-04-07 13:33:00 +02:00
parent 907e7988b2
commit fce3339319
2 changed files with 18 additions and 5 deletions

View File

@@ -1047,9 +1047,10 @@ nsMemoryReporterManager::StartGettingReports()
// Get reports for this process.
GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData,
s->mDMDDumpIdent);
s->mParentDone = true;
// If there are no child processes, we can finish up immediately.
return (s->mNumChildProcesses == 0)
// If there are no remaining child processes, we can finish up immediately.
return (s->mNumChildProcessesCompleted >= s->mNumChildProcesses)
? FinishReporting()
: NS_OK;
}
@@ -1185,7 +1186,8 @@ nsMemoryReporterManager::HandleChildReports(
MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): completed child %d\n",
aGeneration, s->mNumChildProcessesCompleted);
if (s->mNumChildProcessesCompleted == s->mNumChildProcesses) {
if (s->mNumChildProcessesCompleted >= s->mNumChildProcesses &&
s->mParentDone) {
s->mTimer->Cancel();
FinishReporting();
}
@@ -1195,15 +1197,24 @@ nsMemoryReporterManager::HandleChildReports(
nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData)
{
nsMemoryReporterManager* mgr = static_cast<nsMemoryReporterManager*>(aData);
GetReportsState* s = mgr->mGetReportsState;
MOZ_ASSERT(mgr->mGetReportsState);
MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u)\n",
mgr->mGetReportsState->mGeneration);
s->mGeneration);
// We don't bother sending any kind of cancellation message to the child
// processes that haven't reported back.
mgr->FinishReporting();
if (s->mParentDone) {
mgr->FinishReporting();
} else {
// This is unlikely -- the timeout expired during MinimizeMemoryUsage.
MEMORY_REPORTING_LOG("Timeout expired before parent report started!");
// Let the parent continue with its report, but ensure that
// StartGettingReports gives up immediately after that.
s->mNumChildProcesses = s->mNumChildProcessesCompleted;
}
}
nsresult