Coverage for /Syzygy/agent/asan/runtime.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
86.3%4865630.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/agent/asan/runtime.h"
  16    :  
  17    :  #include <algorithm>
  18    :  #include <utility>
  19    :  #include <vector>
  20    :  
  21    :  #include "base/bind.h"
  22    :  #include "base/command_line.h"
  23    :  #include "base/environment.h"
  24    :  #include "base/file_version_info.h"
  25    :  #include "base/logging.h"
  26    :  #include "base/path_service.h"
  27    :  #include "base/rand_util.h"
  28    :  #include "base/version.h"
  29    :  #include "base/strings/string_number_conversions.h"
  30    :  #include "base/strings/stringprintf.h"
  31    :  #include "base/strings/sys_string_conversions.h"
  32    :  #include "base/strings/utf_string_conversions.h"
  33    :  #include "base/win/pe_image.h"
  34    :  #include "base/win/wrapped_window_proc.h"
  35    :  #include "syzygy/agent/asan/block.h"
  36    :  #include "syzygy/agent/asan/crt_interceptors.h"
  37    :  #include "syzygy/agent/asan/heap_checker.h"
  38    :  #include "syzygy/agent/asan/logger.h"
  39    :  #include "syzygy/agent/asan/memory_interceptors.h"
  40    :  #include "syzygy/agent/asan/memory_interceptors_patcher.h"
  41    :  #include "syzygy/agent/asan/page_protection_helpers.h"
  42    :  #include "syzygy/agent/asan/shadow.h"
  43    :  #include "syzygy/agent/asan/stack_capture_cache.h"
  44    :  #include "syzygy/agent/asan/system_interceptors.h"
  45    :  #include "syzygy/agent/asan/windows_heap_adapter.h"
  46    :  #include "syzygy/agent/asan/memory_notifiers/shadow_memory_notifier.h"
  47    :  #include "syzygy/agent/asan/reporters/breakpad_reporter.h"
  48    :  #include "syzygy/agent/asan/reporters/crashpad_reporter.h"
  49    :  #ifndef _WIN64
  50    :  #include "syzygy/agent/asan/reporters/kasko_reporter.h"
  51    :  #endif
  52    :  #include "syzygy/crashdata/crashdata.h"
  53    :  #include "syzygy/trace/client/client_utils.h"
  54    :  #include "syzygy/trace/protocol/call_trace_defs.h"
  55    :  
  56    :  // Disable all optimizations in this file. This entirely consists of code
  57    :  // that runs once at startup, or once during error handling. The latter code
  58    :  // is particularly useful to keep in its highest-fidelity form to help with
  59    :  // diagnosing edge cases during crash processing.
  60    :  #pragma optimize("", off)
  61    :  #pragma auto_inline(off)
  62    :  
  63    :  namespace agent {
  64    :  namespace asan {
  65    :  
  66    :  namespace {
  67    :  
  68    :  using agent::asan::AsanLogger;
  69    :  using agent::asan::StackCaptureCache;
  70    :  using agent::asan::WindowsHeapAdapter;
  71    :  
  72    :  enum CrashReporterType {
  73    :    kDefaultCrashReporterType,
  74    :    kBreakpadCrashReporterType,
  75    :  #ifndef _WIN64
  76    :    kKaskoCrashReporterType,
  77    :  #endif
  78    :    kCrashpadCrashReporterType,
  79    :  };
  80    :  
  81    :  // A custom exception code we use to indicate that the exception originated
  82    :  // from Asan, and shouldn't be processed again by our unhandled exception
  83    :  // handler. This value has been created according to the rules here:
  84    :  // http://msdn.microsoft.com/en-us/library/windows/hardware/ff543026(v=vs.85).aspx
  85    :  // See winerror.h for more details.
  86    :  static const DWORD kAsanFacility = 0x68B;  // No more than 11 bits.
  87    :  static const DWORD kAsanStatus = 0x5AD0;   // No more than 16 bits.
  88    :  static const DWORD kAsanException =
  89    :      (3 << 30) |              // Severity = error.
  90    :      (1 << 29) |              // Customer defined code (not defined by MS).
  91    :      (kAsanFacility << 16) |  // Facility code.
  92    :      kAsanStatus;             // Status code.
  93    :  static_assert((kAsanFacility >> 11) == 0, "Too many facility bits.");
  94    :  static_assert((kAsanStatus >> 16) == 0, "Too many status bits.");
  95    :  static_assert((kAsanException & (3 << 27)) == 0,
  96    :                "Bits 27 and 28 should be clear.");
  97    :  
  98    :  // Raises an exception, first wrapping it an Asan specific exception. This
  99    :  // indicates to our unhandled exception handler that it doesn't need to
 100    :  // process the exception.
 101    :  void RaiseFilteredException(DWORD code,
 102    :                              DWORD flags,
 103    :                              DWORD num_args,
 104  i :                              const ULONG_PTR* args) {
 105    :    // Retain the original arguments and craft a new exception.
 106    :    const ULONG_PTR arguments[4] = {
 107  i :        code, flags, num_args, reinterpret_cast<const ULONG_PTR>(args)};
 108  i :    ::RaiseException(kAsanException, 0, ARRAYSIZE(arguments), arguments);
 109  i :  }
 110    :  
 111    :  // The default error handler. It is expected that this will be bound in a
 112    :  // callback in the Asan runtime.
 113    :  // @param context The context when the error has been reported.
 114    :  // @param error_info The information about this error.
 115  E :  void DefaultErrorHandler(AsanErrorInfo* error_info) {
 116  E :    DCHECK_NE(reinterpret_cast<AsanErrorInfo*>(NULL), error_info);
 117    :  
 118  E :    ULONG_PTR arguments[] = {reinterpret_cast<ULONG_PTR>(&error_info->context),
 119  E :                             reinterpret_cast<ULONG_PTR>(error_info)};
 120    :  
 121  E :    ::DebugBreak();
 122    :  
 123    :    // This raises an error in such a way that the Asan unhandled exception
 124    :    // handler will not process it.
 125  E :    RaiseFilteredException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, 0,
 126    :                           ARRAYSIZE(arguments), arguments);
 127  E :  }
 128    :  
 129    :  // Writes some early crash keys. These will be present even if SyzyAsan crashes
 130    :  // and can be used to help triage those bugs. This should only be called if a
 131    :  // reporter exists and supports crash keys.
 132  E :  void SetEarlyCrashKeys(AsanRuntime* runtime) {
 133  E :    DCHECK_NE(static_cast<AsanRuntime*>(nullptr), runtime);
 134  E :    DCHECK_NE(static_cast<ReporterInterface*>(nullptr),
 135  E :              runtime->crash_reporter());
 136  E :    DCHECK_NE(0u, runtime->crash_reporter()->GetFeatures() &
 137  E :        ReporterInterface::FEATURE_CRASH_KEYS);
 138    :  
 139  E :    runtime->crash_reporter()->SetCrashKey(
 140    :        "asan-crash-reporter",
 141    :        runtime->crash_reporter()->GetName());
 142    :  
 143  E :    runtime->crash_reporter()->SetCrashKey(
 144    :        "asan-random-key",
 145    :        base::StringPrintf("%016llx", runtime->random_key()).c_str());
 146    :  
 147  E :    if (runtime->params().feature_randomization) {
 148  i :      runtime->crash_reporter()->SetCrashKey(
 149    :          "asan-feature-set",
 150    :          base::UintToString(runtime->GetEnabledFeatureSet()).c_str());
 151    :    }
 152  E :  }
 153    :  
 154    :  // This sets early crash keys for sufficiently modern versions of Chrome that
 155    :  // are known to support this.
 156  E :  void SetEarlyCrashKeysIfPossible(AsanRuntime* runtime) {
 157    :    // To set crash keys we need a crash reporter, and it needs to support early
 158    :    // crash key setting.
 159  E :    if (runtime->crash_reporter() == nullptr)
 160  E :      return;
 161    :    if ((runtime->crash_reporter()->GetFeatures() &
 162  E :            ReporterInterface::FEATURE_EARLY_CRASH_KEYS) == 0) {
 163  E :      return;
 164    :    }
 165    :  
 166    :    // Set a crash key that indicates that early crash keys were successfully
 167    :    // set and then set the remaining early crash keys themselves.
 168  i :    runtime->crash_reporter()->SetCrashKey("asan-early-keys", "true");
 169  i :    SetEarlyCrashKeys(runtime);
 170  E :  }
 171    :  
 172    :  // Initializes an exception record for an Asan crash.
 173    :  void InitializeExceptionRecord(const AsanErrorInfo* error_info,
 174    :                                 EXCEPTION_RECORD* record,
 175  E :                                 EXCEPTION_POINTERS* pointers) {
 176  E :    DCHECK_NE(static_cast<AsanErrorInfo*>(nullptr), error_info);
 177  E :    DCHECK_NE(static_cast<EXCEPTION_RECORD*>(nullptr), record);
 178  E :    DCHECK_NE(static_cast<EXCEPTION_POINTERS*>(nullptr), pointers);
 179    :  
 180  E :    ::memset(record, 0, sizeof(EXCEPTION_RECORD));
 181  E :    record->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
 182  E :    record->ExceptionAddress = GetInstructionPointer(error_info->context);
 183  E :    record->NumberParameters = 2;
 184  E :    record->ExceptionInformation[0] =
 185    :        reinterpret_cast<ULONG_PTR>(&error_info->context);
 186  E :    record->ExceptionInformation[1] = reinterpret_cast<ULONG_PTR>(error_info);
 187    :  
 188  E :    pointers->ExceptionRecord = record;
 189  E :    pointers->ContextRecord = const_cast<CONTEXT*>(&error_info->context);
 190  E :  }
 191    :  
 192    :  // Creates a serialized protobuf representing crash data. Also populates
 193    :  // |memory_ranges| with memory contents related to the crash.
 194    :  bool PopulateProtobufAndMemoryRanges(const AsanErrorInfo& error_info,
 195    :                                       std::string* protobuf,
 196  E :                                       MemoryRanges* memory_ranges) {
 197  E :    DCHECK_NE(static_cast<std::string*>(nullptr), protobuf);
 198  E :    crashdata::Value value;
 199  E :    PopulateErrorInfo(AsanRuntime::runtime()->shadow(), error_info, &value,
 200    :                      memory_ranges);
 201  E :    if (!value.SerializeToString(protobuf))
 202  i :      return false;
 203  E :    return true;
 204  E :  }
 205    :  
 206    :  // Send a crash report for the given exception.
 207    :  void DumpAndCrashViaReporter(AsanErrorInfo* error_info,
 208  E :                               EXCEPTION_POINTERS* exception_pointers) {
 209  E :    auto runtime = AsanRuntime::runtime();
 210  E :    auto reporter = runtime->crash_reporter();
 211  E :    DCHECK_NE(static_cast<ReporterInterface*>(nullptr), reporter);
 212    :  
 213    :    // Set any crash keys.
 214  E :    if (reporter->GetFeatures() & ReporterInterface::FEATURE_CRASH_KEYS) {
 215    :      // Reset the early crash keys, as they may not actually have been set.
 216  E :      SetEarlyCrashKeys(AsanRuntime::runtime());
 217    :  
 218  E :      reporter->SetCrashKey("asan-error-type",
 219    :                            ErrorInfoAccessTypeToStr(error_info->error_type));
 220    :  
 221  E :      if (error_info->shadow_info[0] != '\0')
 222  E :        reporter->SetCrashKey("asan-error-message", error_info->shadow_info);
 223    :  
 224  E :      if (error_info->asan_parameters.feature_randomization) {
 225  i :        reporter->SetCrashKey("asan-feature-set",
 226    :            base::UintToString(error_info->feature_set).c_str());
 227    :      }
 228    :    }
 229    :  
 230    :    // These are in an outer scope so that they persist until the call to
 231    :    // DumpAndCrash.
 232  E :    std::string protobuf;
 233  E :    MemoryRanges memory_ranges;
 234    :  
 235    :    // Populate the protobuf and the memory regions if possible.
 236    :    static const uint32_t kExtraFeatures =
 237    :        ReporterInterface::FEATURE_MEMORY_RANGES |
 238    :        ReporterInterface::FEATURE_CUSTOM_STREAMS;
 239  E :    if ((reporter->GetFeatures() & kExtraFeatures) != 0) {
 240  E :      MemoryRanges* memory_ranges_ptr = nullptr;
 241  E :      if (reporter->GetFeatures() & ReporterInterface::FEATURE_MEMORY_RANGES)
 242  i :        memory_ranges_ptr = &memory_ranges;
 243  E :      PopulateProtobufAndMemoryRanges(*error_info, &protobuf, &memory_ranges);
 244    :  
 245  E :      if (reporter->GetFeatures() & ReporterInterface::FEATURE_CUSTOM_STREAMS) {
 246  E :        reporter->SetCustomStream(
 247    :            ReporterInterface::kCrashdataProtobufStreamType,
 248    :            reinterpret_cast<const uint8_t*>(protobuf.data()),
 249    :            protobuf.size());
 250    :      }
 251    :  
 252    :      // Due to the logic above |memory_ranges| will only be non-empty if
 253    :      // the memory range feature is supported.
 254  E :      if (memory_ranges.size())
 255  E :        reporter->SetMemoryRanges(memory_ranges);
 256    :    }
 257    :  
 258    :    // This function should not return.
 259  E :    reporter->DumpAndCrash(exception_pointers);
 260  E :    NOTREACHED();
 261  i :  }
 262    :  
 263    :  // The crash reporting error handler. It is expected that this will be bound in
 264    :  // a callback in the Asan runtime if a error reporting system is available.
 265    :  // @param error_info The information about this error.
 266  E :  void CrashReporterErrorHandler(AsanErrorInfo* error_info) {
 267  E :    EXCEPTION_RECORD exception = {};
 268  E :    EXCEPTION_POINTERS pointers = {};
 269  E :    InitializeExceptionRecord(error_info, &exception, &pointers);
 270  E :    DumpAndCrashViaReporter(error_info, &pointers);
 271  E :  }
 272    :  
 273    :  // A helper function to find if an intrusive list contains a given entry.
 274    :  // @param list The list in which we want to look for the entry.
 275    :  // @param item The entry we want to look for.
 276    :  // @returns true if the list contains this entry, false otherwise.
 277    :  bool HeapListContainsEntry(const LIST_ENTRY* list, const LIST_ENTRY* item) {
 278    :    LIST_ENTRY* current = list->Flink;
 279    :    while (current != NULL) {
 280    :      LIST_ENTRY* next_item = NULL;
 281    :      if (current->Flink != list) {
 282    :        next_item = current->Flink;
 283    :      }
 284    :  
 285    :      if (current == item) {
 286    :        return true;
 287    :      }
 288    :  
 289    :      current = next_item;
 290    :    }
 291    :    return false;
 292    :  }
 293    :  
 294    :  // A helper function to send a command to Windbg. Windbg should first receive
 295    :  // the ".ocommand ASAN" command to treat those messages as commands.
 296  E :  void AsanDbgCmd(const wchar_t* fmt, ...) {
 297  E :    if (!base::debug::BeingDebugged())
 298  E :      return;
 299    :    // The string should start with "ASAN" to be interpreted by the debugger as a
 300    :    // command.
 301  i :    std::wstring command_wstring = L"ASAN ";
 302    :    va_list args;
 303  i :    va_start(args, fmt);
 304    :  
 305    :    // Append the actual command to the wstring.
 306  i :    base::StringAppendV(&command_wstring, fmt, args);
 307    :  
 308    :    // Append "; g" to make sure that the debugger continues its execution after
 309    :    // executing this command. This is needed because when the .ocommand function
 310    :    // is used under Windbg the debugger will break on OutputDebugString.
 311  i :    command_wstring.append(L"; g");
 312    :  
 313  i :    OutputDebugString(command_wstring.c_str());
 314  E :  }
 315    :  
 316    :  // A helper function to print a message to Windbg's console.
 317  E :  void AsanDbgMessage(const wchar_t* fmt, ...) {
 318  E :    if (!base::debug::BeingDebugged())
 319  E :      return;
 320    :    // Prepend the message with the .echo command so it'll be printed into the
 321    :    // debugger's console.
 322  i :    std::wstring message_wstring = L".echo ";
 323    :    va_list args;
 324  i :    va_start(args, fmt);
 325    :  
 326    :    // Append the actual message to the wstring.
 327  i :    base::StringAppendV(&message_wstring, fmt, args);
 328    :  
 329    :    // Treat the message as a command to print it.
 330  i :    AsanDbgCmd(message_wstring.c_str());
 331  E :  }
 332    :  
 333    :  // Switch to the caller's context and print its stack trace in Windbg.
 334    :  void AsanDbgPrintContext(const CONTEXT& context) {
 335    :    if (!base::debug::BeingDebugged())
 336    :      return;
 337    :    AsanDbgMessage(L"Caller's context (%p) and stack trace:", &context);
 338    :    AsanDbgCmd(L".cxr %p; kv", reinterpret_cast<uint32_t>(&context));
 339    :  }
 340    :  
 341    :  // Returns the maximum allocation size that can be made safely. This leaves
 342    :  // space for child function frames, ideally enough for Breakpad to do its
 343    :  // work.
 344  E :  size_t MaxSafeAllocaSize() {
 345    :    // We leave 5KB of stack space for Breakpad and other crash reporting
 346    :    // machinery.
 347  E :    const size_t kReservedStack = 5 * 1024;
 348    :  
 349    :    // Find the base of the stack.
 350  E :    MEMORY_BASIC_INFORMATION mbi = {};
 351  E :    void* stack = &mbi;
 352  E :    if (VirtualQuery(stack, &mbi, sizeof(mbi)) == 0)
 353  i :      return 0;
 354  E :    size_t max_size = reinterpret_cast<uint8_t*>(stack) -
 355    :                      reinterpret_cast<uint8_t*>(mbi.AllocationBase);
 356  E :    max_size -= std::min(max_size, kReservedStack);
 357  E :    return max_size;
 358  E :  }
 359    :  
 360    :  // Performs a dynamic stack allocation of at most |size| bytes. Sets the actual
 361    :  // size of the allocation and the pointer to it by modifying |size| and |result|
 362    :  // directly.
 363    :  #define SAFE_ALLOCA(size, result)          \
 364    :    {                                        \
 365    :      size_t max_size = MaxSafeAllocaSize(); \
 366    :      size = std::min(size, max_size);       \
 367    :      result = _alloca(size);                \
 368    :      if (result == NULL)                    \
 369    :        size = 0;                            \
 370    :    }
 371    :  
 372    :  // Runs the heap checker if enabled. If heap corruption is found serializes
 373    :  // the results to the stack and modifies the |error_info| structure.
 374    :  #define CHECK_HEAP_CORRUPTION(runtime, error_info)                          \
 375    :    (error_info)->heap_is_corrupt = false;                                    \
 376    :    if (!((runtime)->params_.check_heap_on_failure)) {                        \
 377    :      runtime_->logger_->Write(                                               \
 378    :          "SyzyASAN: Heap checker disabled, ignoring exception.");            \
 379    :    } else {                                                                  \
 380    :      runtime_->logger_->Write(                                               \
 381    :          "SyzyASAN: Heap checker enabled, processing exception.");           \
 382    :      AutoHeapManagerLock lock((runtime)->heap_manager_.get());               \
 383    :      HeapChecker heap_checker((runtime)->shadow());                          \
 384    :      HeapChecker::CorruptRangesVector corrupt_ranges;                        \
 385    :      heap_checker.IsHeapCorrupt(&corrupt_ranges);                            \
 386    :      size_t size = (runtime)->CalculateCorruptHeapInfoSize(corrupt_ranges);  \
 387    :      void* buffer = NULL;                                                    \
 388    :      if (size > 0) {                                                         \
 389    :        SAFE_ALLOCA(size, buffer);                                            \
 390    :        (runtime)                                                             \
 391    :            ->WriteCorruptHeapInfo(corrupt_ranges, size, buffer, error_info); \
 392    :      }                                                                       \
 393    :    }
 394    :  
 395  i :  void LaunchMessageBox(const base::StringPiece& message) {
 396    :    // TODO(chrisha): Consider making this close itself with a timeout to prevent
 397    :    //     hangs on the waterfall.
 398  i :    ::MessageBoxA(nullptr, message.data(), nullptr, MB_OK | MB_ICONEXCLAMATION);
 399  i :  }
 400    :  
 401    :  // Gets the preferred crash reporter type from the environment. This will
 402    :  // override experiments or command-lines, and is largely meant for local
 403    :  // testing.
 404    :  CrashReporterType GetCrashReporterTypeFromEnvironment(
 405  E :      AsanLogger* logger) {
 406  E :    DCHECK_NE(static_cast<AsanLogger*>(nullptr), logger);
 407  E :    std::unique_ptr<ReporterInterface> reporter;
 408    :  
 409  E :    std::unique_ptr<base::Environment> env(base::Environment::Create());
 410  E :    std::string reporter_name;
 411    :    static const char kSyzyAsanCrashReporterEnv[] =
 412    :        "SYZYASAN_CRASH_REPORTER";
 413  E :    if (!env->GetVar(kSyzyAsanCrashReporterEnv, &reporter_name))
 414  E :      return kDefaultCrashReporterType;
 415    :  
 416  i :    CrashReporterType type = kDefaultCrashReporterType;
 417  i :    if (reporter_name == "crashpad") {
 418  i :      type = kCrashpadCrashReporterType;
 419    :  #ifndef _WIN64
 420  i :    } else if (reporter_name == "kasko") {
 421  i :      type = kKaskoCrashReporterType;
 422    :  #endif
 423  i :    } else if (reporter_name == "breakpad") {
 424  i :      type = kBreakpadCrashReporterType;
 425    :    }
 426    :  
 427  i :    if (type != kDefaultCrashReporterType) {
 428  i :      logger->Write(base::StringPrintf("Encountered %s=\"%s\".",
 429    :          kSyzyAsanCrashReporterEnv, reporter_name.c_str()));
 430  i :    } else {
 431  i :      logger->Write(base::StringPrintf("Ignoring %s=\"%s\".",
 432    :          kSyzyAsanCrashReporterEnv, reporter_name.c_str()));
 433    :    }
 434    :  
 435  i :    return type;
 436  E :  }
 437    :  
 438    :  // Attempts to create a crash reporter, starting with the most modern.
 439    :  std::unique_ptr<ReporterInterface> CreateCrashReporterWithTypeHint(
 440  E :      AsanLogger* logger, CrashReporterType reporter_type) {
 441  E :    std::unique_ptr<ReporterInterface> reporter;
 442    :  
 443    :    // Crashpad is not yet enabled by default.
 444  E :    if (reporter_type == kCrashpadCrashReporterType)
 445  E :      reporter.reset(reporters::CrashpadReporter::Create().release());
 446    :  
 447    :  #ifndef _WIN64
 448    :    // Try to initialize a Kasko crash reporter.
 449  E :    if (reporter.get() == nullptr &&
 450    :        (reporter_type == kKaskoCrashReporterType ||
 451    :         reporter_type == kDefaultCrashReporterType)) {
 452  E :      reporter.reset(reporters::KaskoReporter::Create().release());
 453    :    }
 454    :  #endif
 455    :  
 456    :    // If that failed then try to initialize a Breakpad reporter.
 457  E :    if (reporter.get() == nullptr &&
 458    :        (reporter_type == kBreakpadCrashReporterType ||
 459    :         reporter_type == kDefaultCrashReporterType)) {
 460  E :      reporter.reset(reporters::BreakpadReporter::Create().release());
 461    :    }
 462    :  
 463  E :    return reporter;
 464  E :  }
 465    :  
 466    :  }  // namespace
 467    :  
 468  E :  base::Lock AsanRuntime::lock_;
 469    :  AsanRuntime* AsanRuntime::runtime_ = NULL;
 470    :  LPTOP_LEVEL_EXCEPTION_FILTER AsanRuntime::previous_uef_ = NULL;
 471    :  bool AsanRuntime::uef_installed_ = false;
 472    :  
 473    :  AsanRuntime::AsanRuntime()
 474  E :      : logger_(),
 475  E :        stack_cache_(),
 476  E :        asan_error_callback_(),
 477  E :        heap_manager_(),
 478  E :        random_key_(::__rdtsc()) {
 479  E :    ::common::SetDefaultAsanParameters(&params_);
 480  E :    starting_ticks_ = ::GetTickCount();
 481  E :  }
 482    :  
 483  E :  AsanRuntime::~AsanRuntime() {
 484  E :  }
 485    :  
 486  E :  bool AsanRuntime::SetUp(const std::wstring& flags_command_line) {
 487  E :    base::AutoLock auto_lock(lock_);
 488  E :    DCHECK(!runtime_);
 489  E :    runtime_ = this;
 490    :  
 491    :    // Setup the shadow memory first. If this fails the dynamic runtime can
 492    :    // safely disable the instrumentation.
 493  E :    if (!SetUpShadow())
 494  i :      return false;
 495    :  
 496    :    // Parse and propagate any flags set via the environment variable. This logs
 497    :    // failure for us.
 498  E :    if (!::common::ParseAsanParameters(flags_command_line, &params_))
 499  i :      return false;
 500    :  
 501    :    // Initialize the command-line structures. This is needed so that
 502    :    // SetUpLogger() can include the command-line in the message announcing
 503    :    // this process. Note: this is mostly for debugging purposes.
 504  E :    base::CommandLine::Init(0, NULL);
 505    :  
 506    :    // Setup other global state.
 507  E :    common::StackCapture::Init();
 508  E :    StackCaptureCache::Init();
 509  E :    if (!SetUpMemoryNotifier())
 510  i :      return false;
 511  E :    if (!SetUpLogger())
 512  i :      return false;
 513  E :    if (!SetUpStackCache())
 514  i :      return false;
 515  E :    if (!SetUpHeapManager())
 516  i :      return false;
 517  E :    WindowsHeapAdapter::SetUp(heap_manager_.get());
 518    :  
 519    :    // Determine the preferred crash reporter type, as specified in the
 520    :    // environment. If this isn't present it defaults to
 521    :    // kDefaultCrashReporterType, in which case experiments or command-line flags
 522    :    // may specify the crash reporter to use.
 523    :    CrashReporterType crash_reporter_type =
 524  E :        GetCrashReporterTypeFromEnvironment(logger());
 525    :  
 526  E :    if (params_.feature_randomization) {
 527  E :      AsanFeatureSet feature_set = GenerateRandomFeatureSet();
 528  E :      PropagateFeatureSet(feature_set);
 529    :  
 530    :      // If no specific crash reporter has been specified, then allow the
 531    :      // experiment to specify it.
 532  E :      if (crash_reporter_type == kDefaultCrashReporterType &&
 533    :          (feature_set & ASAN_FEATURE_ENABLE_CRASHPAD) != 0) {
 534  E :        crash_reporter_type = kCrashpadCrashReporterType;
 535    :      }
 536    :    }
 537    :  
 538    :    // Propagates the flags values to the different modules.
 539  E :    PropagateParams();
 540    :  
 541    :    // The name 'disable_breakpad_reporting' is legacy; this actually means to
 542    :    // disable all external crash reporting integration.
 543  E :    if (!params_.disable_breakpad_reporting) {
 544    :      // This will create the crash reporter with a preference for creating a
 545    :      // reporter of the hinted type. If such a reporter isn't available, it will
 546    :      // fall back to trying to create the most 'modern' reporter available.
 547  E :      crash_reporter_.reset(CreateCrashReporterWithTypeHint(
 548    :          logger(), crash_reporter_type).release());
 549    :    }
 550    :  
 551    :    // Set up the appropriate error handler depending on whether or not
 552    :    // we successfully initialized a crash reporter.
 553  E :    if (crash_reporter_.get() != nullptr) {
 554  E :      logger_->Write(base::StringPrintf(
 555    :          "SyzyASAN: Using %s for error reporting.",
 556    :          crash_reporter_->GetName()));
 557  E :      SetErrorCallBack(base::Bind(&CrashReporterErrorHandler));
 558  E :    } else {
 559  E :      logger_->Write("SyzyASAN: Using default error reporting handler.");
 560  E :      SetErrorCallBack(base::Bind(&DefaultErrorHandler));
 561    :    }
 562    :  
 563    :    // Install the unhandled exception handler. This is only installed once
 564    :    // across all runtime instances in a process so we check that it hasn't
 565    :    // already been installed.
 566    :    // TODO(chrisha): Conditionally install this based on the crash reporter in
 567    :    // use. Eventually, Crashpad will provide us a callback instead of having us
 568    :    // register the handler ourselves.
 569  E :    if (!uef_installed_) {
 570  E :      uef_installed_ = true;
 571  E :      previous_uef_ = ::SetUnhandledExceptionFilter(&UnhandledExceptionFilter);
 572    :    }
 573    :  
 574    :    // Finally, initialize the heap manager. This comes after parsing all
 575    :    // parameters as some decisions can only be made once.
 576  E :    heap_manager_->Init();
 577    :  
 578    :    // Set some early crash keys.
 579  E :    SetEarlyCrashKeysIfPossible(this);
 580    :  
 581  E :    return true;
 582  E :  }
 583    :  
 584  E :  void AsanRuntime::TearDown() {
 585  E :    base::AutoLock auto_lock(lock_);
 586    :  
 587    :    // The WindowsHeapAdapter will only have been initialized if the heap manager
 588    :    // was successfully created and initialized.
 589  E :    if (heap_manager_.get() != nullptr)
 590  E :      WindowsHeapAdapter::TearDown();
 591  E :    TearDownHeapManager();
 592  E :    TearDownStackCache();
 593  E :    TearDownLogger();
 594  E :    TearDownMemoryNotifier();
 595  E :    TearDownShadow();
 596  E :    asan_error_callback_.Reset();
 597    :  
 598    :    // Unregister ourselves as the singleton runtime for UEF.
 599  E :    runtime_ = NULL;
 600    :  
 601    :    // In principle, we should also check that all the heaps have been destroyed
 602    :    // but this is not guaranteed to be the case in Chrome, so the heap list may
 603    :    // not be empty here.
 604  E :  }
 605    :  
 606  E :  void AsanRuntime::OnErrorImpl(AsanErrorInfo* error_info) {
 607  E :    DCHECK_NE(reinterpret_cast<AsanErrorInfo*>(NULL), error_info);
 608    :  
 609    :    // Copy the parameters into the crash report.
 610  E :    error_info->asan_parameters = params_;
 611  E :    error_info->feature_set = GetEnabledFeatureSet();
 612    :  
 613  E :    LogAsanErrorInfo(error_info);
 614    :  
 615  E :    if (params_.minidump_on_failure) {
 616  E :      DCHECK(logger_.get() != NULL);
 617  E :      std::string protobuf;
 618  E :      MemoryRanges memory_ranges;
 619  E :      PopulateProtobufAndMemoryRanges(*error_info, &protobuf, &memory_ranges);
 620    :  
 621  E :      logger_->SaveMinidumpWithProtobufAndMemoryRanges(
 622    :          &error_info->context, error_info, protobuf, memory_ranges);
 623  E :    }
 624    :  
 625  E :    if (params_.exit_on_failure) {
 626  E :      DCHECK(logger_.get() != NULL);
 627  E :      logger_->Stop();
 628  E :      exit(EXIT_FAILURE);
 629    :    }
 630  E :  }
 631    :  
 632  E :  void AsanRuntime::OnError(AsanErrorInfo* error_info) {
 633  E :    DCHECK_NE(reinterpret_cast<AsanErrorInfo*>(NULL), error_info);
 634    :  
 635    :    // Grab the global page protection lock to prevent page protection settings
 636    :    // from being modified while processing the error.
 637  E :    ::common::AutoRecursiveLock lock(block_protect_lock);
 638    :  
 639    :    // Unfortunately this is a giant macro, but it needs to be as it performs
 640    :    // stack allocations.
 641  E :    CHECK_HEAP_CORRUPTION(this, error_info);
 642    :  
 643  E :    OnErrorImpl(error_info);
 644    :  
 645    :    // Call the callback to handle this error.
 646  E :    DCHECK(!asan_error_callback_.is_null());
 647  E :    asan_error_callback_.Run(error_info);
 648  E :  }
 649    :  
 650  E :  void AsanRuntime::SetErrorCallBack(const AsanOnErrorCallBack& callback) {
 651  E :    asan_error_callback_ = callback;
 652  E :  }
 653    :  
 654  E :  bool AsanRuntime::SetUpShadow() {
 655    :    // If a non-trivial static shadow is provided, but it's the wrong size, then
 656    :    // this runtime is unable to support hotpatching and its being run in the
 657    :    // wrong memory model.
 658  E :    if (asan_memory_interceptors_shadow_memory_size > 1 &&
 659    :        asan_memory_interceptors_shadow_memory_size != Shadow::RequiredLength()) {
 660    :      static const char kMessage[] =
 661    :          "Runtime can't support the current memory model. LAA?";
 662  i :      LaunchMessageBox(kMessage);
 663  i :      NOTREACHED() << kMessage;
 664    :    }
 665    :  
 666    :    // Use the static shadow memory if possible.
 667  E :    if (asan_memory_interceptors_shadow_memory_size == Shadow::RequiredLength()) {
 668  E :      shadow_.reset(new Shadow(asan_memory_interceptors_shadow_memory,
 669    :                               asan_memory_interceptors_shadow_memory_size));
 670  E :    } else {
 671    :      // Otherwise dynamically allocate the shadow memory.
 672  E :      shadow_.reset(new Shadow());
 673    :  
 674    :      // If the allocation fails, then return false.
 675  E :      if (shadow_->shadow() == nullptr)
 676  i :        return false;
 677    :  
 678    :      // Patch the memory interceptors to refer to the newly allocated shadow.
 679    :      // If this fails simply explode because it is unsafe to continue.
 680  E :      CHECK(PatchMemoryInterceptorShadowReferences(
 681    :          asan_memory_interceptors_shadow_memory, shadow_->shadow()));
 682    :    }
 683    :  
 684    :    // Setup the shadow and configure the various interceptors to use it.
 685  E :    shadow_->SetUp();
 686  E :    agent::asan::SetCrtInterceptorShadow(shadow_.get());
 687  E :    agent::asan::SetMemoryInterceptorShadow(shadow_.get());
 688  E :    agent::asan::SetSystemInterceptorShadow(shadow_.get());
 689    :  
 690  E :    return true;
 691  E :  }
 692    :  
 693  E :  void AsanRuntime::TearDownShadow() {
 694    :    // If this didn't successfully initialize then do nothing.
 695  E :    if (shadow_->shadow() == nullptr)
 696  i :      return;
 697    :  
 698  E :    shadow_->TearDown();
 699  E :    agent::asan::SetCrtInterceptorShadow(nullptr);
 700  E :    agent::asan::SetMemoryInterceptorShadow(nullptr);
 701  E :    agent::asan::SetSystemInterceptorShadow(nullptr);
 702    :    // Unpatch the probes if necessary.
 703  E :    if (shadow_->shadow() != asan_memory_interceptors_shadow_memory) {
 704  E :      CHECK(PatchMemoryInterceptorShadowReferences(
 705    :          shadow_->shadow(), asan_memory_interceptors_shadow_memory));
 706    :    }
 707  E :    shadow_.reset();
 708  E :  }
 709    :  
 710  E :  bool AsanRuntime::SetUpMemoryNotifier() {
 711  E :    DCHECK_NE(static_cast<Shadow*>(nullptr), shadow_.get());
 712  E :    DCHECK_NE(static_cast<uint8_t*>(nullptr), shadow_->shadow());
 713  E :    DCHECK_EQ(static_cast<MemoryNotifierInterface*>(nullptr),
 714  E :              memory_notifier_.get());
 715    :    memory_notifiers::ShadowMemoryNotifier* memory_notifier =
 716  E :        new memory_notifiers::ShadowMemoryNotifier(shadow_.get());
 717  E :    memory_notifier->NotifyInternalUse(memory_notifier, sizeof(*memory_notifier));
 718  E :    memory_notifier_.reset(memory_notifier);
 719  E :    return true;
 720  E :  }
 721    :  
 722  E :  void AsanRuntime::TearDownMemoryNotifier() {
 723  E :    if (memory_notifier_.get() == nullptr)
 724  i :      return;
 725    :  
 726    :    memory_notifiers::ShadowMemoryNotifier* memory_notifier =
 727    :        reinterpret_cast<memory_notifiers::ShadowMemoryNotifier*>(
 728  E :            memory_notifier_.get());
 729  E :    memory_notifier->NotifyReturnedToOS(memory_notifier,
 730    :                                        sizeof(*memory_notifier));
 731  E :    memory_notifier_.reset(nullptr);
 732  E :  }
 733    :  
 734  E :  bool AsanRuntime::SetUpLogger() {
 735  E :    DCHECK_NE(static_cast<MemoryNotifierInterface*>(nullptr),
 736  E :              memory_notifier_.get());
 737  E :    DCHECK_EQ(static_cast<AsanLogger*>(nullptr), logger_.get());
 738    :  
 739    :    // Setup variables we're going to use.
 740  E :    std::unique_ptr<base::Environment> env(base::Environment::Create());
 741  E :    std::unique_ptr<AsanLogger> client(new AsanLogger);
 742  E :    CHECK(env.get() != NULL);
 743  E :    CHECK(client.get() != NULL);
 744    :  
 745    :    // Initialize the client.
 746  E :    client->set_instance_id(
 747    :        base::UTF8ToWide(trace::client::GetInstanceIdForThisModule()));
 748  E :    client->Init();
 749    :  
 750    :    // Register the client singleton instance.
 751  E :    logger_.reset(client.release());
 752  E :    memory_notifier_->NotifyInternalUse(logger_.get(), sizeof(*logger_.get()));
 753    :  
 754  E :    return true;
 755  E :  }
 756    :  
 757  E :  void AsanRuntime::TearDownLogger() {
 758  E :    if (logger_.get() == nullptr)
 759  i :      return;
 760    :  
 761  E :    DCHECK_NE(static_cast<MemoryNotifierInterface*>(nullptr),
 762  E :              memory_notifier_.get());
 763  E :    memory_notifier_->NotifyReturnedToOS(logger_.get(), sizeof(*logger_.get()));
 764  E :    logger_.reset();
 765  E :  }
 766    :  
 767  E :  bool AsanRuntime::SetUpStackCache() {
 768  E :    DCHECK_NE(static_cast<MemoryNotifierInterface*>(nullptr),
 769  E :              memory_notifier_.get());
 770  E :    DCHECK_NE(static_cast<AsanLogger*>(nullptr), logger_.get());
 771  E :    DCHECK_EQ(static_cast<StackCaptureCache*>(nullptr), stack_cache_.get());
 772  E :    stack_cache_.reset(
 773    :        new StackCaptureCache(logger_.get(), memory_notifier_.get()));
 774  E :    memory_notifier_->NotifyInternalUse(stack_cache_.get(),
 775    :                                        sizeof(*stack_cache_.get()));
 776    :  
 777  E :    return true;
 778  E :  }
 779    :  
 780  E :  void AsanRuntime::TearDownStackCache() {
 781  E :    if (stack_cache_.get() == nullptr)
 782  i :      return;
 783    :  
 784  E :    DCHECK_NE(static_cast<MemoryNotifierInterface*>(nullptr),
 785  E :              memory_notifier_.get());
 786  E :    DCHECK_NE(static_cast<AsanLogger*>(nullptr), logger_.get());
 787    :  
 788  E :    stack_cache_->LogStatistics();
 789  E :    memory_notifier_->NotifyReturnedToOS(stack_cache_.get(),
 790    :                                         sizeof(*stack_cache_.get()));
 791  E :    stack_cache_.reset();
 792  E :  }
 793    :  
 794  E :  bool AsanRuntime::SetUpHeapManager() {
 795  E :    DCHECK_NE(static_cast<MemoryNotifierInterface*>(nullptr),
 796  E :              memory_notifier_.get());
 797  E :    DCHECK_NE(static_cast<AsanLogger*>(nullptr), logger_.get());
 798  E :    DCHECK_NE(static_cast<StackCaptureCache*>(nullptr), stack_cache_.get());
 799  E :    DCHECK_EQ(static_cast<heap_managers::BlockHeapManager*>(nullptr),
 800  E :              heap_manager_.get());
 801    :  
 802  E :    heap_manager_.reset(new heap_managers::BlockHeapManager(
 803    :        shadow(), stack_cache_.get(), memory_notifier_.get()));
 804  E :    memory_notifier_->NotifyInternalUse(heap_manager_.get(),
 805    :                                        sizeof(*heap_manager_.get()));
 806    :  
 807    :    // Configure the heap manager to notify us on heap corruption.
 808  E :    heap_manager_->SetHeapErrorCallback(
 809    :        base::Bind(&AsanRuntime::OnError, base::Unretained(this)));
 810    :  
 811  E :    return true;
 812  E :  }
 813    :  
 814  E :  void AsanRuntime::TearDownHeapManager() {
 815  E :    if (stack_cache_.get() == nullptr)
 816  i :      return;
 817    :  
 818  E :    DCHECK_NE(static_cast<MemoryNotifierInterface*>(nullptr),
 819  E :              memory_notifier_.get());
 820  E :    DCHECK_NE(static_cast<AsanLogger*>(nullptr), logger_.get());
 821  E :    DCHECK_NE(static_cast<StackCaptureCache*>(nullptr), stack_cache_.get());
 822    :  
 823    :    // Tear down the heap manager before we destroy it and lose our pointer
 824    :    // to it. This is necessary because the heap manager can raise errors
 825    :    // while tearing down the heap, which will in turn call back into the
 826    :    // block heap manager via the runtime.
 827  E :    heap_manager_->TearDownHeapManager();
 828  E :    memory_notifier_->NotifyReturnedToOS(heap_manager_.get(),
 829    :                                         sizeof(*heap_manager_.get()));
 830  E :    heap_manager_.reset();
 831  E :  }
 832    :  
 833  E :  bool AsanRuntime::GetAsanFlagsEnvVar(std::wstring* env_var_wstr) {
 834  E :    std::unique_ptr<base::Environment> env(base::Environment::Create());
 835  E :    if (env.get() == NULL) {
 836  i :      LOG(ERROR) << "base::Environment::Create returned NULL.";
 837  i :      return false;
 838    :    }
 839    :  
 840    :    // If this fails, the environment variable simply does not exist.
 841  E :    std::string env_var_str;
 842  E :    if (!env->GetVar(::common::kSyzyAsanOptionsEnvVar, &env_var_str)) {
 843  E :      return true;
 844    :    }
 845    :  
 846  E :    *env_var_wstr = base::SysUTF8ToWide(env_var_str);
 847    :  
 848  E :    return true;
 849  E :  }
 850    :  
 851  E :  void AsanRuntime::PropagateParams() {
 852    :    // This function has to be kept in sync with the AsanParameters struct. These
 853    :    // checks will ensure that this is the case.
 854    :  #ifdef _WIN64
 855    :    static_assert(sizeof(::common::AsanParameters) == 64,
 856    :                  "Must propagate parameters.");
 857    :  #else
 858    :    static_assert(sizeof(::common::AsanParameters) == 60,
 859    :                  "Must propagate parameters.");
 860    :  #endif
 861    :    static_assert(::common::kAsanParametersVersion == 14,
 862    :                  "Must update parameters version.");
 863    :  
 864    :    // Push the configured parameter values to the appropriate endpoints.
 865  E :    heap_manager_->set_parameters(params_);
 866  E :    StackCaptureCache::set_compression_reporting_period(params_.reporting_period);
 867  E :    common::StackCapture::set_bottom_frames_to_skip(
 868    :        params_.bottom_frames_to_skip);
 869  E :    stack_cache_->set_max_num_frames(params_.max_num_frames);
 870    :    // ignored_stack_ids is used locally by AsanRuntime.
 871  E :    logger_->set_log_as_text(params_.log_as_text);
 872    :    // exit_on_failure is used locally by AsanRuntime.
 873  E :    logger_->set_minidump_on_failure(params_.minidump_on_failure);
 874  E :  }
 875    :  
 876    :  size_t AsanRuntime::CalculateCorruptHeapInfoSize(
 877  E :      const HeapChecker::CorruptRangesVector& corrupt_ranges) {
 878  E :    size_t n = corrupt_ranges.size() *
 879    :               (sizeof(AsanCorruptBlockRange) + sizeof(AsanBlockInfo));
 880  E :    return n;
 881  E :  }
 882    :  
 883    :  void AsanRuntime::WriteCorruptHeapInfo(
 884    :      const HeapChecker::CorruptRangesVector& corrupt_ranges,
 885    :      size_t buffer_size,
 886    :      void* buffer,
 887  E :      AsanErrorInfo* error_info) {
 888  E :    DCHECK((buffer_size == 0 && buffer == NULL) ||
 889    :           (buffer_size != 0 && buffer != NULL));
 890  E :    DCHECK_NE(reinterpret_cast<AsanErrorInfo*>(NULL), error_info);
 891    :  
 892  E :    ::memset(buffer, 0, buffer_size);
 893    :  
 894  E :    error_info->heap_is_corrupt = false;
 895  E :    error_info->corrupt_range_count = 0;
 896  E :    error_info->corrupt_block_count = 0;
 897  E :    error_info->corrupt_ranges_reported = 0;
 898  E :    error_info->corrupt_ranges = NULL;
 899    :  
 900  E :    if (corrupt_ranges.empty())
 901  i :      return;
 902    :  
 903    :    // If we have corrupt ranges then set the aggregate fields.
 904  E :    error_info->heap_is_corrupt = true;
 905  E :    error_info->corrupt_range_count = corrupt_ranges.size();
 906  E :    for (size_t i = 0; i < corrupt_ranges.size(); ++i)
 907  E :      error_info->corrupt_block_count += corrupt_ranges[i].block_count;
 908    :  
 909    :    // We report a AsanCorruptBlockRange and at least one AsanBlockInfo per
 910    :    // corrupt range. Determine how many ranges we can report on.
 911    :    size_t range_count =
 912  E :        buffer_size / (sizeof(AsanCorruptBlockRange) + sizeof(AsanBlockInfo));
 913  E :    range_count = std::min(range_count, corrupt_ranges.size());
 914    :  
 915    :    // Allocate space for the corrupt range metadata.
 916  E :    uint8_t* cursor = reinterpret_cast<uint8_t*>(buffer);
 917  E :    uint8_t* buffer_end = cursor + buffer_size;
 918  E :    error_info->corrupt_ranges = reinterpret_cast<AsanCorruptBlockRange*>(cursor);
 919  E :    cursor += range_count * sizeof(AsanCorruptBlockRange);
 920  E :    error_info->corrupt_range_count = corrupt_ranges.size();
 921  E :    error_info->corrupt_ranges_reported = range_count;
 922    :  
 923    :    // Allocate space for the corrupt block metadata.
 924  E :    size_t block_count = (buffer_end - cursor) / sizeof(AsanBlockInfo);
 925  E :    AsanBlockInfo* block_infos = reinterpret_cast<AsanBlockInfo*>(cursor);
 926  E :    cursor += block_count * sizeof(AsanBlockInfo);
 927    :  
 928    :    // Write as many corrupt block ranges as we have room for. This is
 929    :    // effectively random as it is by order of address.
 930  E :    for (size_t i = 0; i < range_count; ++i) {
 931    :      // Copy the information about the corrupt range.
 932  E :      error_info->corrupt_ranges[i] = corrupt_ranges[i];
 933    :  
 934    :      // Allocate space for the first block of this range on the stack.
 935    :      // TODO(sebmarchand): Report more blocks if necessary.
 936  E :      AsanBlockInfo* asan_block_info = block_infos;
 937  E :      error_info->corrupt_ranges[i].block_info = block_infos;
 938  E :      error_info->corrupt_ranges[i].block_info_count = 1;
 939  E :      ++block_infos;
 940    :  
 941    :      // Use a shadow walker to find the first corrupt block in this range and
 942    :      // copy its metadata.
 943  E :      ShadowWalker shadow_walker(
 944    :          shadow(), false,
 945    :          reinterpret_cast<const uint8_t*>(corrupt_ranges[i].address),
 946    :          reinterpret_cast<const uint8_t*>(corrupt_ranges[i].address) +
 947    :              corrupt_ranges[i].length);
 948  E :      BlockInfo block_info = {};
 949  E :      CHECK(shadow_walker.Next(&block_info));
 950    :      // The heap checker removes block protections as it goes, so this block
 951    :      // should be readable. However, remove page protections just to be sure.
 952    :      // They are left turned off so that the minidump generation can introspect
 953    :      // the block.
 954  E :      BlockProtectNone(block_info, shadow());
 955  E :      ErrorInfoGetAsanBlockInfo(shadow(), block_info, stack_cache_.get(),
 956    :                                asan_block_info);
 957  E :      DCHECK_EQ(kDataIsCorrupt, asan_block_info->analysis.block_state);
 958  E :    }
 959    :  
 960    :    return;
 961  E :  }
 962    :  
 963  E :  void AsanRuntime::LogAsanErrorInfo(AsanErrorInfo* error_info) {
 964  E :    DCHECK_NE(reinterpret_cast<AsanErrorInfo*>(NULL), error_info);
 965    :  
 966  E :    const char* bug_descr = ErrorInfoAccessTypeToStr(error_info->error_type);
 967  E :    if (logger_->log_as_text()) {
 968  E :      std::string output(base::StringPrintf(
 969    :          "SyzyASAN error: %s on address 0x%08X (stack_id=0x%08X)\n", bug_descr,
 970    :          error_info->location, error_info->crash_stack_id));
 971  E :      if (error_info->access_mode != agent::asan::ASAN_UNKNOWN_ACCESS) {
 972  E :        const char* access_mode_str = NULL;
 973  E :        if (error_info->access_mode == agent::asan::ASAN_READ_ACCESS)
 974  E :          access_mode_str = "READ";
 975  E :        else
 976  E :          access_mode_str = "WRITE";
 977  E :        base::StringAppendF(&output, "%s of size %d at 0x%08X\n", access_mode_str,
 978    :                            error_info->access_size, error_info->location);
 979    :      }
 980    :  
 981    :      // Log the failure and stack.
 982  E :      logger_->WriteWithContext(output, error_info->context);
 983    :  
 984  E :      logger_->Write(error_info->shadow_info);
 985  E :      if (error_info->block_info.free_stack_size != 0U) {
 986  E :        logger_->WriteWithStackTrace("freed here:\n",
 987    :                                     error_info->block_info.free_stack,
 988    :                                     error_info->block_info.free_stack_size);
 989    :      }
 990  E :      if (error_info->block_info.alloc_stack_size != NULL) {
 991  E :        logger_->WriteWithStackTrace("previously allocated here:\n",
 992    :                                     error_info->block_info.alloc_stack,
 993    :                                     error_info->block_info.alloc_stack_size);
 994    :      }
 995  E :      if (error_info->error_type >= USE_AFTER_FREE) {
 996  E :        std::string shadow_text;
 997  E :        shadow()->AppendShadowMemoryText(error_info->location, &shadow_text);
 998  E :        logger_->Write(shadow_text);
 999  E :      }
1000  E :    }
1001    :  
1002    :    // Print the base of the Windbg help message.
1003  E :    AsanDbgMessage(L"An Asan error has been found (%ls), here are the details:",
1004    :                   base::SysUTF8ToWide(bug_descr).c_str());
1005    :  
1006    :    // Print the Windbg information to display the allocation stack if present.
1007  E :    if (error_info->block_info.alloc_stack_size != NULL) {
1008  E :      AsanDbgMessage(L"Allocation stack trace:");
1009  E :      AsanDbgCmd(L"dps %p l%d", error_info->block_info.alloc_stack,
1010    :                 error_info->block_info.alloc_stack_size);
1011    :    }
1012    :  
1013    :    // Print the Windbg information to display the free stack if present.
1014  E :    if (error_info->block_info.free_stack_size != NULL) {
1015  E :      AsanDbgMessage(L"Free stack trace:");
1016  E :      AsanDbgCmd(L"dps %p l%d", error_info->block_info.free_stack,
1017    :                 error_info->block_info.free_stack_size);
1018    :    }
1019  E :  }
1020    :  
1021    :  // static
1022  E :  AsanFeatureSet AsanRuntime::GenerateRandomFeatureSet() {
1023    :    AsanFeatureSet enabled_features =
1024  E :        static_cast<AsanFeatureSet>(base::RandGenerator(ASAN_FEATURE_MAX));
1025  E :    DCHECK_LT(enabled_features, ASAN_FEATURE_MAX);
1026  E :    enabled_features &= kAsanValidFeatures;
1027  E :    return enabled_features;
1028  E :  }
1029    :  
1030  E :  void AsanRuntime::PropagateFeatureSet(AsanFeatureSet feature_set) {
1031  E :    DCHECK_EQ(0U, feature_set & ~kAsanValidFeatures);
1032  E :    heap_manager_->enable_page_protections_ =
1033    :        (feature_set & ASAN_FEATURE_ENABLE_PAGE_PROTECTIONS) != 0;
1034  E :    params_.enable_large_block_heap =
1035    :        (feature_set & ASAN_FEATURE_ENABLE_LARGE_BLOCK_HEAP) != 0;
1036  E :  }
1037    :  
1038  E :  void AsanRuntime::GetBadAccessInformation(AsanErrorInfo* error_info) {
1039  E :    base::AutoLock lock(lock_);
1040    :  
1041    :    // Checks if this is an access to an internal structure or if it's an access
1042    :    // in the upper region of the memory (over the 2 GB limit).
1043  E :    if ((reinterpret_cast<size_t>(error_info->location) & (1 << 31)) != 0 ||
1044    :        shadow()->GetShadowMarkerForAddress(error_info->location) ==
1045    :            kAsanMemoryMarker) {
1046  E :      error_info->error_type = WILD_ACCESS;
1047  E :    } else if (shadow()->GetShadowMarkerForAddress(error_info->location) ==
1048    :               kInvalidAddressMarker) {
1049  E :      error_info->error_type = INVALID_ADDRESS;
1050  E :    } else {
1051  E :      ErrorInfoGetBadAccessInformation(shadow(), stack_cache_.get(), error_info);
1052    :    }
1053  E :  }
1054    :  
1055  E :  bool AsanRuntime::allocation_filter_flag() {
1056  E :    return heap_manager_->allocation_filter_flag();
1057  E :  }
1058    :  
1059  E :  void AsanRuntime::set_allocation_filter_flag(bool value) {
1060  E :    heap_manager_->set_allocation_filter_flag(value);
1061  E :  }
1062    :  
1063  E :  void AsanRuntime::AddThreadId(uint32_t thread_id) {
1064  E :    DCHECK_NE(0u, thread_id);
1065  E :    base::AutoLock lock(thread_ids_lock_);
1066  E :    thread_ids_.insert(thread_id);
1067  E :  }
1068    :  
1069  E :  bool AsanRuntime::ThreadIdIsValid(uint32_t thread_id) {
1070  E :    base::AutoLock lock(thread_ids_lock_);
1071  E :    return thread_ids_.count(thread_id) > 0;
1072  E :  }
1073    :  
1074  E :  bool AsanRuntime::HeapIdIsValid(HeapManagerInterface::HeapId heap_id) {
1075    :    // Consider dying heaps in this query, as they are still valid from the
1076    :    // point of view of an error report.
1077  E :    return heap_manager_->IsValidHeapIdUnlocked(heap_id, true);
1078  E :  }
1079    :  
1080  E :  HeapType AsanRuntime::GetHeapType(HeapManagerInterface::HeapId heap_id) {
1081  E :    return heap_manager_->GetHeapTypeUnlocked(heap_id);
1082  E :  }
1083    :  
1084  i :  int AsanRuntime::CrashForException(EXCEPTION_POINTERS* exception) {
1085  i :    return ExceptionFilterImpl(false, exception);
1086  i :  }
1087    :  
1088    :  LONG WINAPI
1089  E :  AsanRuntime::UnhandledExceptionFilter(struct _EXCEPTION_POINTERS* exception) {
1090  E :    return ExceptionFilterImpl(true, exception);
1091  E :  }
1092    :  
1093    :  // static
1094    :  LONG AsanRuntime::ExceptionFilterImpl(bool is_unhandled,
1095  E :                                        EXCEPTION_POINTERS* exception) {
1096    :    // This ensures that we don't have multiple colliding crashes being processed
1097    :    // simultaneously.
1098  E :    base::AutoLock auto_lock(lock_);
1099    :  
1100    :    // Grab the global page protection lock to prevent page protection settings
1101    :    // from being modified while processing the error.
1102  E :    ::common::AutoRecursiveLock lock(block_protect_lock);
1103    :  
1104    :    // This is needed for unittesting.
1105  E :    runtime_->logger_->Write("SyzyASAN: Handling an exception.");
1106    :  
1107    :    // If we're bound to a runtime then look for heap corruption and
1108    :    // potentially augment the exception record. This needs to exist in the
1109    :    // outermost scope of this function as pointers to it may be passed to
1110    :    // other exception handlers.
1111  E :    AsanErrorInfo error_info = {};
1112    :  
1113    :    // If this is set to true then an Asan error will be emitted.
1114  E :    bool emit_asan_error = false;
1115    :    // Will be set to true if a near-nullptr access is detected.
1116  E :    bool near_nullptr_access = false;
1117    :  
1118  E :    Shadow* shadow = runtime_->shadow();
1119    :    // If this is an exception that we launched then extract the original
1120    :    // exception data and continue processing it.
1121  E :    if (exception->ExceptionRecord->ExceptionCode == kAsanException) {
1122  i :      ULONG_PTR* args = exception->ExceptionRecord->ExceptionInformation;
1123  i :      DWORD code = args[0];
1124  i :      DWORD flags = args[1];
1125  i :      DWORD nargs = args[2];
1126  i :      const ULONG_PTR* orig_args = reinterpret_cast<const ULONG_PTR*>(args[3]);
1127    :  
1128    :      // Rebuild the exception with the original exception data.
1129  i :      exception->ExceptionRecord->ExceptionCode = code;
1130  i :      exception->ExceptionRecord->ExceptionFlags = flags;
1131  i :      exception->ExceptionRecord->NumberParameters = nargs;
1132  i :      for (DWORD i = 0; i < nargs; ++i)
1133  i :        args[i] = orig_args[i];
1134  E :    } else if (runtime_) {
1135    :      // Initialize this as if heap corruption is the primary error being
1136    :      // reported. This will be overridden by the access violation handling
1137    :      // code below, if necessary.
1138  E :      error_info.location = exception->ExceptionRecord->ExceptionAddress;
1139  E :      error_info.context = *exception->ContextRecord;
1140  E :      error_info.error_type = CORRUPT_HEAP;
1141  E :      error_info.access_mode = ASAN_UNKNOWN_ACCESS;
1142    :  
1143    :      // It is possible that access violations are due to page protections of a
1144    :      // sufficiently large allocation. In this case the shadow will contain
1145    :      // block redzone markers at the given address. We take over the exception
1146    :      // if that is the case.
1147    :      if (exception->ExceptionRecord->ExceptionCode ==
1148    :              EXCEPTION_ACCESS_VIOLATION &&
1149  E :          exception->ExceptionRecord->NumberParameters >= 2 &&
1150    :          exception->ExceptionRecord->ExceptionInformation[0] <= 1) {
1151    :        void* address = reinterpret_cast<void*>(
1152  E :            exception->ExceptionRecord->ExceptionInformation[1]);
1153    :  
1154    :        // The first 64k of user memory is unmapped in Windows, we treat those as
1155    :        // near-nullptr accesses.
1156  E :        near_nullptr_access =
1157    :            address < reinterpret_cast<void*>(Shadow::kAddressLowerBound);
1158    :  
1159  E :        ShadowMarker marker = shadow->GetShadowMarkerForAddress(address);
1160    :        if ((!near_nullptr_access ||
1161    :             runtime_->params().report_invalid_accesses) &&
1162  E :            ShadowMarkerHelper::IsRedzone(marker) &&
1163    :            ShadowMarkerHelper::IsActiveBlock(marker)) {
1164  E :          BlockInfo block_info = {};
1165  E :          if (shadow->BlockInfoFromShadow(address, &block_info)) {
1166    :            // Page protections have to be removed from this block otherwise our
1167    :            // own inspection will cause further errors.
1168  E :            BlockProtectNone(block_info, runtime_->shadow());
1169    :  
1170    :            // Useful for unittesting.
1171  E :            runtime_->logger_->Write(
1172    :                "SyzyASAN: Caught an invalid access via "
1173    :                "an access violation exception.");
1174    :  
1175    :            // Override the invalid access location with the faulting address,
1176    :            // not the code address.
1177  E :            error_info.location = address;
1178    :            // The exact access size isn't reported so simply set it to 1 (an
1179    :            // obvious lower bound).
1180  E :            error_info.access_size = 1;
1181    :            // Determine if this is a read or a write using information in the
1182    :            // exception record.
1183  E :            error_info.access_mode =
1184    :                exception->ExceptionRecord->ExceptionInformation[0] == 0
1185    :                    ? ASAN_READ_ACCESS
1186    :                    : ASAN_WRITE_ACCESS;
1187    :  
1188    :            // Fill out the rest of the bad access information.
1189  E :            ErrorInfoGetBadAccessInformation(shadow, runtime_->stack_cache(),
1190    :                                             &error_info);
1191  E :            emit_asan_error = true;
1192    :          }
1193    :        }
1194    :      }
1195    :  
1196  E :      CHECK_HEAP_CORRUPTION(runtime_, &error_info);
1197  E :      if (error_info.heap_is_corrupt)
1198  E :        emit_asan_error = true;
1199    :    }
1200    :  
1201    :    // If an Asan error was detected then report it via the logger and take over
1202    :    // the exception record.
1203  E :    EXCEPTION_RECORD record = {};
1204  E :    if (emit_asan_error) {
1205  E :      if (near_nullptr_access) {
1206  E :        runtime_->logger_->Write(
1207    :            "SyzyASAN: Caught a near-nullptr access with heap corruption.");
1208    :      }
1209    :  
1210    :      // Log the error via the usual means.
1211  E :      runtime_->OnErrorImpl(&error_info);
1212    :  
1213    :      // Remember the old exception record.
1214  E :      EXCEPTION_RECORD* old_record = exception->ExceptionRecord;
1215    :  
1216    :      // Initialize the exception record and chain the original exception to it.
1217  E :      InitializeExceptionRecord(&error_info, &record, exception);
1218  E :      record.ExceptionRecord = old_record;
1219  E :    } else if (near_nullptr_access &&
1220    :               !runtime_->params().report_invalid_accesses) {
1221    :      // For unit testing. Record that we ignored a near-nullptr access.
1222  E :      runtime_->logger_->Write(
1223    :          "SyzyASAN: Ignoring a near-nullptr access without heap corruption.");
1224    :    }
1225    :  
1226    :    // If a crash reporter is present then use it.
1227  E :    if (emit_asan_error && runtime_->crash_reporter() != nullptr) {
1228  E :      DumpAndCrashViaReporter(&error_info, exception);
1229  E :      return EXCEPTION_CONTINUE_SEARCH;
1230    :    }
1231    :  
1232  E :    if (is_unhandled) {
1233    :      // Pass the buck to the next exception handler. If the process has an
1234    :      // integrated crash reporter that we're not explicitly aware of this will
1235    :      // eventually make its way there.
1236  E :      if (previous_uef_ != NULL)
1237  E :        return (*previous_uef_)(exception);
1238    :    }
1239    :  
1240    :    // We can't do anything with this, so let the system deal with it.
1241  i :    return EXCEPTION_CONTINUE_SEARCH;
1242  i :  }
1243    :  
1244  i :  void AsanRuntime::EnableDeferredFreeThread() {
1245  i :    DCHECK(heap_manager_);
1246  i :    heap_manager_->EnableDeferredFreeThread();
1247  i :  }
1248    :  
1249  i :  void AsanRuntime::DisableDeferredFreeThread() {
1250  i :    DCHECK(heap_manager_);
1251  i :    heap_manager_->DisableDeferredFreeThread();
1252  i :  }
1253    :  
1254  E :  AsanFeatureSet AsanRuntime::GetEnabledFeatureSet() {
1255  E :    AsanFeatureSet enabled_features = static_cast<AsanFeatureSet>(0U);
1256  E :    if (heap_manager_->enable_page_protections_)
1257  E :      enabled_features |= ASAN_FEATURE_ENABLE_PAGE_PROTECTIONS;
1258  E :    if (params_.enable_large_block_heap)
1259  E :      enabled_features |= ASAN_FEATURE_ENABLE_LARGE_BLOCK_HEAP;
1260  E :    if (crash_reporter_.get() != nullptr &&
1261    :        crash_reporter_->GetName() == reporters::CrashpadReporter::kName) {
1262  i :      enabled_features |= ASAN_FEATURE_ENABLE_CRASHPAD;
1263    :    }
1264    :  
1265  E :    return enabled_features;
1266  E :  }
1267    :  
1268    :  }  // namespace asan
1269    :  }  // namespace agent

Coverage information generated Fri Jul 29 11:00:21 2016.