diff --git a/browser/extensions/asan-reporter/bootstrap.js b/browser/extensions/asan-reporter/bootstrap.js index a383c1a6d7c0..61d6be922626 100644 --- a/browser/extensions/asan-reporter/bootstrap.js +++ b/browser/extensions/asan-reporter/bootstrap.js @@ -29,6 +29,10 @@ 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) @@ -44,7 +48,7 @@ this.TabCrashObserver = { if (!aSubject.get("abnormal")) { return; } - processDirectory("/tmp"); + processDirectory(asanDumpDir); } }, }; @@ -60,15 +64,7 @@ function startup(aData, aReason) { // 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) { diff --git a/browser/extensions/asan-reporter/clone_asan_reporter.sh b/browser/extensions/asan-reporter/clone_asan_reporter.sh index f34e61ef3fd8..9019b9495f10 100755 --- a/browser/extensions/asan-reporter/clone_asan_reporter.sh +++ b/browser/extensions/asan-reporter/clone_asan_reporter.sh @@ -2,7 +2,7 @@ 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 . diff --git a/mozglue/build/AsanOptions.cpp b/mozglue/build/AsanOptions.cpp index 4f19e099bcc8..c2c1208d8d2f 100644 --- a/mozglue/build/AsanOptions.cpp +++ b/mozglue/build/AsanOptions.cpp @@ -32,14 +32,6 @@ // 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 @@ -61,9 +53,7 @@ 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"; } diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 470d3357d72a..79b7dc8aca4c 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -341,7 +341,10 @@ SaveFileToEnv(const char *name, nsIFile *file) } // Load the path of a file saved with SaveFileToEnv -static already_AddRefed +#ifndef MOZ_ASAN_REPORTER +static +#endif +already_AddRefed GetFileFromEnv(const char *name) { nsresult rv; @@ -4245,6 +4248,18 @@ XREMain::XRE_mainStartup(bool* aExitFlag) 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); @@ -5294,3 +5309,32 @@ extern "C" void GeckoHandleOOM(size_t size) { mozalloc_handle_oom(size); } + +#ifdef MOZ_ASAN_REPORTER +void setASanReporterPath(nsIFile* aDir) { + nsCOMPtr 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 diff --git a/toolkit/xre/nsAppRunner.h b/toolkit/xre/nsAppRunner.h index afca2fab67bd..ee3309b1ddf9 100644 --- a/toolkit/xre/nsAppRunner.h +++ b/toolkit/xre/nsAppRunner.h @@ -129,4 +129,14 @@ const char* PlatformBuildID(); */ 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 GetFileFromEnv(const char *name); +#endif + #endif // nsAppRunner_h__ diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 05e1c9dd5d3a..aabc3fddc790 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -360,6 +360,24 @@ XRE_InitChildProcess(int aArgc, 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). + nsCOMPtr 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();