Bug 1571648 - Prevent OOMs from too many or too-big Decoder Doctor issues - r=bryce

DecoderDoctorDiagnostics had no limitations on reported and stored issues.

New limitations, per document:
- No more than 128 issues are kept at any time.
- Issues older than 10 seconds are discarded.
- Issues containing too-long text (more than 2048 characters) are ignored.

Differential Revision: https://phabricator.services.mozilla.com/D45480

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Gerald Squelart 2019-09-11 16:55:35 +00:00
Родитель 9ead971a06
Коммит f66f85f869
1 изменённых файлов: 65 добавлений и 7 удалений

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/dom/DecoderDoctorNotificationBinding.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/TimeStamp.h"
#include "nsContentUtils.h"
#include "nsGkAtoms.h"
#include "mozilla/dom/Document.h"
@ -85,17 +86,21 @@ class DecoderDoctorDocumentWatcher : public nsITimerCallback, public nsINamed {
dom::Document* mDocument;
struct Diagnostics {
Diagnostics(DecoderDoctorDiagnostics&& aDiagnostics, const char* aCallSite)
Diagnostics(DecoderDoctorDiagnostics&& aDiagnostics, const char* aCallSite,
mozilla::TimeStamp aTimeStamp)
: mDecoderDoctorDiagnostics(std::move(aDiagnostics)),
mCallSite(aCallSite) {}
mCallSite(aCallSite),
mTimeStamp(aTimeStamp) {}
Diagnostics(const Diagnostics&) = delete;
Diagnostics(Diagnostics&& aOther)
: mDecoderDoctorDiagnostics(
std::move(aOther.mDecoderDoctorDiagnostics)),
mCallSite(std::move(aOther.mCallSite)) {}
mCallSite(std::move(aOther.mCallSite)),
mTimeStamp(aOther.mTimeStamp) {}
const DecoderDoctorDiagnostics mDecoderDoctorDiagnostics;
const nsCString mCallSite;
const mozilla::TimeStamp mTimeStamp;
};
typedef nsTArray<Diagnostics> DiagnosticsSequence;
DiagnosticsSequence mDiagnosticsSequence;
@ -354,10 +359,10 @@ static void ReportToConsole(dom::Document* aDocument,
aDocument, aConsoleStringId,
aParams.IsEmpty() ? "<no params>"
: NS_ConvertUTF16toUTF8(aParams[0]).get(),
(aParams.Length() < 1 || aParams[1].IsEmpty()) ? "" : ", ",
(aParams.Length() < 1 || aParams[1].IsEmpty())
(aParams.Length() < 1 || aParams[0].IsEmpty()) ? "" : ", ",
(aParams.Length() < 1 || aParams[0].IsEmpty())
? ""
: NS_ConvertUTF16toUTF8(aParams[1]).get(),
: NS_ConvertUTF16toUTF8(aParams[0]).get(),
aParams.Length() < 2 ? "" : ", ...");
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Media"), aDocument,
@ -759,12 +764,28 @@ void DecoderDoctorDocumentWatcher::AddDiagnostics(
return;
}
const mozilla::TimeStamp now = mozilla::TimeStamp::Now();
constexpr size_t MaxDiagnostics = 128;
constexpr double MaxSeconds = 10.0;
while (
mDiagnosticsSequence.Length() > MaxDiagnostics ||
(!mDiagnosticsSequence.IsEmpty() &&
(now - mDiagnosticsSequence[0].mTimeStamp).ToSeconds() > MaxSeconds)) {
// Too many, or too old.
mDiagnosticsSequence.RemoveElementAt(0);
if (mDiagnosticsHandled != 0) {
// Make sure Notify picks up the new element added below.
--mDiagnosticsHandled;
}
}
DD_DEBUG(
"DecoderDoctorDocumentWatcher[%p, "
"doc=%p]::AddDiagnostics(DecoderDoctorDiagnostics{%s}, call site '%s')",
this, mDocument, aDiagnostics.GetDescription().Data(), aCallSite);
mDiagnosticsSequence.AppendElement(
Diagnostics(std::move(aDiagnostics), aCallSite));
Diagnostics(std::move(aDiagnostics), aCallSite, now));
EnsureTimerIsStarted();
}
@ -818,6 +839,15 @@ void DecoderDoctorDiagnostics::StoreFormatDiagnostics(dom::Document* aDocument,
MOZ_ASSERT(mDiagnosticsType == eUnsaved);
mDiagnosticsType = eFormatSupportCheck;
if (NS_WARN_IF(aFormat.Length() > 2048)) {
DD_WARN(
"DecoderDoctorDiagnostics[%p]::StoreFormatDiagnostics(Document* "
"aDocument=%p, format= TOO LONG! '%s', can-play=%d, call site '%s')",
aDocument, this, NS_ConvertUTF16toUTF8(aFormat).get(), aCanPlay,
aCallSite);
return;
}
if (NS_WARN_IF(!aDocument)) {
DD_WARN(
"DecoderDoctorDiagnostics[%p]::StoreFormatDiagnostics(Document* "
@ -865,6 +895,16 @@ void DecoderDoctorDiagnostics::StoreMediaKeySystemAccess(
MOZ_ASSERT(mDiagnosticsType == eUnsaved);
mDiagnosticsType = eMediaKeySystemAccessRequest;
if (NS_WARN_IF(aKeySystem.Length() > 2048)) {
DD_WARN(
"DecoderDoctorDiagnostics[%p]::StoreMediaKeySystemAccess(Document* "
"aDocument=%p, keysystem= TOO LONG! '%s', supported=%d, call site "
"'%s')",
aDocument, this, NS_ConvertUTF16toUTF8(aKeySystem).get(), aIsSupported,
aCallSite);
return;
}
if (NS_WARN_IF(!aDocument)) {
DD_WARN(
"DecoderDoctorDiagnostics[%p]::StoreMediaKeySystemAccess(Document* "
@ -954,6 +994,24 @@ void DecoderDoctorDiagnostics::StoreDecodeError(dom::Document* aDocument,
MOZ_ASSERT(mDiagnosticsType == eUnsaved);
mDiagnosticsType = eDecodeError;
if (NS_WARN_IF(aError.Message().Length() > 2048)) {
DD_WARN(
"DecoderDoctorDiagnostics[%p]::StoreDecodeError(Document* "
"aDocument=%p, aError= TOO LONG! '%s', aMediaSrc=<provided>, call site "
"'%s')",
aDocument, this, aError.Description().get(), aCallSite);
return;
}
if (NS_WARN_IF(aMediaSrc.Length() > 2048)) {
DD_WARN(
"DecoderDoctorDiagnostics[%p]::StoreDecodeError(Document* "
"aDocument=%p, aError=%s, aMediaSrc= TOO LONG! <provided>, call site "
"'%s')",
aDocument, this, aError.Description().get(), aCallSite);
return;
}
if (NS_WARN_IF(!aDocument)) {
DD_WARN(
"DecoderDoctorDiagnostics[%p]::StoreDecodeError("