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

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

Coverage information generated Thu Jan 14 17:40:38 2016.