Index: syzygy/agent/asan/runtime.cc |
diff --git a/syzygy/agent/asan/runtime.cc b/syzygy/agent/asan/runtime.cc |
index bd851fb2179d9d31842e50a5dc89d1da12678361..9ec64bd6ab220a393748a205884775ce385782c7 100644 |
--- a/syzygy/agent/asan/runtime.cc |
+++ b/syzygy/agent/asan/runtime.cc |
@@ -67,6 +67,13 @@ using agent::asan::AsanLogger; |
using agent::asan::StackCaptureCache; |
using agent::asan::WindowsHeapAdapter; |
+enum CrashReporterType { |
+ kDefaultCrashReporterType, |
+ kBreakpadCrashReporterType, |
+ kKaskoCrashReporterType, |
+ kCrashpadCrashReporterType, |
+}; |
+ |
// A custom exception code we use to indicate that the exception originated |
// from Asan, and shouldn't be processed again by our unhandled exception |
// handler. This value has been created according to the rules here: |
@@ -387,45 +394,63 @@ void LaunchMessageBox(const base::StringPiece& message) { |
::MessageBoxA(nullptr, message.data(), nullptr, MB_OK | MB_ICONEXCLAMATION); |
} |
-std::unique_ptr<ReporterInterface> CreateCrashReporter(AsanLogger* logger) { |
+// Gets the preferred crash reporter type from the environment. This will |
+// override experiments or command-lines, and is largely meant for local |
+// testing. |
+CrashReporterType GetCrashReporterTypeFromEnvironment( |
+ AsanLogger* logger) { |
+ DCHECK_NE(static_cast<AsanLogger*>(nullptr), logger); |
std::unique_ptr<ReporterInterface> reporter; |
- // First try to grab the preferred crash reporter, overridden by the |
- // environment. |
std::unique_ptr<base::Environment> env(base::Environment::Create()); |
std::string reporter_name; |
- if (env->GetVar("SYZYASAN_CRASH_REPORTER", &reporter_name)) { |
- if (reporter_name == "crashpad") |
- reporter.reset(reporters::CrashpadReporter::Create().release()); |
- else if (reporter_name == "kasko") |
- reporter.reset(reporters::KaskoReporter::Create().release()); |
- else if (reporter_name == "breakpad") |
- reporter.reset(reporters::BreakpadReporter::Create().release()); |
- |
- if (reporter.get() != nullptr) { |
- logger->Write(base::StringPrintf( |
- "Using requested \"%s\" crash reporter.", reporter_name)); |
- return reporter; |
- } else { |
- logger->Write(base::StringPrintf( |
- "Unable to create requested \"%s\" crash reporter.", reporter_name)); |
- } |
+ static const char kSyzyAsanCrashReporterEnv[] = |
+ "SYZYASAN_CRASH_REPORTER"; |
+ if (!env->GetVar(kSyzyAsanCrashReporterEnv, &reporter_name)) |
+ return kDefaultCrashReporterType; |
+ |
+ CrashReporterType type = kDefaultCrashReporterType; |
+ if (reporter_name == "crashpad") { |
+ type = kCrashpadCrashReporterType; |
+ } else if (reporter_name == "kasko") { |
+ type = kKaskoCrashReporterType; |
+ } else if (reporter_name == "breakpad") { |
+ type = kBreakpadCrashReporterType; |
+ } |
+ |
+ if (type != kDefaultCrashReporterType) { |
+ logger->Write(base::StringPrintf("Encountered %s=\"%s\".", |
+ kSyzyAsanCrashReporterEnv, reporter_name.c_str())); |
+ } else { |
+ logger->Write(base::StringPrintf("Ignoring %s=\"%s\".", |
+ kSyzyAsanCrashReporterEnv, reporter_name.c_str())); |
} |
- // No crash reporter was explicitly specified, or it was unable to be |
- // initialized. Try all of them, starting with the most recent. |
+ return type; |
+} |
+ |
+// Attempts to create a crash reporter, starting with the most modern. |
+std::unique_ptr<ReporterInterface> CreateCrashReporterWithTypeHint( |
+ AsanLogger* logger, CrashReporterType reporter_type) { |
+ std::unique_ptr<ReporterInterface> reporter; |
- // Don't try grabbing a Crashpad reporter by default, as we're not yet |
- // ready to ship this. |
- // TODO(chrisha): Add Crashpad support behind a feature flag. |
+ // Crashpad is not yet enabled by default. |
+ if (reporter_type == kCrashpadCrashReporterType) |
+ reporter.reset(reporters::CrashpadReporter::Create().release()); |
// Try to initialize a Kasko crash reporter. |
- if (reporter.get() == nullptr) |
+ if (reporter.get() == nullptr && |
+ (reporter_type == kKaskoCrashReporterType || |
+ reporter_type == kDefaultCrashReporterType)) { |
reporter.reset(reporters::KaskoReporter::Create().release()); |
+ } |
// If that failed then try to initialize a Breakpad reporter. |
- if (reporter.get() == nullptr) |
+ if (reporter.get() == nullptr && |
+ (reporter_type == kBreakpadCrashReporterType || |
+ reporter_type == kDefaultCrashReporterType)) { |
reporter.reset(reporters::BreakpadReporter::Create().release()); |
+ } |
return reporter; |
} |
@@ -483,9 +508,23 @@ bool AsanRuntime::SetUp(const std::wstring& flags_command_line) { |
return false; |
WindowsHeapAdapter::SetUp(heap_manager_.get()); |
+ // Determine the preferred crash reporter type, as specified in the |
+ // environment. If this isn't present it defaults to |
+ // kDefaultCrashReporterType, in which case experiments or command-line flags |
+ // may specify the crash reporter to use. |
+ CrashReporterType crash_reporter_type = |
+ GetCrashReporterTypeFromEnvironment(logger()); |
+ |
if (params_.feature_randomization) { |
AsanFeatureSet feature_set = GenerateRandomFeatureSet(); |
PropagateFeatureSet(feature_set); |
+ |
+ // If no specific crash reporter has been specified, then allow the |
+ // experiment to specify it. |
+ if (crash_reporter_type == kDefaultCrashReporterType && |
+ (feature_set & ASAN_FEATURE_ENABLE_CRASHPAD) != 0) { |
+ crash_reporter_type = kCrashpadCrashReporterType; |
+ } |
} |
// Propagates the flags values to the different modules. |
@@ -493,11 +532,16 @@ bool AsanRuntime::SetUp(const std::wstring& flags_command_line) { |
// The name 'disable_breakpad_reporting' is legacy; this actually means to |
// disable all external crash reporting integration. |
- if (!params_.disable_breakpad_reporting) |
- crash_reporter_.reset(CreateCrashReporter(logger()).release()); |
+ if (!params_.disable_breakpad_reporting) { |
+ // This will create the crash reporter with a preference for creating a |
+ // reporter of the hinted type. If such a reporter isn't available, it will |
+ // fall back to trying to create the most 'modern' reporter available. |
+ crash_reporter_.reset(CreateCrashReporterWithTypeHint( |
+ logger(), crash_reporter_type).release()); |
+ } |
// Set up the appropriate error handler depending on whether or not |
- // we successfully found a crash reporter. |
+ // we successfully initialized a crash reporter. |
if (crash_reporter_.get() != nullptr) { |
logger_->Write(base::StringPrintf( |
"SyzyASAN: Using %s for error reporting.", |
@@ -961,6 +1005,7 @@ void AsanRuntime::LogAsanErrorInfo(AsanErrorInfo* error_info) { |
} |
} |
+// static |
AsanFeatureSet AsanRuntime::GenerateRandomFeatureSet() { |
AsanFeatureSet enabled_features = |
static_cast<AsanFeatureSet>(base::RandGenerator(ASAN_FEATURE_MAX)); |
@@ -1199,6 +1244,10 @@ AsanFeatureSet AsanRuntime::GetEnabledFeatureSet() { |
enabled_features |= ASAN_FEATURE_ENABLE_PAGE_PROTECTIONS; |
if (params_.enable_large_block_heap) |
enabled_features |= ASAN_FEATURE_ENABLE_LARGE_BLOCK_HEAP; |
+ if (crash_reporter_.get() != nullptr && |
+ crash_reporter_->GetName() == reporters::CrashpadReporter::kName) { |
+ enabled_features |= ASAN_FEATURE_ENABLE_CRASHPAD; |
+ } |
return enabled_features; |
} |