Bug 1471532 - Support Windows in ASan Nightly Reporter builds. r?froydnj
MozReview-Commit-ID: AK2dBOgoazY
--- a/browser/extensions/asan-reporter/bootstrap.js
+++ b/browser/extensions/asan-reporter/bootstrap.js
@@ -24,56 +24,52 @@ const PREF_LOG_LEVEL = "asanreporter.log
// Setup logging
const LOGGER_NAME = "extensions.asanreporter";
let logger = Log.repository.getLogger(LOGGER_NAME);
logger.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
logger.addAppender(new Log.DumpAppender(new Log.BasicFormatter()));
logger.level = Preferences.get(PREF_LOG_LEVEL, Log.Level.Info);
+// Determine the directory where ASan dumps will be located
+let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+let asanDumpDir = OS.Path.join(profileDir.path, "asan");
+
this.TabCrashObserver = {
init() {
if (this.initialized)
return;
this.initialized = true;
Services.obs.addObserver(this, "ipc:content-shutdown");
},
observe(aSubject, aTopic, aData) {
if (aTopic == "ipc:content-shutdown") {
aSubject.QueryInterface(Ci.nsIPropertyBag2);
if (!aSubject.get("abnormal")) {
return;
}
- processDirectory("/tmp");
+ processDirectory(asanDumpDir);
}
},
};
function install(aData, aReason) {}
function uninstall(aData, aReason) {}
function startup(aData, aReason) {
logger.info("Starting up...");
// Install a handler to observe tab crashes, so we can report those right
// after they happen instead of relying on the user to restart the browser.
TabCrashObserver.init();
- // We could use OS.Constants.Path.tmpDir here, but unfortunately there is
- // no way in C++ to get the same value *prior* to xpcom initialization.
- // Since ASan needs its options, including the "log_path" option already
- // at early startup, there is no way to pass this on to ASan.
- //
- // Instead, we hardcode the /tmp directory here, which should be fine in
- // most cases, as long as we are on Linux and Mac (the main targets for
- // this addon at the time of writing).
- processDirectory("/tmp");
+ processDirectory(asanDumpDir);
}
function shutdown(aData, aReason) {
logger.info("Shutting down...");
}
function processDirectory(pathString) {
let iterator = new OS.File.DirectoryIterator(pathString);
--- a/browser/extensions/asan-reporter/clone_asan_reporter.sh
+++ b/browser/extensions/asan-reporter/clone_asan_reporter.sh
@@ -1,11 +1,11 @@
#!/bin/sh
mkdir tmp/
git clone --no-checkout --depth 1 https://github.com/choller/firefox-asan-reporter tmp/
-(cd tmp && git reset --hard d508c6e3f5df752a9a7a2d6f1e4e7261ec2290e7)
+(cd tmp && git reset --hard c42a0b9c131c90cec2a2e93efb77e02e1673316f)
# Copy only whitelisted files
cp tmp/bootstrap.js tmp/install.rdf.in tmp/moz.build tmp/README.md tmp/LICENSE .
# Remove the temporary directory
rm -Rf tmp/
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1074,16 +1074,20 @@ XRE_XPCShellMain(int argc, char** argv,
mozilla::LogModule::Init(argc, argv);
#ifdef MOZ_GECKO_PROFILER
char aLocal;
profiler_init(&aLocal);
#endif
+#ifdef MOZ_ASAN_REPORTER
+ PR_SetEnv("MOZ_DISABLE_ASAN_REPORTER=1");
+#endif
+
if (PR_GetEnv("MOZ_CHAOSMODE")) {
ChaosFeature feature = ChaosFeature::Any;
long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
if (featureInt) {
// NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
feature = static_cast<ChaosFeature>(featureInt);
}
ChaosMode::SetChaosFeature(feature);
--- a/mozglue/build/AsanOptions.cpp
+++ b/mozglue/build/AsanOptions.cpp
@@ -27,24 +27,16 @@
// this will also likely require setting LSAN_OPTIONS with a suppression
// file, as in build/sanitizers/lsan_suppressions.txt.
//
// allocator_may_return_null=1 - Tell ASan to return NULL when an allocation
// fails instead of aborting the program. This allows us to handle failing
// allocations the same way we would handle them with a regular allocator and
// also uncovers potential bugs that might occur in these situations.
//
-// log_path=/tmp/ff_asan_log - When running with the ASan reporter extension
-// enabled (MOZ_ASAN_REPORTER), then we need to dump our logs to files
-// instead of stderr so the reporter extension can find it. Unfortunately,
-// this function is called so early at startup that we can't use the profile
-// directory or even ask XPCOM for a temporary directory. Since the extension
-// is only meant to run on Linux and Mac OSX for now, hardcoding /tmp is an
-// option that should work for most standard environments.
-//
// max_malloc_fill_size - Tell ASan to initialize memory to a certain value
// when it is allocated. This option specifies the maximum allocation size
// for which ASan should still initialize the memory. The value we specify
// here is exactly 256MiB.
//
// max_free_fill_size - Similar to max_malloc_fill_size, tell ASan to
// overwrite memory with a certain value when it is freed. Again, the value
// here specifies the maximum allocation size, larger allocations will
@@ -56,15 +48,13 @@
// are 0xe4 and 0xe5 to match the kAllocPoison and kAllocJunk constants used
// by mozjemalloc.
//
extern "C" MOZ_ASAN_BLACKLIST
const char* __asan_default_options() {
return "allow_user_segv_handler=1:alloc_dealloc_mismatch=0:detect_leaks=0"
":max_free_fill_size=268435456:max_malloc_fill_size=268435456"
":malloc_fill_byte=228:free_fill_byte=229"
-#ifdef MOZ_ASAN_REPORTER
- ":log_path=/tmp/ff_asan_log"
-#endif
+ ":handle_sigill=1"
":allocator_may_return_null=1";
}
#endif
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -336,17 +336,20 @@ SaveFileToEnv(const char *name, nsIFile
#else
nsAutoCString path;
file->GetNativePath(path);
SaveWordToEnv(name, path);
#endif
}
// Load the path of a file saved with SaveFileToEnv
-static already_AddRefed<nsIFile>
+#ifndef MOZ_ASAN_REPORTER
+static
+#endif
+already_AddRefed<nsIFile>
GetFileFromEnv(const char *name)
{
nsresult rv;
nsCOMPtr<nsIFile> file;
#ifdef XP_WIN
WCHAR path[_MAX_PATH];
if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(),
@@ -4240,16 +4243,28 @@ XREMain::XRE_mainStartup(bool* aExitFlag
mozilla::Telemetry::SetProfileDir(mProfD);
if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
MakeOrSetMinidumpPath(mProfD);
CrashReporter::SetProfileDirectory(mProfD);
+#ifdef MOZ_ASAN_REPORTER
+ // In ASan reporter builds, we need to set ASan's log_path as early as
+ // possible, so it dumps its errors into files there instead of using
+ // the default stderr location. Since this is crucial for ASan reporter
+ // to work at all (and we don't want people to use a non-functional
+ // ASan reporter build), all failures while setting log_path are fatal.
+ setASanReporterPath(mProfD);
+
+ // Export to env for child processes
+ SaveFileToEnv("ASAN_REPORTER_PATH", mProfD);
+#endif
+
nsAutoCString version;
BuildVersion(version);
#ifdef TARGET_OS_ABI
NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
#else
// No TARGET_XPCOM_ABI, but at least the OS is known
NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN");
@@ -5289,8 +5304,37 @@ XRE_EnableSameExecutableForContentProc()
}
// Because rust doesn't handle weak symbols, this function wraps the weak
// malloc_handle_oom for it.
extern "C" void
GeckoHandleOOM(size_t size) {
mozalloc_handle_oom(size);
}
+
+#ifdef MOZ_ASAN_REPORTER
+void setASanReporterPath(nsIFile* aDir) {
+ nsCOMPtr<nsIFile> dir;
+ aDir->Clone(getter_AddRefs(dir));
+
+ dir->Append(NS_LITERAL_STRING("asan"));
+ nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700);
+ if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) {
+ MOZ_CRASH("[ASan Reporter] Unable to create crash directory.");
+ }
+
+ dir->Append(NS_LITERAL_STRING("ff_asan_log"));
+
+#ifdef XP_WIN
+ nsAutoString nspathW;
+ rv = dir->GetPath(nspathW);
+ NS_ConvertUTF16toUTF8 nspath(nspathW);
+#else
+ nsAutoCString nspath;
+ rv = dir->GetNativePath(nspath);
+#endif
+ if (NS_FAILED(rv)) {
+ MOZ_CRASH("[ASan Reporter] Unable to get native path for crash directory.");
+ }
+
+ __sanitizer_set_report_path(nspath.get());
+}
+#endif
--- a/toolkit/xre/nsAppRunner.h
+++ b/toolkit/xre/nsAppRunner.h
@@ -124,9 +124,19 @@ const char* PlatformBuildID();
} // namespace mozilla
/**
* Set up platform specific error handling such as suppressing DLL load dialog
* and the JIT debugger on Windows, and install unix signal handlers.
*/
void SetupErrorHandling(const char* progname);
+
+#ifdef MOZ_ASAN_REPORTER
+extern "C" {
+ void MOZ_EXPORT __sanitizer_set_report_path(const char *path);
+}
+void setASanReporterPath(nsIFile* aDir);
+
+already_AddRefed<nsIFile> GetFileFromEnv(const char *name);
+#endif
+
#endif // nsAppRunner_h__
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -355,16 +355,40 @@ XRE_InitChildProcess(int aArgc,
char* aArgv[],
const XREChildData* aChildData)
{
NS_ENSURE_ARG_MIN(aArgc, 2);
NS_ENSURE_ARG_POINTER(aArgv);
NS_ENSURE_ARG_POINTER(aArgv[0]);
MOZ_ASSERT(aChildData);
+#ifdef MOZ_ASAN_REPORTER
+ // In ASan reporter builds, we need to set ASan's log_path as early as
+ // possible, so it dumps its errors into files there instead of using
+ // the default stderr location. Since this is crucial for ASan reporter
+ // to work at all (and we don't want people to use a non-functional
+ // ASan reporter build), all failures while setting log_path are fatal.
+ //
+ // We receive this log_path via the ASAN_REPORTER_PATH environment variable
+ // because there is no other way to generically get the necessary profile
+ // directory in all child types without adding support for that in each
+ // child process type class (at the risk of missing this in a child).
+ //
+ // In certain cases (e.g. child startup through xpcshell or gtests), this
+ // code needs to remain disabled, as no ASAN_REPORTER_PATH would be available.
+ if (!PR_GetEnv("MOZ_DISABLE_ASAN_REPORTER") &&
+ !PR_GetEnv("MOZ_RUN_GTEST")) {
+ nsCOMPtr<nsIFile> asanReporterPath = GetFileFromEnv("ASAN_REPORTER_PATH");
+ if (!asanReporterPath) {
+ MOZ_CRASH("Child did not receive ASAN_REPORTER_PATH!");
+ }
+ setASanReporterPath(asanReporterPath);
+ }
+#endif
+
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
// This has to happen before glib thread pools are started.
mozilla::SandboxEarlyInit();
#endif
#ifdef MOZ_JPROF
// Call the code to install our handler
setupProfilingStuff();