Bug 1403348: Part 4 - Annotate certain startup crashes with AsyncShutdown script contents. r=mccr8 data-r=rweiss

We're seeing startup crashes which point to data corruption in the source of
the AsyncShutdown component and module, but it's unclear whether the source of
this corruption is on disk, in memory, or in XDR data.

This change annotates crash reports with the contents of those files, so that
we can compare the actual source with the corrupted values in the generated
errors, and narrow down the source of the corruption.

MozReview-Commit-ID: 7p8y73XUGLK

--HG--
extra : rebase_source : 8e1b85df0cf69556af6f998f3d638bf2033e6ca0
extra : source : cf8613751378c8790b56131cd2a1be68573f9286
This commit is contained in:
Kris Maglione 2017-11-04 17:20:17 -07:00
parent 7d6982559e
commit a036df8b65
5 changed files with 95 additions and 30 deletions

View File

@ -26,6 +26,7 @@
#include "mozilla/ModuleUtils.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "mozJSComponentLoader.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsContentUtils.h"
#include "nsDirectoryServiceUtils.h"
@ -1134,6 +1135,7 @@ ServiceWorkerRegistrar::GetState(nsIPropertyBag**)
#define RELEASE_ASSERT_SUCCEEDED(rv, name) do { \
if (NS_FAILED(rv)) { \
mozJSComponentLoader::Get()->AnnotateCrashReport(); \
if (rv == NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS) { \
if (auto* context = CycleCollectedJSContext::Get()) { \
if (RefPtr<Exception> exn = context->GetPendingException()) { \

View File

@ -66,6 +66,10 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/js/xpconnect/loader',
]
MOCHITEST_MANIFESTS += [
'test/mochitest.ini',
]

View File

@ -69,6 +69,7 @@ LOCAL_INCLUDES += [
'../system',
'/dom/base',
'/dom/bindings',
'/js/xpconnect/loader',
'/xpcom/build',
'/xpcom/threads',
]

View File

@ -49,6 +49,7 @@
#include "mozilla/scache/StartupCacheUtils.h"
#include "mozilla/MacroForEach.h"
#include "mozilla/Preferences.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/ScriptPreloader.h"
#include "mozilla/dom/DOMPrefs.h"
#include "mozilla/dom/ScriptSettings.h"
@ -56,6 +57,10 @@
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/Unused.h"
#ifdef MOZ_CRASHREPORTER
#include "mozilla/ipc/CrashReporterClient.h"
#endif
using namespace mozilla;
using namespace mozilla::scache;
using namespace mozilla::loader;
@ -359,6 +364,45 @@ ResolveModuleObjectProperty(JSContext* aCx, HandleObject aModObj, const char* na
return aModObj;
}
#ifdef MOZ_CRASHREPORTER
static mozilla::Result<nsCString, nsresult> ReadScript(ComponentLoaderInfo& aInfo);
static nsresult
AnnotateScriptContents(const nsACString& aName, const nsACString& aURI)
{
ComponentLoaderInfo info(aURI);
nsCString str;
MOZ_TRY_VAR(str, ReadScript(info));
// The crash reporter won't accept any strings with embedded nuls. We
// shouldn't have any here, but if we do because of data corruption, we
// still want the annotation. So replace any embedded nuls before
// annotating.
str.ReplaceSubstring(NS_LITERAL_CSTRING("\0"), NS_LITERAL_CSTRING("\\0"));
CrashReporter::AnnotateCrashReport(aName, str);
return NS_OK;
}
#endif // defined MOZ_CRASHREPORTER
nsresult
mozJSComponentLoader::AnnotateCrashReport()
{
#ifdef MOZ_CRASHREPORTER
Unused << AnnotateScriptContents(
NS_LITERAL_CSTRING("nsAsyncShutdownComponent"),
NS_LITERAL_CSTRING("resource://gre/components/nsAsyncShutdown.js"));
Unused << AnnotateScriptContents(
NS_LITERAL_CSTRING("AsyncShutdownModule"),
NS_LITERAL_CSTRING("resource://gre/modules/AsyncShutdown.jsm"));
#endif // defined MOZ_CRASHREPORTER
return NS_OK;
}
const mozilla::Module*
mozJSComponentLoader::LoadModule(FileLocation& aFile)
{
@ -401,6 +445,8 @@ mozJSComponentLoader::LoadModule(FileLocation& aFile)
if (NS_FAILED(rv)) {
// Temporary debugging assertion for bug 1403348:
if (isCriticalModule && !exn.isUndefined()) {
AnnotateCrashReport();
JSAutoCompartment ac(cx, xpc::PrivilegedJunkScope());
JS_WrapValue(cx, &exn);
@ -705,6 +751,36 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
return thisObj;
}
static mozilla::Result<nsCString, nsresult>
ReadScript(ComponentLoaderInfo& aInfo)
{
MOZ_TRY(aInfo.EnsureScriptChannel());
nsCOMPtr<nsIInputStream> scriptStream;
MOZ_TRY(NS_MaybeOpenChannelUsingOpen2(aInfo.ScriptChannel(),
getter_AddRefs(scriptStream)));
uint64_t len64;
uint32_t bytesRead;
MOZ_TRY(scriptStream->Available(&len64));
NS_ENSURE_TRUE(len64 < UINT32_MAX, Err(NS_ERROR_FILE_TOO_BIG));
NS_ENSURE_TRUE(len64, Err(NS_ERROR_FAILURE));
uint32_t len = (uint32_t)len64;
/* malloc an internal buf the size of the file */
nsCString str;
if (!str.SetLength(len, fallible))
return Err(NS_ERROR_OUT_OF_MEMORY);
/* read the file in one swoop */
MOZ_TRY(scriptStream->Read(str.BeginWriting(), len, &bytesRead));
if (bytesRead != len)
return Err(NS_BASE_STREAM_OSERROR);
return Move(str);
}
nsresult
mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
nsIFile* aComponentFile,
@ -795,39 +871,13 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
else
Compile(cx, options, buf.get(), map.size(), &script);
} else {
rv = aInfo.EnsureScriptChannel();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInputStream> scriptStream;
rv = NS_MaybeOpenChannelUsingOpen2(aInfo.ScriptChannel(),
getter_AddRefs(scriptStream));
NS_ENSURE_SUCCESS(rv, rv);
uint64_t len64;
uint32_t bytesRead;
rv = scriptStream->Available(&len64);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(len64 < UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
if (!len64)
return NS_ERROR_FAILURE;
uint32_t len = (uint32_t)len64;
/* malloc an internal buf the size of the file */
auto buf = MakeUniqueFallible<char[]>(len + 1);
if (!buf)
return NS_ERROR_OUT_OF_MEMORY;
/* read the file in one swoop */
rv = scriptStream->Read(buf.get(), len, &bytesRead);
if (bytesRead != len)
return NS_BASE_STREAM_OSERROR;
buf[len] = '\0';
nsCString str;
MOZ_TRY_VAR(str, ReadScript(aInfo));
if (reuseGlobal)
CompileForNonSyntacticScope(cx, options, buf.get(), bytesRead, &script);
CompileForNonSyntacticScope(cx, options, str.get(), str.Length(), &script);
else
Compile(cx, options, buf.get(), bytesRead, &script);
Compile(cx, options, str.get(), str.Length(), &script);
}
// Propagate the exception, if one exists. Also, don't leave the stale
// exception on this context.

View File

@ -78,6 +78,14 @@ class mozJSComponentLoader final : public mozilla::ModuleLoader,
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
/**
* Temporary diagnostic function for startup crashes in bug 1403348:
*
* Annotate the crash report with the contents of the async shutdown
* module/component scripts.
*/
nsresult AnnotateCrashReport();
protected:
virtual ~mozJSComponentLoader();