From 4ad08c82f7f571e1a932120ef9569eb6f8d66500 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 26 Nov 2020 14:27:01 +0100 Subject: [PATCH] Enable simulating errors to test fuzzer reliability This adds a d8 flag --simulate-errors, which on shutdown will cause certain errors. This enables testing the reliability of sanitizers. This will cause a fatal error, a dcheck (if available) or a violation that can be detected with one of the following sanitizers: ASAN, UBSAN, MSAN, CFI. The same flag used in differential fuzzing will cause an error subsumed with the error state "fake_difference". Bug: chromium:1152412 Change-Id: I4b36c6fe716797004d634263617d22ca67b05600 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2554999 Commit-Queue: Michael Achenbach Reviewed-by: Clemens Backes Cr-Commit-Position: refs/heads/master@{#71430} --- src/d8/d8.cc | 51 ++++++++++++++++++++++++++++ src/d8/d8.h | 2 ++ tools/clusterfuzz/v8_suppressions.py | 2 ++ 3 files changed, 55 insertions(+) diff --git a/src/d8/d8.cc b/src/d8/d8.cc index 7bcf4bcf1a..78e1cef834 100644 --- a/src/d8/d8.cc +++ b/src/d8/d8.cc @@ -2645,6 +2645,54 @@ void Shell::OnExit(v8::Isolate* isolate) { delete counters_file_; delete counter_map_; + + if (options.simulate_errors) { + // Simulate several errors detectable by fuzzers behind a flag. + SimulateErrors(); + } +} + +void Dummy(char* arg) {} + +void Shell::SimulateErrors() { + // Initialize a fresh RNG to not interfere with JS execution. + std::unique_ptr rng; + int64_t seed = internal::FLAG_random_seed; + if (seed != 0) { + rng = std::make_unique(seed); + } else { + rng = std::make_unique(); + } + + double p = rng->NextDouble(); + if (p < 0.1) { + // Caught in all build types. + FATAL("Fake error."); + } else if (p < 0.2) { + // Caught in debug builds. + DCHECK(false); + } else if (p < 0.3) { + // Caught by UBSAN. + int32_t val = -1; + USE(val << 8); + } else if (p < 0.4) { + // Use-after-free caught by ASAN. + std::vector* storage = new std::vector(3); + delete storage; + USE(storage->at(1)); + } else if (p < 0.5) { + // Use-of-uninitialized-value caught by MSAN. + int uninitialized[1]; + if (uninitialized[0]) + USE(uninitialized); + } else if (p < 0.6) { + // Control flow violation caught by CFI. + void (*func)() = (void (*)()) & Dummy; + func(); + } else if (p < 0.7) { + // Observable difference caught by differential fuzzing. + printf("___fake_difference___\n"); + } } static FILE* FOpen(const char* path, const char* mode) { @@ -3392,6 +3440,9 @@ bool Shell::SetOptions(int argc, char* argv[]) { } else if (strcmp(argv[i], "--no-arguments") == 0) { options.include_arguments = false; argv[i] = nullptr; + } else if (strcmp(argv[i], "--simulate-errors") == 0) { + options.simulate_errors = true; + argv[i] = nullptr; } else if (strcmp(argv[i], "--stress-opt") == 0) { options.stress_opt = true; argv[i] = nullptr; diff --git a/src/d8/d8.h b/src/d8/d8.h index 0bb4b380c9..2931257f0d 100644 --- a/src/d8/d8.h +++ b/src/d8/d8.h @@ -343,6 +343,7 @@ class ShellOptions { DisallowReassignment omit_quit = {"omit-quit", false}; DisallowReassignment wait_for_background_tasks = { "wait-for-background-tasks", true}; + DisallowReassignment simulate_errors = {"simulate-errors", false}; DisallowReassignment stress_opt = {"stress-opt", false}; DisallowReassignment stress_runs = {"stress-runs", 1}; DisallowReassignment stress_snapshot = {"stress-snapshot", false}; @@ -622,6 +623,7 @@ class Shell : public i::AllStatic { Local name); static void StoreInCodeCache(Isolate* isolate, Local name, const ScriptCompiler::CachedData* data); + static void SimulateErrors(); // We may have multiple isolates running concurrently, so the access to // the isolate_status_ needs to be concurrency-safe. static base::LazyMutex isolate_status_lock_; diff --git a/tools/clusterfuzz/v8_suppressions.py b/tools/clusterfuzz/v8_suppressions.py index 71c69fb6b2..684d9740bf 100644 --- a/tools/clusterfuzz/v8_suppressions.py +++ b/tools/clusterfuzz/v8_suppressions.py @@ -57,6 +57,8 @@ IGNORE_TEST_CASES = { IGNORE_OUTPUT = { 'crbug.com/689877': re.compile(r'^.*SyntaxError: .*Stack overflow$', re.M), + 'fake_difference': + re.compile(r'^.*___fake_difference___$', re.M), } # Lines matching any of the following regular expressions will be ignored