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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
76.2%1792350.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/asan_runtime.h"
  16    :  
  17    :  #include "base/bind.h"
  18    :  #include "base/command_line.h"
  19    :  #include "base/environment.h"
  20    :  #include "base/logging.h"
  21    :  #include "base/string_number_conversions.h"
  22    :  #include "base/utf_string_conversions.h"
  23    :  #include "base/strings/string_tokenizer.h"
  24    :  #include "base/strings/sys_string_conversions.h"
  25    :  #include "base/win/pe_image.h"
  26    :  #include "base/win/wrapped_window_proc.h"
  27    :  #include "syzygy/agent/asan/asan_logger.h"
  28    :  #include "syzygy/agent/asan/asan_shadow.h"
  29    :  #include "syzygy/agent/asan/stack_capture_cache.h"
  30    :  #include "syzygy/trace/client/client_utils.h"
  31    :  #include "syzygy/trace/protocol/call_trace_defs.h"
  32    :  
  33    :  namespace agent {
  34    :  namespace asan {
  35    :  
  36    :  namespace {
  37    :  
  38    :  using agent::asan::AsanLogger;
  39    :  using agent::asan::HeapProxy;
  40    :  using agent::asan::StackCaptureCache;
  41    :  using base::win::WinProcExceptionFilter;
  42    :  
  43    :  typedef void  (__cdecl * SetCrashKeyValueFuncPtr)(const char*, const char*);
  44    :  
  45    :  // The default error handler. It is expected that this will be bound in a
  46    :  // callback in the ASAN runtime.
  47    :  // @param context The context when the error has been reported.
  48    :  // @param error_info The information about this error.
  49  i :  void DefaultErrorHandler(CONTEXT* context, AsanErrorInfo* error_info) {
  50  i :    DCHECK(context != NULL);
  51  i :    DCHECK(error_info != NULL);
  52    :  
  53    :    ULONG_PTR arguments[] = {
  54  i :      reinterpret_cast<ULONG_PTR>(context),
  55    :      reinterpret_cast<ULONG_PTR>(error_info)
  56  i :    };
  57    :  
  58  i :    ::DebugBreak();
  59    :    ::RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
  60    :                     0,
  61    :                     ARRAYSIZE(arguments),
  62  i :                     &arguments[0]);
  63  i :  }
  64    :  
  65    :  // Returns the breakpad crash reporting functions if breakpad is enabled for
  66    :  // the current executable.
  67    :  //
  68    :  // @param crash_func A pointer to a crash reporting function will be returned
  69    :  //     here, or NULL.
  70    :  // @param key_value_func A pointer to a function to set additional key/value
  71    :  //     attributes for the crash before calling crash_func, or NULL. This may
  72    :  //     return NULL even if crash_func returns non-NULL.
  73    :  //
  74    :  // If we're running in the context of a breakpad enabled binary we can
  75    :  // report errors directly via that breakpad entry-point. This allows us
  76    :  // to report the exact context of the error without including the asan_rtl
  77    :  // in crash context, depending on where and when we capture the context.
  78    :  void GetBreakpadFunctions(WinProcExceptionFilter* crash_func,
  79  E :                            SetCrashKeyValueFuncPtr* key_value_func ) {
  80  E :    DCHECK(crash_func != NULL);
  81  E :    DCHECK(key_value_func != NULL);
  82    :  
  83    :    // The named entry-point exposed to report a crash.
  84    :    static const char kCrashHandlerSymbol[] = "CrashForException";
  85    :  
  86    :    // The named entry-point exposed to annotate a crash with a key/value pair.
  87    :    static const char kSetCrashKeyValueSymbol[] = "SetCrashKeyValuePair";
  88    :  
  89    :    // Get a handle to the current executable image.
  90  E :    HMODULE exe_hmodule = ::GetModuleHandle(NULL);
  91    :  
  92    :    // Lookup the crash handler symbol.
  93    :    *crash_func = reinterpret_cast<WinProcExceptionFilter>(
  94  E :        ::GetProcAddress(exe_hmodule, kCrashHandlerSymbol));
  95    :  
  96    :    // Lookup the crash annotation symbol.
  97    :    *key_value_func = reinterpret_cast<SetCrashKeyValueFuncPtr>(
  98  E :        ::GetProcAddress(exe_hmodule, kSetCrashKeyValueSymbol));
  99  E :  }
 100    :  
 101    :  // The breakpad error handler. It is expected that this will be bound in a
 102    :  // callback in the ASAN runtime.
 103    :  // @param func_ptr A pointer to the breakpad error reporting function. This
 104    :  //     will be used to perform the error reporting.
 105    :  // @param crash_func_ptr A pointer to the breakpad crash reporting function.
 106    :  // @param key_value_func A pointer to a function to set additional key/value
 107    :  //     attributes for the crash before calling crash_func. For backwards
 108    :  //     compatibility, with older breakpad clients, this parameter is optional
 109    :  //     (it may be NULL).
 110    :  // @param context The context when the error has been reported.
 111    :  // @param error_info The information about this error.
 112    :  void BreakpadErrorHandler(WinProcExceptionFilter crash_func_ptr,
 113    :                            SetCrashKeyValueFuncPtr set_key_value_func_ptr,
 114    :                            CONTEXT* context,
 115  i :                            AsanErrorInfo* error_info) {
 116  i :    DCHECK(crash_func_ptr != NULL);
 117  i :    DCHECK(context != NULL);
 118  i :    DCHECK(error_info != NULL);
 119    :  
 120  i :    if (set_key_value_func_ptr != NULL) {
 121    :      set_key_value_func_ptr(
 122    :          "asan-error-type",
 123  i :          HeapProxy::AccessTypeToStr(error_info->error_type));
 124  i :      if (error_info->shadow_info[0] != '\0') {
 125    :        set_key_value_func_ptr(
 126  i :            "asan-error-message", error_info->shadow_info);
 127    :      }
 128    :    }
 129    :  
 130  i :    EXCEPTION_RECORD exception = {};
 131  i :    exception.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
 132  i :    exception.ExceptionAddress = reinterpret_cast<PVOID>(context->Eip);
 133  i :    exception.NumberParameters = 2;
 134  i :    exception.ExceptionInformation[0] = reinterpret_cast<ULONG_PTR>(context);
 135  i :    exception.ExceptionInformation[1] = reinterpret_cast<ULONG_PTR>(error_info);
 136    :  
 137  i :    EXCEPTION_POINTERS pointers = { &exception, context };
 138  i :    crash_func_ptr(&pointers);
 139  i :    NOTREACHED();
 140  i :  }
 141    :  
 142    :  // Try to update the value of a size_t variable from a command-line.
 143    :  // @param cmd_line The command line who might contain a given parameter.
 144    :  // @param param_name The parameter that we want to read.
 145    :  // @param value Will receive the value of the parameter if it's present.
 146    :  // @returns true on success, false otherwise.
 147    :  bool UpdateSizetFromCommandLine(const CommandLine& cmd_line,
 148    :                                  const std::string& param_name,
 149  E :                                  size_t* value) {
 150  E :    DCHECK(value != NULL);
 151  E :    if (!cmd_line.HasSwitch(param_name))
 152  E :      return true;
 153  E :    std::string value_str = cmd_line.GetSwitchValueASCII(param_name);
 154  E :    size_t new_value = 0;
 155  E :    if (!base::StringToSizeT(value_str, &new_value))
 156  i :      return false;
 157  E :    *value = new_value;
 158    :  
 159  E :    return true;
 160  E :  }
 161    :  
 162    :  // Try to update the value of an array of ignored stack ids from a command-line.
 163    :  // We expect the values to be in hexadecimal format and separated by a
 164    :  // semi-colon.
 165    :  // @param cmd_line The command line to parse.
 166    :  // @param param_name The parameter that we want to read.
 167    :  // @param values Will receive the set of parsed values.
 168    :  // @returns true on success, false otherwise.
 169    :  bool ReadIgnoredStackIdsFromCommandLine(const CommandLine& cmd_line,
 170    :                                          const std::string& param_name,
 171  E :                                          AsanRuntime::StackIdSet* values) {
 172  E :    DCHECK(values != NULL);
 173  E :    if (!cmd_line.HasSwitch(param_name))
 174  E :      return true;
 175  E :    std::string value_str = cmd_line.GetSwitchValueASCII(param_name);
 176  E :    base::StringTokenizer string_tokenizer(value_str, ";");
 177  E :    while (string_tokenizer.GetNext()) {
 178  E :      int64 new_value = 0;
 179  E :      if (!base::HexStringToInt64(string_tokenizer.token(), &new_value))
 180  i :        return false;
 181  E :      values->insert(static_cast<StackCapture::StackId>(new_value));
 182  E :    }
 183  E :    return true;
 184  E :  }
 185    :  
 186    :  // A helper function to find if an intrusive list contains a given entry.
 187    :  // @param list The list in which we want to look for the entry.
 188    :  // @param item The entry we want to look for.
 189    :  // @returns true if the list contains this entry, false otherwise.
 190  E :  bool HeapListContainsEntry(const LIST_ENTRY* list, const LIST_ENTRY* item) {
 191  E :    LIST_ENTRY* current = list->Flink;
 192  E :    while (current != NULL) {
 193  E :      LIST_ENTRY* next_item = NULL;
 194  E :      if (current->Flink != list) {
 195  E :        next_item = current->Flink;
 196    :      }
 197    :  
 198  E :      if (current == item) {
 199  E :        return true;
 200    :      }
 201    :  
 202  E :      current = next_item;
 203  E :    }
 204  i :    return false;
 205  E :  }
 206    :  
 207    :  // Check if the current process is large address aware.
 208    :  // @returns true if it is, false otherwise.
 209  E :  bool CurrentProcessIsLargeAddressAware() {
 210  E :    const base::win::PEImage image(::GetModuleHandle(NULL));
 211    :  
 212    :    bool process_is_large_address_aware =
 213    :      (image.GetNTHeaders()->FileHeader.Characteristics &
 214  E :          IMAGE_FILE_LARGE_ADDRESS_AWARE) != 0;
 215    :  
 216  E :    return process_is_large_address_aware;
 217  E :  }
 218    :  
 219    :  }  // namespace
 220    :  
 221    :  const char AsanRuntime::kSyzyAsanEnvVar[] = "SYZYGY_ASAN_OPTIONS";
 222    :  
 223    :  const char AsanRuntime::kBottomFramesToSkip[] =
 224    :      "bottom_frames_to_skip";
 225    :  const char AsanRuntime::kCompressionReportingPeriod[] =
 226    :      "compression_reporting_period";
 227    :  const char AsanRuntime::kExitOnFailure[] = "exit_on_failure";
 228    :  const char AsanRuntime::kIgnoredStackIds[] = "ignored_stack_ids";
 229    :  const char AsanRuntime::kMaxNumberOfFrames[] = "max_num_frames";
 230    :  const char AsanRuntime::kMiniDumpOnFailure[] = "minidump_on_failure";
 231    :  const char AsanRuntime::kNoLogAsText[] = "no_log_as_text";
 232    :  const char AsanRuntime::kQuarantineSize[] = "quarantine_size";
 233    :  const wchar_t AsanRuntime::kSyzyAsanDll[] = L"asan_rtl.dll";
 234    :  
 235    :  AsanRuntime::AsanRuntime()
 236    :      : logger_(NULL), stack_cache_(NULL), asan_error_callback_(), flags_(),
 237  E :        heap_proxy_dlist_lock_(), heap_proxy_dlist_() {
 238  E :  }
 239    :  
 240  E :  AsanRuntime::~AsanRuntime() {
 241  E :  }
 242    :  
 243  E :  void AsanRuntime::SetUp(const std::wstring& flags_command_line) {
 244    :    // Ensure that the current process is not large address aware. It shouldn't be
 245    :    // because the shadow memory assume that the process will only be able to use
 246    :    // 2GB of address space.
 247  E :    CHECK(!CurrentProcessIsLargeAddressAware());
 248    :  
 249    :    // Initialize the command-line structures. This is needed so that
 250    :    // SetUpLogger() can include the command-line in the message announcing
 251    :    // this process. Note: this is mostly for debugging purposes.
 252  E :    CommandLine::Init(0, NULL);
 253    :  
 254  E :    Shadow::SetUp();
 255    :  
 256  E :    InitializeListHead(&heap_proxy_dlist_);
 257    :  
 258    :    // Setup the "global" state.
 259  E :    HeapProxy::Init();
 260  E :    StackCapture::Init();
 261  E :    StackCaptureCache::Init();
 262  E :    SetUpLogger();
 263  E :    SetUpStackCache();
 264  E :    if (!ParseFlagsFromString(flags_command_line)) {
 265  i :      LOG(ERROR) << "Unable to parse the flags from the input string (\""
 266    :                 << flags_command_line.c_str() << "\").";
 267    :    }
 268    :    // Propagates the flags values to the different modules.
 269  E :    PropagateFlagsValues();
 270    :  
 271    :    // Register the error reporting callback to use if/when an ASAN error is
 272    :    // detected. If we're able to resolve a breakpad error reporting function
 273    :    // then use that; otherwise, fall back to the default error handler.
 274  E :    WinProcExceptionFilter crash_func_ptr = NULL;
 275  E :    SetCrashKeyValueFuncPtr set_key_value_func_ptr = NULL;
 276  E :    GetBreakpadFunctions(&crash_func_ptr, &set_key_value_func_ptr);
 277  E :    if (crash_func_ptr != NULL) {
 278  i :      LOG(INFO) << "SyzyASAN: Using Breakpad for error reporting.";
 279    :      SetErrorCallBack(base::Bind(
 280  i :          &BreakpadErrorHandler, crash_func_ptr, set_key_value_func_ptr));
 281  i :    } else {
 282  E :      LOG(INFO) << "SyzyASAN: Using default error reporting handler.";
 283  E :      SetErrorCallBack(base::Bind(&DefaultErrorHandler));
 284    :    }
 285  E :  }
 286    :  
 287  E :  void AsanRuntime::TearDown() {
 288  E :    TearDownStackCache();
 289  E :    TearDownLogger();
 290  E :    DCHECK(asan_error_callback_.is_null() == FALSE);
 291  E :    asan_error_callback_.Reset();
 292  E :    Shadow::TearDown();
 293    :    // In principle, we should also check that all the heaps have been destroyed
 294    :    // but this is not guaranteed to be the case in Chrome, so the heap list may
 295    :    // not be empty here.
 296  E :  }
 297    :  
 298  E :  void AsanRuntime::OnError(CONTEXT* context, AsanErrorInfo* error_info) {
 299  E :    DCHECK(context != NULL);
 300    :  
 301  E :    if (flags_.minidump_on_failure) {
 302  i :      DCHECK(logger_.get() != NULL);
 303  i :      logger_->SaveMiniDump(context, error_info);
 304    :    }
 305    :  
 306  E :    if (flags_.exit_on_failure) {
 307  E :      DCHECK(logger_.get() != NULL);
 308  E :      logger_->Stop();
 309  E :      exit(EXIT_FAILURE);
 310    :    }
 311    :  
 312    :    // Call the callback to handle this error.
 313  E :    DCHECK(!asan_error_callback_.is_null());
 314  E :    asan_error_callback_.Run(context, error_info);
 315  E :  }
 316    :  
 317  E :  void AsanRuntime::SetErrorCallBack(const AsanOnErrorCallBack& callback) {
 318  E :    asan_error_callback_ = callback;
 319  E :  }
 320    :  
 321  E :  void AsanRuntime::SetUpLogger() {
 322    :    // Setup variables we're going to use.
 323  E :    scoped_ptr<base::Environment> env(base::Environment::Create());
 324  E :    scoped_ptr<AsanLogger> client(new AsanLogger);
 325  E :    CHECK(env.get() != NULL);
 326  E :    CHECK(client.get() != NULL);
 327    :  
 328    :    // Initialize the client.
 329    :    client->set_instance_id(
 330  E :        UTF8ToWide(trace::client::GetInstanceIdForThisModule()));
 331  E :    client->Init();
 332    :  
 333    :    // Register the client singleton instance.
 334  E :    logger_.reset(client.release());
 335  E :  }
 336    :  
 337  E :  void AsanRuntime::TearDownLogger() {
 338  E :    logger_.reset();
 339  E :  }
 340    :  
 341  E :  void AsanRuntime::SetUpStackCache() {
 342  E :    DCHECK(stack_cache_.get() == NULL);
 343  E :    DCHECK(logger_.get() != NULL);
 344  E :    stack_cache_.reset(new StackCaptureCache(logger_.get()));
 345  E :  }
 346    :  
 347  E :  void AsanRuntime::TearDownStackCache() {
 348  E :    DCHECK(stack_cache_.get() != NULL);
 349  E :    stack_cache_->LogStatistics();
 350  E :    stack_cache_.reset();
 351  E :  }
 352    :  
 353  E :  bool AsanRuntime::ParseFlagsFromString(std::wstring str) {
 354    :    // Prepends the flags with the agent name. We need to do this because the
 355    :    // command-line constructor expect the process name to be the first value of
 356    :    // the command-line string.
 357    :    // Start by inserting a space at the beginning of the flags to separate the
 358    :    // flags from the agent name.
 359  E :    str.insert(0, L" ");
 360    :    // Insert the agent name.
 361  E :    str.insert(0, kSyzyAsanDll);
 362    :  
 363  E :    CommandLine cmd_line = CommandLine::FromString(str);
 364    :  
 365    :    // Parse the quarantine size flag.
 366  E :    flags_.quarantine_size = HeapProxy::default_quarantine_max_size();
 367    :    if (!UpdateSizetFromCommandLine(cmd_line, kQuarantineSize,
 368  E :                                    &flags_.quarantine_size)) {
 369  i :      LOG(ERROR) << "Unable to read " << kQuarantineSize << " from the argument "
 370    :                 << "list.";
 371  i :      return false;
 372    :    }
 373    :  
 374    :    // Parse the reporting period flag.
 375    :    flags_.reporting_period =
 376  E :        StackCaptureCache::GetDefaultCompressionReportingPeriod();
 377    :    if (!UpdateSizetFromCommandLine(cmd_line, kCompressionReportingPeriod,
 378  E :                                    &flags_.reporting_period)) {
 379  i :      LOG(ERROR) << "Unable to read " << kCompressionReportingPeriod
 380    :                 << " from the argument list.";
 381  i :      return false;
 382    :    }
 383    :  
 384    :    // Parse the bottom frames to skip flag.
 385  E :    flags_.bottom_frames_to_skip = StackCapture::bottom_frames_to_skip();
 386    :    if (!UpdateSizetFromCommandLine(cmd_line, kBottomFramesToSkip,
 387  E :                                    &flags_.bottom_frames_to_skip)) {
 388  i :      LOG(ERROR) << "Unable to read " << kBottomFramesToSkip << " from the "
 389    :                 << "argument list.";
 390  i :      return false;
 391    :    }
 392    :  
 393    :    // Parse the max number of frames flag.
 394  E :    flags_.max_num_frames = stack_cache_->max_num_frames();
 395    :    if (!UpdateSizetFromCommandLine(cmd_line, kMaxNumberOfFrames,
 396  E :                                    &flags_.max_num_frames)) {
 397  i :      LOG(ERROR) << "Unable to read " << kMaxNumberOfFrames << " from the "
 398    :                 << "argument list.";
 399  i :      return false;
 400    :    }
 401    :  
 402    :    // Parse the ignored stack ids.
 403    :    if (!ReadIgnoredStackIdsFromCommandLine(cmd_line, kIgnoredStackIds,
 404  E :                                            &flags_.ignored_stack_ids)) {
 405  i :      LOG(ERROR) << "Unable to read " << kIgnoredStackIds << " from the "
 406    :                 << "argument list.";
 407  i :      return false;
 408    :    }
 409    :  
 410    :    // Parse the other (boolean) flags.
 411  E :    flags_.exit_on_failure = cmd_line.HasSwitch(kExitOnFailure);
 412  E :    flags_.minidump_on_failure = cmd_line.HasSwitch(kMiniDumpOnFailure);
 413  E :    flags_.log_as_text = !cmd_line.HasSwitch(kNoLogAsText);
 414    :  
 415  E :    return true;
 416  E :  }
 417    :  
 418  E :  bool AsanRuntime::GetAsanFlagsEnvVar(std::wstring* env_var_wstr) {
 419  E :    scoped_ptr<base::Environment> env(base::Environment::Create());
 420  E :    if (env.get() == NULL) {
 421  i :      LOG(ERROR) << "base::Environment::Create returned NULL.";
 422  i :      return false;
 423    :    }
 424    :  
 425    :    // If this fails, the environment variable simply does not exist.
 426  E :    std::string env_var_str;
 427  E :    if (!env->GetVar(kSyzyAsanEnvVar, &env_var_str)) {
 428  E :      return true;
 429    :    }
 430    :  
 431  i :    *env_var_wstr = base::SysUTF8ToWide(env_var_str);
 432    :  
 433  i :    return true;
 434  E :  }
 435    :  
 436  E :  void AsanRuntime::PropagateFlagsValues() const {
 437    :    // TODO(sebmarchand): Look into edit-free ways to expose new flags to the
 438    :    //     different modules.
 439  E :    HeapProxy::set_default_quarantine_max_size(flags_.quarantine_size);
 440  E :    StackCapture::set_bottom_frames_to_skip(flags_.bottom_frames_to_skip);
 441  E :    StackCaptureCache::set_compression_reporting_period(flags_.reporting_period);
 442  E :    stack_cache_->set_max_num_frames(flags_.max_num_frames);
 443  E :    logger_->set_log_as_text(flags_.log_as_text);
 444  E :    logger_->set_minidump_on_failure(flags_.minidump_on_failure);
 445  E :  }
 446    :  
 447  E :  void AsanRuntime::set_flags(const AsanFlags* flags) {
 448  E :    DCHECK(flags != NULL);
 449  E :    flags_ = *flags;
 450  E :  }
 451    :  
 452  E :  void AsanRuntime::AddHeap(HeapProxy* heap) {
 453  E :    base::AutoLock lock(heap_proxy_dlist_lock_);
 454  E :    InsertTailList(&heap_proxy_dlist_, HeapProxy::ToListEntry(heap));
 455  E :  }
 456    :  
 457  E :  void AsanRuntime::RemoveHeap(HeapProxy* heap) {
 458  E :    base::AutoLock lock(heap_proxy_dlist_lock_);
 459    :    DCHECK(HeapListContainsEntry(&heap_proxy_dlist_,
 460  E :                                 HeapProxy::ToListEntry(heap)));
 461  E :    RemoveEntryList(HeapProxy::ToListEntry(heap));
 462  E :  }
 463    :  
 464    :  void AsanRuntime::ReportAsanErrorDetails(const void* addr,
 465    :                                           const CONTEXT& context,
 466    :                                           const StackCapture& stack,
 467    :                                           HeapProxy::AccessMode access_mode,
 468    :                                           size_t access_size,
 469  E :                                           AsanErrorInfo* bad_access_info) {
 470  E :    DCHECK(bad_access_info != NULL);
 471  E :    base::AutoLock lock(heap_proxy_dlist_lock_);
 472    :  
 473    :    // Checks if this is an access to an internal structure or if it's an access
 474    :    // in the upper region of the memory (over the 2 GB limit).
 475    :    if ((reinterpret_cast<size_t>(addr) & (1 << 31)) != 0 ||
 476  E :        Shadow::GetShadowMarkerForAddress(addr) == Shadow::kAsanMemoryByte) {
 477  E :      LIST_ENTRY* item = heap_proxy_dlist_.Flink;
 478  E :      CHECK(item != NULL);
 479  E :      HeapProxy* proxy = HeapProxy::FromListEntry(item);
 480  E :      CHECK(proxy != NULL);
 481  E :      bad_access_info->error_type = HeapProxy::WILD_ACCESS;
 482    :      proxy->ReportWildAccess(addr, context, stack, access_mode,
 483  E :                              access_size);
 484  E :      return;
 485    :    }
 486    :  
 487    :    // Iterates over the HeapProxy list to find the memory block containing this
 488    :    // address. We expect that there is at least one heap proxy extant.
 489  E :    HeapProxy* proxy = NULL;
 490  E :    LIST_ENTRY* item = heap_proxy_dlist_.Flink;
 491  E :    CHECK(item != NULL);
 492  E :    while (item != NULL) {
 493  E :      LIST_ENTRY* next_item = NULL;
 494  E :      if (item->Flink != &heap_proxy_dlist_) {
 495  i :        next_item = item->Flink;
 496    :      }
 497    :  
 498  E :      proxy = HeapProxy::FromListEntry(item);
 499    :      if (proxy->OnBadAccess(addr,
 500    :                             context,
 501    :                             stack,
 502    :                             access_mode,
 503    :                             access_size,
 504  E :                             bad_access_info)) {
 505  E :        break;
 506    :      }
 507    :  
 508  i :      item = next_item;
 509  i :    }
 510    :  
 511    :    // If item is NULL then we went through the list without finding the heap
 512    :    // from which this address was allocated. We can just reuse the logger of
 513    :    // the last heap proxy we saw to report an "unknown" error. As every poisoned
 514    :    // block of the shadow memory should point to a memory block or to an internal
 515    :    // structure this case should never happen.
 516  E :    if (item == NULL) {
 517  i :      NOTREACHED();
 518  i :      bad_access_info->error_type = HeapProxy::UNKNOWN_BAD_ACCESS;
 519  i :      CHECK(proxy != NULL);
 520  i :      proxy->ReportWildAccess(addr, context, stack, access_mode, access_size);
 521    :    }
 522  E :  }
 523    :  
 524    :  }  // namespace asan
 525    :  }  // namespace agent

Coverage information generated Thu Jul 04 09:34:53 2013.