Coverage for /Syzygy/instrument/transforms/asan_transform_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
99.3%102210290.C++test

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    :  // Unittests for the Asan transform.
  16    :  
  17    :  #include "syzygy/instrument/transforms/asan_transform.h"
  18    :  
  19    :  #include <set>
  20    :  #include <unordered_set>
  21    :  #include <vector>
  22    :  
  23    :  #include "base/scoped_native_library.h"
  24    :  #include "base/files/scoped_temp_dir.h"
  25    :  #include "base/strings/string_util.h"
  26    :  #include "base/strings/stringprintf.h"
  27    :  #include "base/win/pe_image.h"
  28    :  #include "gmock/gmock.h"
  29    :  #include "gtest/gtest.h"
  30    :  #include "syzygy/block_graph/basic_block_assembler.h"
  31    :  #include "syzygy/block_graph/block_hash.h"
  32    :  #include "syzygy/block_graph/unittest_util.h"
  33    :  #include "syzygy/common/defs.h"
  34    :  #include "syzygy/core/unittest_util.h"
  35    :  #include "syzygy/instrument/transforms/asan_intercepts.h"
  36    :  #include "syzygy/instrument/transforms/unittest_util.h"
  37    :  #include "syzygy/pe/coff_relinker.h"
  38    :  #include "syzygy/pe/coff_utils.h"
  39    :  #include "syzygy/pe/decomposer.h"
  40    :  #include "syzygy/pe/pe_file.h"
  41    :  #include "syzygy/pe/pe_relinker.h"
  42    :  #include "syzygy/pe/pe_utils.h"
  43    :  #include "syzygy/pe/unittest_util.h"
  44    :  #include "syzygy/pe/transforms/pe_add_imports_transform.h"
  45    :  #include "third_party/distorm/files/include/mnemonics.h"
  46    :  
  47    :  namespace instrument {
  48    :  namespace transforms {
  49    :  
  50    :  namespace {
  51    :  
  52    :  using block_graph::BasicBlock;
  53    :  using block_graph::BasicCodeBlock;
  54    :  using block_graph::BasicBlockSubGraph;
  55    :  using block_graph::BlockGraph;
  56    :  using block_graph::Instruction;
  57    :  using block_graph::RelativeAddressFilter;
  58    :  using core::RelativeAddress;
  59    :  using testing::ContainerEq;
  60    :  typedef AsanBasicBlockTransform::MemoryAccessMode AsanMemoryAccessMode;
  61    :  typedef AsanBasicBlockTransform::AsanHookMap HookMap;
  62    :  typedef AsanBasicBlockTransform::AsanHookMapEntryKey HookMapEntryKey;
  63    :  
  64    :  // Derived classes to expose protected members for unit-testing.
  65    :  
  66    :  class TestAsanBasicBlockTransform : public AsanBasicBlockTransform {
  67    :   public:
  68    :    using AsanBasicBlockTransform::InstrumentBasicBlock;
  69    :  
  70  E :    explicit TestAsanBasicBlockTransform(AsanHookMap* hooks_check_access)
  71  E :        : AsanBasicBlockTransform(hooks_check_access) {
  72  E :    }
  73    :  };
  74    :  
  75    :  class TestAsanInterceptorFilter : public AsanInterceptorFilter {
  76    :   public:
  77    :    using AsanInterceptorFilter::AddBlockToHashMap;
  78    :  };
  79    :  
  80    :  class TestAsanTransform : public AsanTransform {
  81    :   public:
  82    :    using AsanTransform::asan_parameters_block_;
  83    :    using AsanTransform::heap_init_blocks_;
  84    :    using AsanTransform::hot_patched_blocks_;
  85    :    using AsanTransform::static_intercepted_blocks_;
  86    :    using AsanTransform::use_interceptors_;
  87    :    using AsanTransform::use_liveness_analysis_;
  88    :    using AsanTransform::CoffInterceptFunctions;
  89    :    using AsanTransform::FindHeapInitAndCrtHeapBlocks;
  90    :    using AsanTransform::ShouldSkipBlock;
  91    :    using AsanTransform::PeFindStaticallyLinkedFunctionsToIntercept;
  92    :    using AsanTransform::PeInterceptFunctions;
  93    :    using AsanTransform::PeInjectAsanParameters;
  94    :  };
  95    :  
  96    :  class AsanTransformTest : public testing::TestDllTransformTest {
  97    :   public:
  98  E :    AsanTransformTest() : basic_block_(NULL) {
  99  E :      basic_block_ = subgraph_.AddBasicCodeBlock("dummy");
 100  E :      bb_asm_.reset(new block_graph::BasicBlockAssembler(
 101    :          basic_block_->instructions().begin(),
 102    :          &basic_block_->instructions()));
 103    :  
 104    :      // Insert a block description into the subgraph containing the dummy
 105    :      // basic block.
 106    :      BasicBlockSubGraph::BlockDescription* description =
 107  E :          subgraph_.AddBlockDescription("dummy_block", "dummy_compiland",
 108    :                                        BlockGraph::CODE_BLOCK, 0, 1, 0);
 109  E :      description->basic_block_order.push_back(basic_block_);
 110  E :    }
 111    :  
 112  E :    void ApplyTransformToIntegrationTestDll() {
 113  E :      base::FilePath input_path = ::testing::GetOutputRelativePath(
 114    :          testing::kIntegrationTestsDllName);
 115    :  
 116  E :      base::FilePath temp_dir;
 117  E :      CreateTemporaryDir(&temp_dir);
 118  E :      relinked_path_ = temp_dir.Append(testing::kIntegrationTestsDllName);
 119    :  
 120  E :      pe::PERelinker relinker(&pe_policy_);
 121  E :      relinker.set_input_path(input_path);
 122  E :      relinker.set_output_path(relinked_path_);
 123    :  
 124  E :      asan_transform_.use_interceptors_ = true;
 125  E :      asan_transform_.use_liveness_analysis_ = true;
 126  E :      relinker.AppendTransform(&asan_transform_);
 127  E :      ASSERT_TRUE(relinker.Init());
 128  E :      ASSERT_TRUE(relinker.Relink());
 129  E :    }
 130    :  
 131    :    void AddHookRef(const std::string& hook_name,
 132    :                    AsanBasicBlockTransform::MemoryAccessMode access_kind,
 133    :                    int access_size,
 134    :                    uint16_t opcode,
 135  E :                    bool save_flags) {
 136    :        HookMapEntryKey map_key = {
 137  E :            access_kind,
 138  E :            access_size,
 139  E :            opcode,
 140  E :            save_flags
 141    :        };
 142  E :        hooks_check_access_[map_key] =
 143    :            block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 4, hook_name);
 144    :        // Set up the references to the hooks needed by SyzyAsan.
 145  E :        hooks_check_access_ref_[map_key] =
 146    :            BlockGraph::Reference(BlockGraph::ABSOLUTE_REF, 4,
 147    :                                  hooks_check_access_[map_key], 0, 0);
 148  E :    }
 149    :  
 150  E :    void InitHooksRefs() {
 151    :      // Initialize the read access hooks.
 152  E :      for (int access_size = 1; access_size <= 8; access_size *= 2) {
 153    :        std::string name =
 154  E :            base::StringPrintf("asan_check_%d_byte_read_access", access_size);
 155  E :        AddHookRef(name, AsanBasicBlockTransform::kReadAccess, access_size, 0,
 156    :                   true);
 157  E :        name += "_no_flags";
 158  E :        AddHookRef(name, AsanBasicBlockTransform::kReadAccess, access_size, 0,
 159    :                   false);
 160  E :      }
 161    :      // Initialize the write access hooks.
 162  E :      for (int access_size = 1; access_size <= 8; access_size *= 2) {
 163    :        std::string name =
 164  E :            base::StringPrintf("asan_check_%d_byte_write_access", access_size);
 165  E :        AddHookRef(name, AsanBasicBlockTransform::kWriteAccess, access_size, 0,
 166    :                   true);
 167  E :        name += "_no_flags";
 168  E :        AddHookRef(name, AsanBasicBlockTransform::kWriteAccess, access_size, 0,
 169    :                   false);
 170  E :      }
 171    :  
 172  E :      const _InstructionType strings[] = { I_CMPS, I_MOVS, I_STOS };
 173  E :      int strings_length = arraysize(strings);
 174    :  
 175  E :      for (int access_size = 1; access_size <= 4; access_size *= 2) {
 176  E :        for (int inst = 0; inst < strings_length; ++inst) {
 177  E :          uint16_t opcode = strings[inst];
 178    :          const char* opcode_str =
 179  E :              reinterpret_cast<const char*>(GET_MNEMONIC_NAME(opcode));
 180    :          std::string name =
 181  E :              base::StringPrintf("asan_check_repz_%d_byte_%s_access",
 182    :                                 access_size, opcode_str);
 183  E :          name = base::ToLowerASCII(name);
 184  E :          AddHookRef(name, AsanBasicBlockTransform::kRepzAccess, access_size,
 185    :                     opcode, true);
 186  E :        }
 187  E :      }
 188    :  
 189    :      // Initialize special instruction hooks.
 190  E :      for (int access_size = 1; access_size <= 4; access_size *= 2) {
 191  E :        for (int inst = 0; inst < strings_length; ++inst) {
 192  E :          uint16_t opcode = strings[inst];
 193    :          const char* opcode_str =
 194  E :              reinterpret_cast<const char*>(GET_MNEMONIC_NAME(opcode));
 195    :  
 196    :          // Initialize the strings without prefix access hooks.
 197    :          std::string name =
 198  E :              base::StringPrintf("asan_check_%d_byte_%s_access",
 199    :                                 access_size, opcode_str);
 200  E :          name = base::ToLowerASCII(name);
 201  E :          AddHookRef(name, AsanBasicBlockTransform::kInstrAccess, access_size,
 202    :                     opcode, true);
 203    :  
 204    :          // Initialize the strings with prefix access hooks.
 205  E :          std::string repz_name = base::StringPrintf(
 206    :              "asan_check_repz_%d_byte_%s_access", access_size, opcode_str);
 207  E :          name = base::ToLowerASCII(repz_name);
 208  E :          AddHookRef(repz_name, AsanBasicBlockTransform::kRepzAccess, access_size,
 209    :                     opcode, true);
 210  E :        }
 211  E :      }
 212  E :    }
 213    :  
 214  E :    bool AddInstructionFromBuffer(const uint8_t* data, size_t length) {
 215  E :      EXPECT_NE(static_cast<const uint8_t*>(NULL), data);
 216  E :      EXPECT_GE(assm::kMaxInstructionLength, length);
 217    :  
 218  E :      block_graph::Instruction temp;
 219  E :      if (!block_graph::Instruction::FromBuffer(data, length, &temp))
 220  i :        return false;
 221    :  
 222    :      // Append this instruction to the basic block.
 223  E :      basic_block_->instructions().push_back(temp);
 224    :  
 225  E :      return true;
 226  E :    }
 227    :  
 228    :    // Some handy constants we'll use throughout the tests.
 229    :    // @{
 230    :    static const BasicBlock::Size kDataSize;
 231    :    static const uint8_t kBlockData[];
 232    :    // @}
 233    :  
 234    :   protected:
 235    :    TestAsanTransform asan_transform_;
 236    :    HookMap hooks_check_access_ref_;
 237    :    std::map<HookMapEntryKey, BlockGraph::Block*> hooks_check_access_;
 238    :    BasicBlockSubGraph subgraph_;
 239    :    BasicCodeBlock* basic_block_;
 240    :    std::unique_ptr<block_graph::BasicBlockAssembler> bb_asm_;
 241    :    base::FilePath relinked_path_;
 242    :  };
 243    :  
 244    :  const BasicBlock::Size AsanTransformTest::kDataSize = 32;
 245    :  const uint8_t AsanTransformTest::kBlockData[AsanTransformTest::kDataSize] = {};
 246    :  
 247    :  // Dummy library name to test |set_instrument_dll_name|.
 248    :  const char kFooDll[] = "foo.dll";
 249    :  
 250    :  }  // namespace
 251    :  
 252  E :  TEST_F(AsanTransformTest, SetAsanParameters) {
 253  E :    common::InflatedAsanParameters iparams;
 254  E :    common::InflatedAsanParameters* null = NULL;
 255  E :    common::InflatedAsanParameters* params = &iparams;
 256    :  
 257  E :    EXPECT_EQ(null, asan_transform_.asan_parameters());
 258  E :    asan_transform_.set_asan_parameters(params);
 259  E :    EXPECT_EQ(params, asan_transform_.asan_parameters());
 260  E :    asan_transform_.set_asan_parameters(NULL);
 261  E :    EXPECT_EQ(null, asan_transform_.asan_parameters());
 262  E :  }
 263    :  
 264  E :  TEST_F(AsanTransformTest, SetDryRunFlag) {
 265  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 266  E :    EXPECT_FALSE(bb_transform.dry_run());
 267  E :    bb_transform.set_dry_run(true);
 268  E :    EXPECT_TRUE(bb_transform.dry_run());
 269  E :    bb_transform.set_dry_run(false);
 270  E :    EXPECT_FALSE(bb_transform.dry_run());
 271  E :  }
 272    :  
 273  E :  TEST_F(AsanTransformTest, SetHotPatchingFlag) {
 274  E :    EXPECT_FALSE(asan_transform_.hot_patching());
 275  E :    asan_transform_.set_hot_patching(true);
 276  E :    EXPECT_TRUE(asan_transform_.hot_patching());
 277  E :    asan_transform_.set_hot_patching(false);
 278  E :    EXPECT_FALSE(asan_transform_.hot_patching());
 279  E :  }
 280    :  
 281  E :  TEST_F(AsanTransformTest, SetInstrumentDllName) {
 282  E :    EXPECT_EQ(AsanTransform::kSyzyAsanDll, asan_transform_.instrument_dll_name());
 283  E :    asan_transform_.set_instrument_dll_name(kFooDll);
 284  E :    EXPECT_EQ(kFooDll, asan_transform_.instrument_dll_name());
 285  E :  }
 286    :  
 287  E :  TEST_F(AsanTransformTest, SetInstrumentDllNameHotPatchingMode) {
 288    :    // The default dll name is different in hot patching mode.
 289  E :    asan_transform_.set_hot_patching(true);
 290  E :    EXPECT_EQ(AsanTransform::kSyzyAsanHpDll,
 291  E :              asan_transform_.instrument_dll_name());
 292  E :    asan_transform_.set_instrument_dll_name(kFooDll);
 293  E :    EXPECT_EQ(kFooDll, asan_transform_.instrument_dll_name());
 294  E :  }
 295    :  
 296  E :  TEST_F(AsanTransformTest, GetInstrumentationHappenedFlag) {
 297  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 298  E :    EXPECT_FALSE(bb_transform.instrumentation_happened());
 299  E :  }
 300    :  
 301  E :  TEST_F(AsanTransformTest, SetInstrumentationRate) {
 302  E :    EXPECT_EQ(1.0, asan_transform_.instrumentation_rate());
 303  E :    asan_transform_.set_instrumentation_rate(1.2);
 304  E :    EXPECT_EQ(1.0, asan_transform_.instrumentation_rate());
 305  E :    asan_transform_.set_instrumentation_rate(-0.2);
 306  E :    EXPECT_EQ(0.0, asan_transform_.instrumentation_rate());
 307  E :    asan_transform_.set_instrumentation_rate(0.5);
 308  E :    EXPECT_EQ(0.5, asan_transform_.instrumentation_rate());;
 309    :  
 310  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 311  E :    EXPECT_EQ(1.0, bb_transform.instrumentation_rate());
 312  E :    bb_transform.set_instrumentation_rate(1.2);
 313  E :    EXPECT_EQ(1.0, bb_transform.instrumentation_rate());
 314  E :    bb_transform.set_instrumentation_rate(-0.2);
 315  E :    EXPECT_EQ(0.0, bb_transform.instrumentation_rate());
 316  E :    bb_transform.set_instrumentation_rate(0.5);
 317  E :    EXPECT_EQ(0.5, bb_transform.instrumentation_rate());
 318  E :  }
 319    :  
 320  E :  TEST_F(AsanTransformTest, SetInterceptCRTFuntionsFlag) {
 321  E :    EXPECT_FALSE(asan_transform_.use_interceptors());
 322  E :    asan_transform_.set_use_interceptors(true);
 323  E :    EXPECT_TRUE(asan_transform_.use_interceptors());
 324  E :    asan_transform_.set_use_interceptors(false);
 325  E :    EXPECT_FALSE(asan_transform_.use_interceptors());
 326  E :  }
 327    :  
 328  E :  TEST_F(AsanTransformTest, SetRemoveRedundantChecksFlag) {
 329  E :    EXPECT_FALSE(asan_transform_.remove_redundant_checks());
 330  E :    asan_transform_.set_remove_redundant_checks(true);
 331  E :    EXPECT_TRUE(asan_transform_.remove_redundant_checks());
 332  E :    asan_transform_.set_remove_redundant_checks(false);
 333  E :    EXPECT_FALSE(asan_transform_.remove_redundant_checks());
 334    :  
 335  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 336  E :    EXPECT_FALSE(bb_transform.remove_redundant_checks());
 337  E :    bb_transform.set_remove_redundant_checks(true);
 338  E :    EXPECT_TRUE(bb_transform.remove_redundant_checks());
 339  E :    bb_transform.set_remove_redundant_checks(false);
 340  E :    EXPECT_FALSE(bb_transform.remove_redundant_checks());
 341  E :  }
 342    :  
 343  E :  TEST_F(AsanTransformTest, SetUseLivenessFlag) {
 344  E :    EXPECT_FALSE(asan_transform_.use_liveness_analysis());
 345  E :    asan_transform_.set_use_liveness_analysis(true);
 346  E :    EXPECT_TRUE(asan_transform_.use_liveness_analysis());
 347  E :    asan_transform_.set_use_liveness_analysis(false);
 348  E :    EXPECT_FALSE(asan_transform_.use_liveness_analysis());
 349    :  
 350  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 351  E :    EXPECT_FALSE(bb_transform.use_liveness_analysis());
 352  E :    bb_transform.set_use_liveness_analysis(true);
 353  E :    EXPECT_TRUE(bb_transform.use_liveness_analysis());
 354  E :    bb_transform.set_use_liveness_analysis(false);
 355  E :    EXPECT_FALSE(bb_transform.use_liveness_analysis());
 356  E :  }
 357    :  
 358  E :  TEST_F(AsanTransformTest, ApplyAsanTransformPE) {
 359  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
 360    :  
 361  E :    asan_transform_.use_interceptors_ = true;
 362  E :    ASSERT_TRUE(block_graph::ApplyBlockGraphTransform(
 363  E :        &asan_transform_, policy_, &block_graph_, header_block_));
 364  E :  }
 365    :  
 366  E :  TEST_F(AsanTransformTest, ApplyAsanTransformCoff) {
 367  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDllObj());
 368    :  
 369  E :    asan_transform_.use_interceptors_ = true;
 370  E :    ASSERT_TRUE(block_graph::ApplyBlockGraphTransform(
 371  E :        &asan_transform_, policy_, &block_graph_, header_block_));
 372  E :  }
 373    :  
 374  E :  TEST_F(AsanTransformTest, NopsNotInstrumented) {
 375    :    // Add all of the nops to the block.
 376    :    static const size_t kMaxNopSize =
 377    :        block_graph::BasicBlockAssembler::kMaxNopInstructionSize;
 378  E :    for (size_t i = 1; i <= kMaxNopSize; ++i)
 379  E :      bb_asm_->nop(i);
 380    :  
 381    :    // Add source ranges to the instruction.
 382  E :    block_graph::Instruction& i1 = *basic_block_->instructions().begin();
 383    :    Instruction::SourceRange source_range =
 384  E :        Instruction::SourceRange(RelativeAddress(1000), i1.size());
 385  E :    i1.set_source_range(source_range);
 386    :  
 387    :    // Instrument this basic block.
 388  E :    InitHooksRefs();
 389  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 390  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 391    :        basic_block_,
 392    :        AsanBasicBlockTransform::kSafeStackAccess,
 393  E :        BlockGraph::PE_IMAGE));
 394    :  
 395    :    // Expect that no instrumentation happened.
 396  E :    EXPECT_FALSE(bb_transform.instrumentation_happened());
 397    :  
 398    :    // Expect the same number of instructions as before the instrumentation.
 399  E :    ASSERT_EQ(basic_block_->instructions().size(), kMaxNopSize);
 400  E :  }
 401    :  
 402  E :  TEST_F(AsanTransformTest, InjectAsanHooksPe) {
 403    :    // Add a read access to the memory.
 404  E :    bb_asm_->mov(assm::eax, block_graph::Operand(assm::ebx));
 405    :    // Add a write access to the memory.
 406  E :    bb_asm_->mov(block_graph::Operand(assm::ecx), assm::edx);
 407    :  
 408    :    // Add source ranges to the instruction.
 409  E :    block_graph::Instruction& i1 = *basic_block_->instructions().begin();
 410    :    Instruction::SourceRange source_range =
 411  E :        Instruction::SourceRange(RelativeAddress(1000), i1.size());
 412  E :    i1.set_source_range(source_range);
 413    :  
 414    :    // Instrument this basic block.
 415  E :    InitHooksRefs();
 416  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 417  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 418    :        basic_block_,
 419    :        AsanBasicBlockTransform::kSafeStackAccess,
 420  E :        BlockGraph::PE_IMAGE));
 421    :  
 422    :    // Ensure that the basic block is instrumented.
 423    :  
 424    :    // Check what the transform reports at first.
 425  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 426    :  
 427    :    // We had 2 instructions initially, and for each of them we add 3
 428    :    // instructions, so we expect to have 2 + 3 * 2 = 8 instructions.
 429  E :    ASSERT_EQ(basic_block_->instructions().size(), 8);
 430    :  
 431    :    // Walk through the instructions to ensure that the Asan hooks have been
 432    :    // injected.
 433    :    BasicBlock::Instructions::const_iterator iter_inst =
 434  E :        basic_block_->instructions().begin();
 435    :  
 436  E :    Instruction::SourceRange empty_source_range;
 437  E :    ASSERT_NE(empty_source_range, source_range);
 438    :  
 439    :    // First we check if the first memory access is instrumented as a 4 byte read
 440    :    // access. We also validate that the instrumentation has not had source range
 441    :    // information added.
 442  E :    ASSERT_EQ(empty_source_range, iter_inst->source_range());
 443  E :    ASSERT_EQ(I_PUSH, (iter_inst++)->representation().opcode);
 444  E :    ASSERT_EQ(empty_source_range, iter_inst->source_range());
 445  E :    ASSERT_EQ(I_LEA, (iter_inst++)->representation().opcode);
 446  E :    ASSERT_EQ(empty_source_range, iter_inst->source_range());
 447  E :    ASSERT_EQ(iter_inst->references().size(), 1);
 448    :    HookMapEntryKey check_4_byte_read_key =
 449  E :        { AsanBasicBlockTransform::kReadAccess, 4, 0, true };
 450  E :    ASSERT_EQ(hooks_check_access_[check_4_byte_read_key],
 451  E :        iter_inst->references().begin()->second.block());
 452  E :    ASSERT_EQ(O_DISP, iter_inst->representation().ops[0].type);
 453  E :    ASSERT_EQ(I_CALL, (iter_inst++)->representation().opcode);
 454  E :    ASSERT_EQ(I_MOV, (iter_inst++)->representation().opcode);
 455    :  
 456    :    // Then we check if the second memory access is well instrumented as a 4 byte
 457    :    // write access.
 458  E :    ASSERT_EQ(I_PUSH, (iter_inst++)->representation().opcode);
 459  E :    ASSERT_EQ(I_LEA, (iter_inst++)->representation().opcode);
 460  E :    ASSERT_EQ(iter_inst->references().size(), 1);
 461    :    HookMapEntryKey check_4_byte_write_key =
 462  E :        { AsanBasicBlockTransform::kWriteAccess, 4, 0, true };
 463  E :    ASSERT_EQ(hooks_check_access_[check_4_byte_write_key],
 464  E :        iter_inst->references().begin()->second.block());
 465  E :    ASSERT_EQ(I_CALL, (iter_inst++)->representation().opcode);
 466  E :    ASSERT_EQ(I_MOV, (iter_inst++)->representation().opcode);
 467    :  
 468  E :    ASSERT_TRUE(iter_inst == basic_block_->instructions().end());
 469  E :  }
 470    :  
 471  E :  TEST_F(AsanTransformTest, InjectAsanHooksWithSourceRangePe) {
 472    :    // Add a read access to the memory.
 473  E :    bb_asm_->mov(assm::eax, block_graph::Operand(assm::ebx));
 474    :  
 475    :    // Add a source range to the instruction.
 476  E :    block_graph::Instruction& i1 = *basic_block_->instructions().begin();
 477    :    Instruction::SourceRange source_range =
 478  E :        Instruction::SourceRange(RelativeAddress(1000), i1.size());
 479  E :    i1.set_source_range(source_range);
 480    :  
 481    :    // Keep track of basic block size.
 482  E :    uint32_t before_instructions_count = basic_block_->instructions().size();
 483    :  
 484    :    // Instrument this basic block.
 485  E :    InitHooksRefs();
 486  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 487  E :    bb_transform.set_debug_friendly(true);
 488    :  
 489  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 490    :          basic_block_,
 491    :          AsanBasicBlockTransform::kSafeStackAccess,
 492  E :          BlockGraph::PE_IMAGE));
 493    :  
 494    :    // Ensure this basic block is instrumented.
 495  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 496  E :    uint32_t after_instructions_count = basic_block_->instructions().size();
 497  E :    ASSERT_LT(before_instructions_count, after_instructions_count);
 498    :  
 499    :    // Walk through the instructions and validate the source range.
 500    :    BasicBlock::Instructions::const_iterator iter_inst =
 501  E :        basic_block_->instructions().begin();
 502    :  
 503  E :    for ( ; iter_inst != basic_block_->instructions().end(); ++iter_inst)
 504  E :      EXPECT_EQ(source_range, iter_inst->source_range());
 505  E :  }
 506    :  
 507  E :  TEST_F(AsanTransformTest, InjectAsanHooksCoff) {
 508    :    // Add a read access to the memory.
 509  E :    bb_asm_->mov(assm::eax, block_graph::Operand(assm::ebx));
 510    :    // Add a write access to the memory.
 511  E :    bb_asm_->mov(block_graph::Operand(assm::ecx), assm::edx);
 512    :  
 513    :    // Add source ranges to the instruction.
 514  E :    block_graph::Instruction& i1 = *basic_block_->instructions().begin();
 515    :    Instruction::SourceRange source_range =
 516  E :        Instruction::SourceRange(RelativeAddress(1000), i1.size());
 517  E :    i1.set_source_range(source_range);
 518    :  
 519    :    // Instrument this basic block.
 520  E :    InitHooksRefs();
 521  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 522  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 523    :        basic_block_,
 524    :        AsanBasicBlockTransform::kSafeStackAccess,
 525  E :        BlockGraph::COFF_IMAGE));
 526    :  
 527    :    // Ensure that the basic block is instrumented.
 528    :  
 529    :    // Check what the transform reports at first.
 530  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 531    :  
 532    :    // We had 2 instructions initially, and for each of them we add 3
 533    :    // instructions, so we expect to have 2 + 3 * 2 = 8 instructions.
 534  E :    ASSERT_EQ(basic_block_->instructions().size(), 8);
 535    :  
 536    :    // Walk through the instructions to ensure that the Asan hooks have been
 537    :    // injected.
 538    :    BasicBlock::Instructions::const_iterator iter_inst =
 539  E :        basic_block_->instructions().begin();
 540    :  
 541  E :    Instruction::SourceRange empty_source_range;
 542  E :    ASSERT_NE(empty_source_range, source_range);
 543    :  
 544    :    // First we check if the first memory access is instrumented as a 4 byte read
 545    :    // access. We also validate that the instrumentation has not had source range
 546    :    // information added.
 547  E :    ASSERT_EQ(empty_source_range, iter_inst->source_range());
 548  E :    ASSERT_EQ(I_PUSH, (iter_inst++)->representation().opcode);
 549  E :    ASSERT_EQ(empty_source_range, iter_inst->source_range());
 550  E :    ASSERT_EQ(I_LEA, (iter_inst++)->representation().opcode);
 551  E :    ASSERT_EQ(empty_source_range, iter_inst->source_range());
 552  E :    ASSERT_EQ(iter_inst->references().size(), 1);
 553    :    HookMapEntryKey check_4_byte_read_key =
 554  E :        { AsanBasicBlockTransform::kReadAccess, 4, 0, true };
 555  E :    ASSERT_EQ(hooks_check_access_[check_4_byte_read_key],
 556  E :        iter_inst->references().begin()->second.block());
 557  E :    ASSERT_EQ(O_PC, iter_inst->representation().ops[0].type);
 558  E :    ASSERT_EQ(I_CALL, (iter_inst++)->representation().opcode);
 559  E :    ASSERT_EQ(I_MOV, (iter_inst++)->representation().opcode);
 560    :  
 561    :    // Then we check if the second memory access is well instrumented as a 4 byte
 562    :    // write access.
 563  E :    ASSERT_EQ(I_PUSH, (iter_inst++)->representation().opcode);
 564  E :    ASSERT_EQ(I_LEA, (iter_inst++)->representation().opcode);
 565  E :    ASSERT_EQ(iter_inst->references().size(), 1);
 566    :    HookMapEntryKey check_4_byte_write_key =
 567  E :        { AsanBasicBlockTransform::kWriteAccess, 4, 0, true };
 568  E :    ASSERT_EQ(hooks_check_access_[check_4_byte_write_key],
 569  E :        iter_inst->references().begin()->second.block());
 570  E :    ASSERT_EQ(I_CALL, (iter_inst++)->representation().opcode);
 571  E :    ASSERT_EQ(I_MOV, (iter_inst++)->representation().opcode);
 572    :  
 573  E :    ASSERT_TRUE(iter_inst == basic_block_->instructions().end());
 574  E :  }
 575    :  
 576  E :  TEST_F(AsanTransformTest, InstrumentDifferentKindOfInstructions) {
 577  E :    uint32_t instrumentable_instructions = 0;
 578    :  
 579    :    // Generate a bunch of instrumentable and non-instrumentable instructions.
 580  E :    bb_asm_->mov(assm::eax, block_graph::Operand(assm::ebx));
 581  E :    instrumentable_instructions++;
 582  E :    bb_asm_->mov(block_graph::Operand(assm::ecx), assm::edx);
 583  E :    instrumentable_instructions++;
 584  E :    bb_asm_->call(block_graph::Operand(assm::ecx));
 585  E :    instrumentable_instructions++;
 586  E :    bb_asm_->jmp(block_graph::Operand(assm::ecx));
 587  E :    instrumentable_instructions++;
 588  E :    bb_asm_->push(block_graph::Operand(assm::eax));
 589  E :    instrumentable_instructions++;
 590    :  
 591    :    // Non-instrumentable.
 592  E :    bb_asm_->lea(assm::eax, block_graph::Operand(assm::ecx));
 593    :  
 594    :    uint32_t expected_instructions_count =
 595  E :        basic_block_->instructions().size() + 3 * instrumentable_instructions;
 596    :    // Instrument this basic block.
 597  E :    InitHooksRefs();
 598  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 599  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 600    :        basic_block_,
 601    :        AsanBasicBlockTransform::kSafeStackAccess,
 602  E :        BlockGraph::PE_IMAGE));
 603  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 604  E :    ASSERT_EQ(basic_block_->instructions().size(), expected_instructions_count);
 605  E :  }
 606    :  
 607  E :  TEST_F(AsanTransformTest, InstrumentAndRemoveRedundantChecks) {
 608  E :    uint32_t instrumentable_instructions = 0;
 609    :  
 610    :    // Generate a bunch of instrumentable and non instrumentable instructions.
 611    :    // We generate operand [ecx] multiple time as a redundant memory access.
 612  E :    bb_asm_->mov(assm::eax, block_graph::Operand(assm::ecx));
 613  E :    instrumentable_instructions++;
 614  E :    bb_asm_->mov(block_graph::Operand(assm::ecx), assm::edx);
 615    :    // Validate that indirect call clear the memory state.
 616  E :    bb_asm_->call(block_graph::Operand(assm::ecx));
 617  E :    bb_asm_->push(block_graph::Operand(assm::eax));
 618  E :    instrumentable_instructions++;
 619  E :    bb_asm_->mov(assm::eax, block_graph::Operand(assm::ecx));
 620  E :    instrumentable_instructions++;
 621  E :    bb_asm_->jmp(block_graph::Operand(assm::ecx));
 622    :  
 623    :    uint32_t expected_instructions_count =
 624  E :        basic_block_->instructions().size() + 3 * instrumentable_instructions;
 625    :    // Instrument this basic block.
 626  E :    InitHooksRefs();
 627  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 628  E :    bb_transform.set_remove_redundant_checks(true);
 629  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 630    :        basic_block_,
 631    :        AsanBasicBlockTransform::kSafeStackAccess,
 632  E :        BlockGraph::PE_IMAGE));
 633  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 634  E :    ASSERT_EQ(basic_block_->instructions().size(), expected_instructions_count);
 635  E :  }
 636    :  
 637  E :  TEST_F(AsanTransformTest, NonInstrumentableStackBasedInstructions) {
 638    :    // DEC DWORD [EBP - 0x2830]
 639    :    static const uint8_t kDec1[6] = {0xff, 0x8d, 0xd0, 0xd7, 0xff, 0xff};
 640    :    // INC DWORD [EBP - 0x31c]
 641    :    static const uint8_t kInc1[6] = {0xff, 0x85, 0xe4, 0xfc, 0xff, 0xff};
 642    :    // INC DWORD [ESP + 0x1c]
 643    :    static const uint8_t kInc2[4] = {0xff, 0x44, 0x24, 0x1c};
 644    :    // NEG DWORD [EBP + 0x24]
 645    :    static const uint8_t kNeg1[3] = {0xf7, 0x5d, 0x24};
 646    :    // FILD QWORD [EBP - 0x8]
 647    :    static const uint8_t kFild1[3] = {0xdf, 0x6d, 0xf8};
 648    :    // FISTP QWORD [ESP + 0x28]
 649    :    static const uint8_t kFistp1[4] = {0xdf, 0x7c, 0x24, 0x28};
 650    :    // MOV EDI, [EBP - 0x4]
 651    :    static const uint8_t kMov1[3] = {0x8b, 0x7d, 0xfc};
 652    :    // MOV EAX, [EBP - 0x104]
 653    :    static const uint8_t kMov2[6] = {0x8b, 0x85, 0xfc, 0xfe, 0xff, 0xff};
 654    :  
 655  E :    ASSERT_TRUE(AddInstructionFromBuffer(kDec1, sizeof(kDec1)));
 656  E :    ASSERT_TRUE(AddInstructionFromBuffer(kInc1, sizeof(kInc1)));
 657  E :    ASSERT_TRUE(AddInstructionFromBuffer(kInc2, sizeof(kInc2)));
 658  E :    ASSERT_TRUE(AddInstructionFromBuffer(kNeg1, sizeof(kNeg1)));
 659  E :    ASSERT_TRUE(AddInstructionFromBuffer(kFild1, sizeof(kFild1)));
 660  E :    ASSERT_TRUE(AddInstructionFromBuffer(kFistp1, sizeof(kFistp1)));
 661  E :    ASSERT_TRUE(AddInstructionFromBuffer(kMov1, sizeof(kMov1)));
 662  E :    ASSERT_TRUE(AddInstructionFromBuffer(kMov2, sizeof(kMov2)));
 663    :  
 664    :    // Keep track of the basic block size before Asan transform.
 665  E :    uint32_t expected_basic_block_size = basic_block_->instructions().size();
 666    :  
 667    :    // Instrument this basic block.
 668  E :    InitHooksRefs();
 669  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 670  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 671    :          basic_block_,
 672    :          AsanBasicBlockTransform::kSafeStackAccess,
 673  E :          BlockGraph::PE_IMAGE));
 674    :  
 675    :    // Non-instrumentable instructions implies no change.
 676  E :    EXPECT_FALSE(bb_transform.instrumentation_happened());
 677  E :    EXPECT_EQ(expected_basic_block_size, basic_block_->instructions().size());
 678  E :  }
 679    :  
 680  E :  TEST_F(AsanTransformTest, InstrumentableStackBasedUnsafeInstructions) {
 681    :    // DEC DWORD [EBP - 0x2830]
 682    :    static const uint8_t kDec1[6] = {0xff, 0x8d, 0xd0, 0xd7, 0xff, 0xff};
 683    :  
 684  E :    ASSERT_TRUE(AddInstructionFromBuffer(kDec1, sizeof(kDec1)));
 685    :  
 686    :    // Keep track of the basic block size before Asan transform.
 687  E :    uint32_t previous_basic_block_size = basic_block_->instructions().size();
 688    :  
 689    :    // Instrument this basic block considering invalid stack manipulation.
 690  E :    InitHooksRefs();
 691  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 692  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 693    :          basic_block_,
 694    :          AsanBasicBlockTransform::kUnsafeStackAccess,
 695  E :          BlockGraph::PE_IMAGE));
 696    :  
 697    :    // This instruction should have been instrumented, and we must observe
 698    :    // a increase in size.
 699  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 700  E :    EXPECT_LT(previous_basic_block_size, basic_block_->instructions().size());
 701  E :  }
 702    :  
 703  E :  TEST_F(AsanTransformTest, NonInstrumentableSegmentBasedInstructions) {
 704    :    // add eax, fs:[eax]
 705    :    static const uint8_t kAdd1[3] = {0x64, 0x03, 0x00};
 706    :    // inc gs:[eax]
 707    :    static const uint8_t kInc1[3] = {0x65, 0xFE, 0x00};
 708    :  
 709  E :    ASSERT_TRUE(AddInstructionFromBuffer(kAdd1, sizeof(kAdd1)));
 710  E :    ASSERT_TRUE(AddInstructionFromBuffer(kInc1, sizeof(kInc1)));
 711    :  
 712    :    // Keep track of the basic block size before Asan transform.
 713  E :    uint32_t expected_basic_block_size = basic_block_->instructions().size();
 714    :  
 715    :    // Instrument this basic block.
 716  E :    InitHooksRefs();
 717  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 718  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 719    :          basic_block_,
 720    :          AsanBasicBlockTransform::kSafeStackAccess,
 721  E :          BlockGraph::PE_IMAGE));
 722    :  
 723    :    // Non-instrumentable instructions implies no change.
 724  E :    EXPECT_FALSE(bb_transform.instrumentation_happened());
 725  E :    EXPECT_EQ(expected_basic_block_size, basic_block_->instructions().size());
 726  E :  }
 727    :  
 728  E :  TEST_F(AsanTransformTest, FilteredInstructionsNotInstrumented) {
 729    :    // Add a read access to the memory.
 730  E :    bb_asm_->mov(assm::eax, block_graph::Operand(assm::ebx));
 731    :    // Add a write access to the memory.
 732  E :    bb_asm_->mov(block_graph::Operand(assm::ecx), assm::edx);
 733    :  
 734    :    // Add a source range to the first instruction.
 735  E :    block_graph::Instruction& i1 = *basic_block_->instructions().begin();
 736  E :    i1.set_source_range(Instruction::SourceRange(
 737    :        RelativeAddress(1000), i1.size()));
 738    :  
 739    :    // Create a filter that blocks out that source range.
 740  E :    RelativeAddressFilter filter(
 741    :        RelativeAddressFilter::Range(RelativeAddress(0), 2000));
 742  E :    filter.Mark(RelativeAddressFilter::Range(RelativeAddress(995), 50));
 743    :  
 744    :    // Pass the filter to the BB transform.
 745  E :    InitHooksRefs();
 746  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 747  E :    bb_transform.set_filter(&filter);
 748    :  
 749    :    // Instrument this basic block.
 750  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 751    :          basic_block_,
 752    :          AsanBasicBlockTransform::kSafeStackAccess,
 753  E :          BlockGraph::PE_IMAGE));
 754    :  
 755    :    // Ensure that the basic block is instrumented, but only the second
 756    :    // instruction.
 757    :  
 758    :    // The transform should report changes.
 759  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 760    :  
 761    :    // We had 2 instructions initially. For the second one we add 3
 762    :    // instructions, so we expect to have 1 + (1 + 3) = 5 instructions.
 763  E :    ASSERT_EQ(basic_block_->instructions().size(), 5);
 764    :  
 765    :    // Walk through the instructions to ensure that the Asan hooks have been
 766    :    // injected.
 767    :    BasicBlock::Instructions::const_iterator iter_inst =
 768  E :        basic_block_->instructions().begin();
 769    :  
 770    :    // Ensure the first instruction is not instrumented at all.
 771  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_MOV);
 772    :  
 773    :    // Then we check if the second memory access is well instrumented as a 4 byte
 774    :    // write access.
 775  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_PUSH);
 776  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_LEA);
 777  E :    ASSERT_EQ(iter_inst->references().size(), 1);
 778    :    HookMapEntryKey check_4_byte_write_key =
 779  E :        { AsanBasicBlockTransform::kWriteAccess, 4, 0, true };
 780  E :    ASSERT_TRUE(iter_inst->references().begin()->second.block()
 781  E :        == hooks_check_access_[check_4_byte_write_key]);
 782  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_CALL);
 783  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_MOV);
 784    :  
 785  E :    ASSERT_TRUE(iter_inst == basic_block_->instructions().end());
 786  E :  }
 787    :  
 788  E :  TEST_F(AsanTransformTest, InstrumentableStringInstructions) {
 789    :    static const uint8_t movsd[1] = {0xA5};
 790    :    static const uint8_t movsw[2] = {0x66, 0xA5};
 791    :    static const uint8_t movsb[1] = {0xA4};
 792    :  
 793    :    static const uint8_t cmpsd[1] = {0xA7};
 794    :    static const uint8_t cmpsw[2] = {0x66, 0xA7};
 795    :    static const uint8_t cmpsb[1] = {0xA6};
 796    :  
 797    :    static const uint8_t stosd[1] = {0xAB};
 798    :    static const uint8_t stosw[2] = {0x66, 0xAB};
 799    :    static const uint8_t stosb[1] = {0xAA};
 800    :  
 801  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsd, sizeof(movsd)));
 802  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsw, sizeof(movsw)));
 803  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsb, sizeof(movsb)));
 804  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsd, sizeof(cmpsd)));
 805  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsw, sizeof(cmpsw)));
 806  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsb, sizeof(cmpsb)));
 807  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosd, sizeof(stosd)));
 808  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosw, sizeof(stosw)));
 809  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosb, sizeof(stosb)));
 810    :  
 811    :    // Keep number of instrumentable instructions.
 812  E :    uint32_t count_instructions = basic_block_->instructions().size();
 813    :  
 814    :    // Keep track of the basic block size before Asan transform.
 815  E :    uint32_t basic_block_size = basic_block_->instructions().size();
 816    :  
 817    :    // Instrument this basic block.
 818  E :    InitHooksRefs();
 819  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 820  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 821    :          basic_block_,
 822    :          AsanBasicBlockTransform::kSafeStackAccess,
 823  E :          BlockGraph::PE_IMAGE));
 824    :  
 825  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 826    :  
 827    :    // Each instrumentable instructions implies 1 new instructions.
 828  E :    uint32_t expected_basic_block_size = count_instructions + basic_block_size;
 829    :  
 830    :    // Validate basic block size.
 831  E :    ASSERT_EQ(basic_block_->instructions().size(), expected_basic_block_size);
 832  E :  }
 833    :  
 834  E :  TEST_F(AsanTransformTest, InstrumentableRepzStringInstructions) {
 835    :    static const uint8_t movsd[2] = {0xF3, 0xA5};
 836    :    static const uint8_t movsw[3] = {0xF3, 0x66, 0xA5};
 837    :    static const uint8_t movsb[2] = {0xF3, 0xA4};
 838    :  
 839    :    static const uint8_t cmpsd[2] = {0xF3, 0xA7};
 840    :    static const uint8_t cmpsw[3] = {0xF3, 0x66, 0xA7};
 841    :    static const uint8_t cmpsb[2] = {0xF3, 0xA6};
 842    :  
 843    :    static const uint8_t stosd[2] = {0xF3, 0xAB};
 844    :    static const uint8_t stosw[3] = {0xF3, 0x66, 0xAB};
 845    :    static const uint8_t stosb[2] = {0xF3, 0xAA};
 846    :  
 847  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsd, sizeof(movsd)));
 848  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsw, sizeof(movsw)));
 849  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsb, sizeof(movsb)));
 850  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsd, sizeof(cmpsd)));
 851  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsw, sizeof(cmpsw)));
 852  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsb, sizeof(cmpsb)));
 853  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosd, sizeof(stosd)));
 854  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosw, sizeof(stosw)));
 855  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosb, sizeof(stosb)));
 856    :  
 857    :    // Keep number of instrumentable instructions.
 858  E :    uint32_t count_instructions = basic_block_->instructions().size();
 859    :  
 860    :    // Keep track of the basic block size before Asan transform.
 861  E :    uint32_t basic_block_size = basic_block_->instructions().size();
 862    :  
 863    :    // Instrument this basic block.
 864  E :    InitHooksRefs();
 865  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 866  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 867    :          basic_block_,
 868    :          AsanBasicBlockTransform::kSafeStackAccess,
 869  E :          BlockGraph::PE_IMAGE));
 870    :  
 871  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 872    :  
 873    :    // Each instrumentable instructions implies 1 new instructions.
 874  E :    uint32_t expected_basic_block_size = count_instructions + basic_block_size;
 875    :  
 876    :    // Validate basic block size.
 877  E :    ASSERT_EQ(basic_block_->instructions().size(), expected_basic_block_size);
 878  E :  }
 879    :  
 880  E :  TEST_F(AsanTransformTest, DryRunInstrumentable) {
 881    :    // Generate an instrumentable instruction.
 882  E :    bb_asm_->mov(assm::eax, block_graph::Operand(assm::ecx));
 883    :  
 884    :    // Keep track of the basic block size before Asan transform.
 885  E :    uint32_t basic_block_size = basic_block_->instructions().size();
 886    :  
 887    :    // Instrument this basic block.
 888    :    // Note that InitHooksRefs() is not needed for a dry run.
 889  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 890  E :    bb_transform.set_dry_run(true);
 891    :  
 892  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 893    :        basic_block_,
 894    :        AsanBasicBlockTransform::kSafeStackAccess,
 895  E :        BlockGraph::PE_IMAGE));
 896    :  
 897    :    // The instructions_happened() function should return true because we
 898    :    // had an instruction to instrument.
 899  E :    EXPECT_TRUE(bb_transform.instrumentation_happened());
 900    :  
 901    :    // Yet, the basic block should not be touched.
 902  E :    ASSERT_EQ(basic_block_size, basic_block_->instructions().size());
 903  E :  }
 904    :  
 905  E :  TEST_F(AsanTransformTest, DryRunNonInstrumentable) {
 906    :    // Generate a non-instrumentable instruction.
 907  E :    bb_asm_->xchg(assm::eax, assm::ecx);
 908    :  
 909    :    // Keep track of the basic block size before Asan transform.
 910  E :    uint32_t basic_block_size = basic_block_->instructions().size();
 911    :  
 912    :    // Instrument this basic block.
 913    :    // Note that InitHooksRefs() is not needed for a dry run.
 914  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 915  E :    bb_transform.set_dry_run(true);
 916    :  
 917  E :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 918    :        basic_block_,
 919    :        AsanBasicBlockTransform::kSafeStackAccess,
 920  E :        BlockGraph::PE_IMAGE));
 921    :  
 922    :    // The instructions_happened() function should return false because we
 923    :    // had no instructions to instrument.
 924  E :    EXPECT_FALSE(bb_transform.instrumentation_happened());
 925    :  
 926    :    // The basic block should not be touched either.
 927  E :    ASSERT_EQ(basic_block_size, basic_block_->instructions().size());
 928  E :  }
 929    :  
 930  E :  TEST_F(AsanTransformTest, HotPatchingBBTransformInstrumentable) {
 931  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 932  E :    bb_transform.set_dry_run(true);
 933  E :    HotPatchingAsanBasicBlockTransform hp_bb_transform(&bb_transform);
 934    :  
 935    :    // Generate an instrumentable basic block.
 936  E :    bb_asm_->xchg(assm::eax, assm::ecx);
 937  E :    bb_asm_->mov(assm::eax, block_graph::Operand(assm::ebx));
 938    :  
 939    :    // Check subgraph before transformation.
 940  E :    EXPECT_EQ(2U, basic_block_->instructions().size());
 941  E :    ASSERT_EQ(1U, subgraph_.block_descriptions().size());
 942  E :    EXPECT_EQ(0U, subgraph_.block_descriptions().front().padding_before);
 943  E :    EXPECT_FALSE(hp_bb_transform.prepared_for_hot_patching());
 944    :  
 945    :    // Apply the Asan hot patching basic block transform.
 946  E :    ASSERT_TRUE(hp_bb_transform.TransformBasicBlockSubGraph(
 947  E :        &pe_policy_, &block_graph_, &subgraph_));
 948    :  
 949    :    // Padding should be added in the block description. Also, as the code block
 950    :    // began with a 1-byte instruction, a 2-byte NOP should be prepended.
 951  E :    EXPECT_EQ(3U, basic_block_->instructions().size());
 952  E :    ASSERT_EQ(1U, subgraph_.block_descriptions().size());
 953  E :    EXPECT_EQ(5U, subgraph_.block_descriptions().front().padding_before);
 954  E :    EXPECT_TRUE(hp_bb_transform.prepared_for_hot_patching());
 955  E :  }
 956    :  
 957  E :  TEST_F(AsanTransformTest, HotPatchingBBTransformNonInstrumentable) {
 958  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 959  E :    bb_transform.set_dry_run(true);
 960  E :    HotPatchingAsanBasicBlockTransform hp_bb_transform(&bb_transform);
 961    :  
 962    :    // Generate a non-instrumentable instruction.
 963  E :    bb_asm_->xchg(assm::eax, assm::ecx);
 964    :  
 965    :    // Check subgraph before transformation.
 966  E :    EXPECT_EQ(1U, basic_block_->instructions().size());
 967  E :    ASSERT_EQ(1U, subgraph_.block_descriptions().size());
 968  E :    EXPECT_EQ(0U, subgraph_.block_descriptions().front().padding_before);
 969  E :    EXPECT_FALSE(hp_bb_transform.prepared_for_hot_patching());
 970    :  
 971    :    // Apply the Asan hot patching basic block transform.
 972  E :    ASSERT_TRUE(hp_bb_transform.TransformBasicBlockSubGraph(
 973  E :        &pe_policy_, &block_graph_, &subgraph_));
 974    :  
 975    :    // The subgraph should stay the same.
 976  E :    EXPECT_EQ(1U, basic_block_->instructions().size());
 977  E :    ASSERT_EQ(1U, subgraph_.block_descriptions().size());
 978  E :    EXPECT_EQ(0U, subgraph_.block_descriptions().front().padding_before);
 979  E :    EXPECT_FALSE(hp_bb_transform.prepared_for_hot_patching());
 980  E :  }
 981    :  
 982    :  namespace {
 983    :  
 984    :  using base::win::PEImage;
 985    :  typedef std::set<std::string> StringSet;
 986    :  typedef std::set<void*> FunctionsIATAddressSet;
 987    :  typedef std::vector<std::string> StringVector;
 988    :  
 989  E :  void Intersect(const StringSet& ss1, const StringSet& ss2, StringSet* ss3) {
 990  E :    ASSERT_TRUE(ss3 != NULL);
 991  E :    ss3->clear();
 992  E :    std::set_intersection(ss1.begin(), ss1.end(),
 993    :                          ss2.begin(), ss2.end(),
 994    :                          std::inserter(*ss3, ss3->begin()));
 995  E :  }
 996    :  
 997    :  bool EnumKernel32HeapImports(const PEImage &image,
 998    :                               const char* module,
 999    :                               unsigned long ordinal,
1000    :                               const char* name,
1001    :                               unsigned long hint,
1002    :                               PIMAGE_THUNK_DATA iat,
1003  E :                               void* cookie) {
1004  E :    EXPECT_NE(static_cast<const char*>(NULL), module);
1005  E :    EXPECT_NE(static_cast<void*>(NULL), cookie);
1006    :  
1007  E :    StringVector* modules = reinterpret_cast<StringVector*>(cookie);
1008    :  
1009  E :    if (_stricmp("kernel32.dll", module) == 0 && strncmp("Heap", name, 4) == 0) {
1010  E :      EXPECT_NE(static_cast<const char*>(NULL), name);
1011  E :      modules->push_back(name);
1012    :    }
1013    :  
1014  E :    return true;
1015  E :  }
1016    :  
1017    :  bool EnumKernel32InterceptedFunctionsImports(const PEImage &image,
1018    :                                               const char* module,
1019    :                                               unsigned long ordinal,
1020    :                                               const char* name,
1021    :                                               unsigned long hint,
1022    :                                               PIMAGE_THUNK_DATA iat,
1023  E :                                               void* cookie) {
1024  E :    EXPECT_NE(static_cast<const char*>(NULL), module);
1025  E :    EXPECT_NE(static_cast<void*>(NULL), cookie);
1026    :  
1027  E :    StringVector* modules = reinterpret_cast<StringVector*>(cookie);
1028    :    static const char* kInterceptedFunctions[] = {
1029    :      "ReadFile",
1030    :      "WriteFile",
1031    :    };
1032    :  
1033  E :    if (_stricmp("kernel32.dll", module) == 0) {
1034  E :      for (size_t i = 0; i < arraysize(kInterceptedFunctions); ++i) {
1035  E :        if (base::CompareCaseInsensitiveASCII(kInterceptedFunctions[i], name) ==
1036    :            0) {
1037  E :          EXPECT_NE(static_cast<const char*>(NULL), name);
1038  E :          modules->push_back(name);
1039  E :          return true;
1040    :        }
1041  E :      }
1042    :    }
1043    :  
1044  E :    return true;
1045  E :  }
1046    :  
1047    :  // A struct used to pass parameters in the cookie of EnumAsanImports
1048    :  struct EnumAsanImportsParams {
1049    :    const char* imported_module_name;
1050    :    StringSet* imports;
1051    :  };
1052    :  
1053    :  bool EnumAsanImports(const PEImage &image,
1054    :                       const char* module,
1055    :                       unsigned long ordinal,
1056    :                       const char* name,
1057    :                       unsigned long hint,
1058    :                       PIMAGE_THUNK_DATA iat,
1059  E :                       void* cookie) {
1060  E :    EXPECT_NE(static_cast<const char*>(NULL), module);
1061  E :    EXPECT_NE(static_cast<void*>(NULL), cookie);
1062    :  
1063    :    EnumAsanImportsParams* params =
1064  E :        reinterpret_cast<EnumAsanImportsParams*>(cookie);
1065    :  
1066  E :    if (strcmp(params->imported_module_name, module) == 0) {
1067  E :      EXPECT_NE(static_cast<const char*>(NULL), name);
1068  E :      params->imports->insert(name);
1069    :    }
1070    :  
1071  E :    return true;
1072  E :  }
1073    :  
1074    :  bool GetAsanHooksIATEntries(const PEImage &image,
1075    :                              const char* module,
1076    :                              unsigned long ordinal,
1077    :                              const char* name,
1078    :                              unsigned long hint,
1079    :                              PIMAGE_THUNK_DATA iat,
1080  E :                              void* cookie) {
1081  E :    EXPECT_NE(static_cast<const char*>(NULL), module);
1082  E :    EXPECT_NE(static_cast<void*>(NULL), cookie);
1083    :  
1084    :    FunctionsIATAddressSet* hooks_iat_entries =
1085  E :        reinterpret_cast<FunctionsIATAddressSet*>(cookie);
1086    :  
1087  E :    if (strcmp(AsanTransform::kSyzyAsanDll, module) != 0)
1088  E :      return true;
1089    :  
1090  E :    EXPECT_NE(static_cast<const char*>(NULL), name);
1091    :  
1092    :    // Ensures that the function is an asan_check_access hook.
1093  E :    if (base::StartsWith(name, "asan_check_", base::CompareCase::SENSITIVE))
1094  E :      hooks_iat_entries->insert(reinterpret_cast<PVOID>(iat->u1.Function));
1095    :  
1096  E :    return true;
1097  E :  }
1098    :  
1099    :  void CheckImportsAreRedirectedPe(
1100    :      const base::FilePath::StringType& library_path,
1101  E :      bool hot_patching) {
1102    :  
1103    :    // Load the transformed module without resolving its dependencies.
1104    :    base::NativeLibrary lib =
1105  E :        ::LoadLibraryEx(library_path.c_str(),
1106    :                        NULL,
1107    :                        DONT_RESOLVE_DLL_REFERENCES);
1108  E :    ASSERT_TRUE(lib != NULL);
1109    :    // Make sure it's unloaded on failure.
1110  E :    base::ScopedNativeLibrary lib_keeper(lib);
1111    :  
1112  E :    PEImage image(lib);
1113  E :    ASSERT_TRUE(image.VerifyMagic());
1114  E :    StringSet imports;
1115    :    EnumAsanImportsParams enum_asan_imports_params;
1116  E :    if (!hot_patching) {
1117  E :      enum_asan_imports_params.imported_module_name = AsanTransform::kSyzyAsanDll;
1118  E :    } else {
1119  E :      enum_asan_imports_params.imported_module_name =
1120    :          AsanTransform::kSyzyAsanHpDll;
1121    :    }
1122  E :    enum_asan_imports_params.imports = &imports;
1123  E :    ASSERT_TRUE(image.EnumAllImports(&EnumAsanImports,
1124  E :                                     &enum_asan_imports_params));
1125    :  
1126  E :    StringVector heap_imports;
1127  E :    ASSERT_TRUE(image.EnumAllImports(&EnumKernel32HeapImports, &heap_imports));
1128  E :    StringVector intercepted_functions_imports;
1129  E :    ASSERT_TRUE(image.EnumAllImports(&EnumKernel32InterceptedFunctionsImports,
1130  E :                                     &intercepted_functions_imports));
1131    :  
1132    :    // This isn't strictly speaking a full test, as we only check that the new
1133    :    // imports have been added. It's however more trouble than it's worth to
1134    :    // test this fully for now.
1135  E :    StringSet expected;
1136  E :    for (size_t i = 0; i < heap_imports.size(); ++i) {
1137  E :      std::string asan_import = "asan_";
1138  E :      asan_import.append(heap_imports[i]);
1139  E :      expected.insert(asan_import);
1140  E :    }
1141  E :    for (size_t i = 0; i < intercepted_functions_imports.size(); ++i) {
1142  E :      std::string asan_import = "asan_";
1143  E :      asan_import.append(intercepted_functions_imports[i]);
1144  E :      expected.insert(asan_import);
1145  E :    }
1146    :  
1147    :    // Imports that should be redirected should all have matching asan imports.
1148  E :    StringSet results;
1149  E :    Intersect(imports, expected, &results);
1150  E :    if (!hot_patching) {
1151  E :      EXPECT_EQ(expected, results);
1152  E :    } else {
1153    :      // These should not be present in hot patching mode.
1154  E :      EXPECT_TRUE(results.empty());
1155    :    }
1156    :  
1157    :    // Some instrumentation functions (but not necessarily all of them) should be
1158    :    // found, unless we are in hot patching mode.
1159  E :    expected.clear();
1160  E :    expected.insert("asan_check_1_byte_read_access");
1161  E :    expected.insert("asan_check_2_byte_read_access");
1162  E :    expected.insert("asan_check_4_byte_read_access");
1163  E :    expected.insert("asan_check_8_byte_read_access");
1164  E :    expected.insert("asan_check_10_byte_read_access");
1165  E :    expected.insert("asan_check_16_byte_read_access");
1166  E :    expected.insert("asan_check_32_byte_read_access");
1167  E :    expected.insert("asan_check_1_byte_write_access");
1168  E :    expected.insert("asan_check_2_byte_write_access");
1169  E :    expected.insert("asan_check_4_byte_write_access");
1170  E :    expected.insert("asan_check_8_byte_write_access");
1171  E :    expected.insert("asan_check_10_byte_write_access");
1172  E :    expected.insert("asan_check_16_byte_write_access");
1173  E :    expected.insert("asan_check_32_byte_write_access");
1174    :  
1175  E :    expected.insert("asan_check_1_byte_read_access_no_flags");
1176  E :    expected.insert("asan_check_2_byte_read_access_no_flags");
1177  E :    expected.insert("asan_check_4_byte_read_access_no_flags");
1178  E :    expected.insert("asan_check_8_byte_read_access_no_flags");
1179  E :    expected.insert("asan_check_10_byte_read_access_no_flags");
1180  E :    expected.insert("asan_check_16_byte_read_access_no_flags");
1181  E :    expected.insert("asan_check_32_byte_read_access_no_flags");
1182  E :    expected.insert("asan_check_1_byte_write_access_no_flags");
1183  E :    expected.insert("asan_check_2_byte_write_access_no_flags");
1184  E :    expected.insert("asan_check_4_byte_write_access_no_flags");
1185  E :    expected.insert("asan_check_8_byte_write_access_no_flags");
1186  E :    expected.insert("asan_check_10_byte_write_access_no_flags");
1187  E :    expected.insert("asan_check_16_byte_write_access_no_flags");
1188  E :    expected.insert("asan_check_32_byte_write_access_no_flags");
1189    :  
1190  E :    expected.insert("asan_check_repz_4_byte_cmps_access");
1191  E :    expected.insert("asan_check_repz_4_byte_movs_access");
1192  E :    expected.insert("asan_check_repz_4_byte_stos_access");
1193  E :    expected.insert("asan_check_repz_2_byte_cmps_access");
1194  E :    expected.insert("asan_check_repz_2_byte_movs_access");
1195  E :    expected.insert("asan_check_repz_2_byte_stos_access");
1196  E :    expected.insert("asan_check_repz_1_byte_cmps_access");
1197  E :    expected.insert("asan_check_repz_1_byte_movs_access");
1198  E :    expected.insert("asan_check_repz_1_byte_stos_access");
1199    :  
1200  E :    expected.insert("asan_check_4_byte_cmps_access");
1201  E :    expected.insert("asan_check_4_byte_movs_access");
1202  E :    expected.insert("asan_check_4_byte_stos_access");
1203  E :    expected.insert("asan_check_2_byte_cmps_access");
1204  E :    expected.insert("asan_check_2_byte_movs_access");
1205  E :    expected.insert("asan_check_2_byte_stos_access");
1206  E :    expected.insert("asan_check_1_byte_cmps_access");
1207  E :    expected.insert("asan_check_1_byte_movs_access");
1208  E :    expected.insert("asan_check_1_byte_stos_access");
1209    :  
1210    :    // We expect all of the instrumentation functions to have been added.
1211  E :    Intersect(imports, expected, &results);
1212  E :    if (!hot_patching) {
1213  E :      EXPECT_EQ(expected, results);
1214  E :    } else {
1215    :      // These should not be present in hot patching mode.
1216  E :      EXPECT_TRUE(results.empty());
1217    :    }
1218    :  
1219    :    // Hot patching mode uses a different prefix for static CRT intercepts.
1220  E :    std::string prefix = !hot_patching ? "asan_" : "hp_asan_";
1221    :  
1222    :    // We expect all of these statically linked CRT functions to be redirected.
1223  E :    expected.clear();
1224  E :    expected.insert(prefix + "memcpy");
1225  E :    expected.insert(prefix + "memmove");
1226  E :    expected.insert(prefix + "memset");
1227  E :    expected.insert(prefix + "memchr");
1228  E :    expected.insert(prefix + "strlen");
1229  E :    expected.insert(prefix + "strrchr");
1230  E :    expected.insert(prefix + "strncpy");
1231  E :    expected.insert(prefix + "strncat");
1232  E :    expected.insert(prefix + "wcsrchr");
1233  E :    expected.insert(prefix + "wcschr");
1234  E :    expected.insert(prefix + "wcsstr");
1235  E :    Intersect(imports, expected, &results);
1236  E :    EXPECT_FALSE(results.empty());
1237  E :    EXPECT_EQ(results, expected);
1238    :  
1239    :    // The implementation of the interceptors for these functions isn't available
1240    :    // so we don't expect them to be redirected.
1241  E :    StringSet not_expected;
1242  E :    not_expected.insert(prefix + "strcmp");
1243  E :    not_expected.insert(prefix + "strcspn");
1244  E :    not_expected.insert(prefix + "strspn");
1245  E :    not_expected.insert(prefix + "strstr");
1246  E :    not_expected.insert(prefix + "strpbrk");
1247  E :    Intersect(imports, not_expected, &results);
1248  E :    EXPECT_TRUE(results.empty());
1249  E :  }
1250    :  
1251    :  }  // namespace
1252    :  
1253  E :  TEST_F(AsanTransformTest, ImportsAreRedirectedPe) {
1254  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformToIntegrationTestDll());
1255    :  
1256  E :    CheckImportsAreRedirectedPe(relinked_path_.value(), false);
1257  E :  }
1258    :  
1259  E :  TEST_F(AsanTransformTest, ImportsAreRedirectedHpPe) {
1260  E :    asan_transform_.set_hot_patching(true);
1261  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformToIntegrationTestDll());
1262    :  
1263  E :    CheckImportsAreRedirectedPe(relinked_path_.value(), true);
1264  E :  }
1265    :  
1266    :  namespace {
1267    :  
1268    :  // Counts the number of references to the given COFF symbol.
1269    :  size_t CountCoffSymbolReferences(const BlockGraph::Block* symbols_block,
1270    :                                   const pe::CoffSymbolNameOffsetMap& symbol_map,
1271  E :                                   const base::StringPiece& name) {
1272  E :    EXPECT_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
1273    :  
1274    :    pe::CoffSymbolNameOffsetMap::const_iterator symbol_it =
1275  E :        symbol_map.find(name.as_string());
1276  E :    if (symbol_it == symbol_map.end())
1277  i :      return 0;
1278    :  
1279  E :    size_t ref_count = 0;
1280  E :    const pe::CoffSymbolOffsets& offsets = symbol_it->second;
1281    :    BlockGraph::Block::ReferrerSet::const_iterator ref_it =
1282  E :        symbols_block->referrers().begin();
1283  E :    for (; ref_it != symbols_block->referrers().end(); ++ref_it) {
1284  E :      BlockGraph::Reference ref;
1285  E :      CHECK(ref_it->first->GetReference(ref_it->second, &ref));
1286  E :      if (offsets.count(ref.offset()) > 0)
1287  E :        ++ref_count;
1288  E :    }
1289    :  
1290  E :    return ref_count;
1291  E :  }
1292    :  
1293    :  }  // namespace
1294    :  
1295  E :  TEST_F(AsanTransformTest, ImportsAreRedirectedCoff) {
1296  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDllObj());
1297    :  
1298    :    // TODO(chrisha): Modify this to use CoffTransformPolicy once it is
1299    :    //     working as intended.
1300  E :    testing::DummyTransformPolicy dummy_policy;
1301  E :    asan_transform_.use_interceptors_ = true;
1302  E :    asan_transform_.use_liveness_analysis_ = true;
1303  E :    ASSERT_TRUE(block_graph::ApplyBlockGraphTransform(
1304  E :        &asan_transform_, &dummy_policy, &block_graph_, header_block_));
1305    :  
1306  E :    BlockGraph::Block* symbols_block = NULL;
1307  E :    BlockGraph::Block* strings_block = NULL;
1308  E :    ASSERT_TRUE(pe::FindCoffSpecialBlocks(
1309  E :        &block_graph_, NULL, &symbols_block, &strings_block));
1310  E :    pe::CoffSymbolNameOffsetMap symbol_map;
1311  E :    ASSERT_TRUE(pe::BuildCoffSymbolNameOffsetMap(
1312  E :        symbols_block, strings_block, &symbol_map));
1313    :  
1314    :    // Convert the symbol map to a set of symbol names.
1315  E :    StringSet symbols;
1316  E :    pe::CoffSymbolNameOffsetMap::const_iterator map_it = symbol_map.begin();
1317  E :    for (; map_it != symbol_map.end(); ++map_it)
1318  E :      symbols.insert(map_it->first);
1319    :  
1320    :    // We expected the following check-access functions to have been
1321    :    // added.
1322  E :    StringSet expected;
1323  E :    expected.insert("_asan_check_1_byte_read_access");
1324  E :    expected.insert("_asan_check_2_byte_read_access");
1325  E :    expected.insert("_asan_check_4_byte_read_access");
1326  E :    expected.insert("_asan_check_8_byte_read_access");
1327  E :    expected.insert("_asan_check_10_byte_read_access");
1328  E :    expected.insert("_asan_check_16_byte_read_access");
1329  E :    expected.insert("_asan_check_32_byte_read_access");
1330  E :    expected.insert("_asan_check_1_byte_write_access");
1331  E :    expected.insert("_asan_check_2_byte_write_access");
1332  E :    expected.insert("_asan_check_4_byte_write_access");
1333  E :    expected.insert("_asan_check_8_byte_write_access");
1334  E :    expected.insert("_asan_check_10_byte_write_access");
1335  E :    expected.insert("_asan_check_16_byte_write_access");
1336  E :    expected.insert("_asan_check_32_byte_write_access");
1337    :  
1338  E :    expected.insert("_asan_check_1_byte_read_access_no_flags");
1339  E :    expected.insert("_asan_check_2_byte_read_access_no_flags");
1340  E :    expected.insert("_asan_check_4_byte_read_access_no_flags");
1341  E :    expected.insert("_asan_check_8_byte_read_access_no_flags");
1342  E :    expected.insert("_asan_check_10_byte_read_access_no_flags");
1343  E :    expected.insert("_asan_check_16_byte_read_access_no_flags");
1344  E :    expected.insert("_asan_check_32_byte_read_access_no_flags");
1345  E :    expected.insert("_asan_check_1_byte_write_access_no_flags");
1346  E :    expected.insert("_asan_check_2_byte_write_access_no_flags");
1347  E :    expected.insert("_asan_check_4_byte_write_access_no_flags");
1348  E :    expected.insert("_asan_check_8_byte_write_access_no_flags");
1349  E :    expected.insert("_asan_check_10_byte_write_access_no_flags");
1350  E :    expected.insert("_asan_check_16_byte_write_access_no_flags");
1351  E :    expected.insert("_asan_check_32_byte_write_access_no_flags");
1352    :  
1353  E :    expected.insert("_asan_check_repz_4_byte_cmps_access");
1354  E :    expected.insert("_asan_check_repz_4_byte_movs_access");
1355  E :    expected.insert("_asan_check_repz_4_byte_stos_access");
1356  E :    expected.insert("_asan_check_repz_2_byte_cmps_access");
1357  E :    expected.insert("_asan_check_repz_2_byte_movs_access");
1358  E :    expected.insert("_asan_check_repz_2_byte_stos_access");
1359  E :    expected.insert("_asan_check_repz_1_byte_cmps_access");
1360  E :    expected.insert("_asan_check_repz_1_byte_movs_access");
1361  E :    expected.insert("_asan_check_repz_1_byte_stos_access");
1362    :  
1363  E :    expected.insert("_asan_check_4_byte_cmps_access");
1364  E :    expected.insert("_asan_check_4_byte_movs_access");
1365  E :    expected.insert("_asan_check_4_byte_stos_access");
1366  E :    expected.insert("_asan_check_2_byte_cmps_access");
1367  E :    expected.insert("_asan_check_2_byte_movs_access");
1368  E :    expected.insert("_asan_check_2_byte_stos_access");
1369  E :    expected.insert("_asan_check_1_byte_cmps_access");
1370  E :    expected.insert("_asan_check_1_byte_movs_access");
1371  E :    expected.insert("_asan_check_1_byte_stos_access");
1372    :  
1373  E :    StringSet results;
1374  E :    Intersect(symbols, expected, &results);
1375  E :    EXPECT_THAT(results, ContainerEq(expected));
1376    :  
1377    :    // Expect at least some of the Asan instrumentation symbols to be referenced.
1378  E :    size_t instrumentation_references = 0;
1379  E :    StringSet::const_iterator str_it = expected.begin();
1380  E :    for (; str_it != expected.end(); ++str_it) {
1381  E :      instrumentation_references += CountCoffSymbolReferences(
1382    :            symbols_block, symbol_map, *str_it);
1383  E :    }
1384  E :    EXPECT_LT(0u, instrumentation_references);
1385    :  
1386    :    // Expect any intercepted symbols to have no references to them if they
1387    :    // are present, and expect an equivalent Asan instrumented symbol to exist
1388    :    // and be referenced.
1389  E :    const AsanIntercept* intercept = kAsanIntercepts;
1390  E :    for (; intercept->undecorated_name != NULL; ++intercept) {
1391  E :      if (intercept->decorated_name == NULL)
1392  E :        continue;
1393    :  
1394  E :      std::string name(intercept->decorated_name);
1395    :  
1396    :      // Build the name of the imported version of this symbol.
1397  E :      std::string imp_name(kDecoratedImportPrefix);
1398  E :      imp_name += name;
1399    :  
1400    :      // Build the name of the Asan instrumented version of this symbol.
1401  E :      std::string asan_name(kDecoratedAsanInterceptPrefix);
1402  E :      asan_name += name;
1403    :  
1404    :      // Build the name of the Asan instrumented imported version of this symbol.
1405  E :      std::string imp_asan_name(kDecoratedImportPrefix);
1406  E :      imp_asan_name += name;
1407    :  
1408  E :      bool has_name = symbols.count(name) > 0;
1409  E :      bool has_imp_name = symbols.count(imp_name) > 0;
1410  E :      bool has_asan_name = symbols.count(asan_name) > 0;
1411  E :      bool has_imp_asan_name = symbols.count(imp_asan_name) > 0;
1412    :  
1413  E :      size_t name_refs = 0;
1414  E :      if (has_name) {
1415  E :        name_refs = CountCoffSymbolReferences(
1416    :            symbols_block, symbol_map, name);
1417    :      }
1418    :  
1419  E :      size_t imp_name_refs = 0;
1420  E :      if (has_imp_name) {
1421  i :        imp_name_refs = CountCoffSymbolReferences(
1422    :            symbols_block, symbol_map, imp_name);
1423    :      }
1424    :  
1425  E :      size_t asan_name_refs = 0;
1426  E :      if (has_asan_name) {
1427  E :        asan_name_refs = CountCoffSymbolReferences(
1428    :            symbols_block, symbol_map, asan_name);
1429    :      }
1430    :  
1431  E :      size_t imp_asan_name_refs = 0;
1432  E :      if (has_imp_asan_name) {
1433  i :        imp_asan_name_refs = CountCoffSymbolReferences(
1434    :            symbols_block, symbol_map, imp_asan_name);
1435    :      }
1436    :  
1437    :      // If the original symbol is present we expect the Asan version to be
1438    :      // present as well. The converse it not necessarily true, as the symbol
1439    :      // can be reused in place by the transform in some cases. We also expect
1440    :      // them to have no references (having been redirected to the Asan
1441    :      // equivalents).
1442  E :      if (has_name) {
1443  E :        EXPECT_TRUE(has_asan_name);
1444  E :        EXPECT_EQ(0u, name_refs);
1445    :      }
1446  E :      if (has_imp_name) {
1447  i :        EXPECT_TRUE(has_imp_asan_name);
1448  i :        EXPECT_EQ(0u, imp_name_refs);
1449    :      }
1450    :  
1451    :      // If the Asan versions of the symbols are present we expect them to
1452    :      // have references.
1453  E :      if (has_asan_name) {
1454  E :        EXPECT_LT(0u, asan_name_refs);
1455    :      }
1456  E :      if (has_imp_asan_name) {
1457  i :        EXPECT_LT(0u, imp_asan_name_refs);
1458    :      }
1459  E :    }
1460  E :  }
1461    :  
1462  E :  TEST_F(AsanTransformTest, AsanHooksAreStubbed) {
1463  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformToIntegrationTestDll());
1464    :  
1465    :    // Load the transformed module without resolving its dependencies.
1466    :    base::NativeLibrary lib =
1467  E :        ::LoadLibraryEx(relinked_path_.value().c_str(),
1468    :                        NULL,
1469    :                        DONT_RESOLVE_DLL_REFERENCES);
1470  E :    ASSERT_TRUE(lib != NULL);
1471    :    // Make sure it's unloaded on failure.
1472  E :    base::ScopedNativeLibrary lib_keeper(lib);
1473    :  
1474  E :    PEImage image(lib);
1475  E :    ASSERT_TRUE(image.VerifyMagic());
1476    :  
1477    :    // Iterate over the image import descriptors. We want to make sure the
1478    :    // one for syzyasan_rtl.dll is bound.
1479  E :    DWORD size = image.GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT);
1480  E :    PIMAGE_IMPORT_DESCRIPTOR iid = image.GetFirstImportChunk();
1481  E :    ASSERT_TRUE(iid != NULL);
1482  E :    ASSERT_GE(size, sizeof(IMAGE_IMPORT_DESCRIPTOR));
1483  E :    for (; iid->FirstThunk; ++iid) {
1484  E :      std::string module_name(reinterpret_cast<LPCSTR>(
1485    :          image.RVAToAddr(iid->Name)));
1486  E :      if (module_name == AsanTransform::kSyzyAsanDll)
1487  E :        ASSERT_NE(0u, iid->TimeDateStamp);
1488  E :    }
1489    :  
1490    :    // As all the hooks may refer to only two kinds of stubs, we expect to have
1491    :    // exactly two entries in the set.
1492  E :    FunctionsIATAddressSet hooks_iat_set;
1493  E :    ASSERT_TRUE(image.EnumAllImports(&GetAsanHooksIATEntries, &hooks_iat_set));
1494  E :    ASSERT_EQ(hooks_iat_set.size(), 2U);
1495    :  
1496    :    // Ensures that all stubs are in the thunks section.
1497  E :    FunctionsIATAddressSet::iterator hook = hooks_iat_set.begin();
1498  E :    for (; hook != hooks_iat_set.end(); ++hook) {
1499  E :      PVOID stub_address = *hook;
1500    :      PIMAGE_SECTION_HEADER stub_sec =
1501  E :          image.GetImageSectionFromAddr(stub_address);
1502  E :      ASSERT_STREQ(common::kThunkSectionName,
1503  E :                   reinterpret_cast<const char*>(stub_sec->Name));
1504  E :    }
1505  E :  }
1506    :  
1507  E :  TEST_F(AsanTransformTest, PeInterceptFunctions) {
1508  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
1509    :  
1510    :    BlockGraph::Block* b1 =
1511  E :        block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 0x20, "testAsan_b1");
1512    :    BlockGraph::Block* b2 =
1513  E :        block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 0x20, "testAsan_b2");
1514    :    BlockGraph::Block* b3 =
1515  E :        block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 0x20, "testAsan_b3");
1516  E :    ASSERT_TRUE(b1 != NULL);
1517  E :    ASSERT_TRUE(b2 != NULL);
1518  E :    ASSERT_TRUE(b3 != NULL);
1519    :  
1520  E :    ASSERT_TRUE(b1->references().empty());
1521  E :    ASSERT_TRUE(b1->referrers().empty());
1522  E :    ASSERT_TRUE(b2->references().empty());
1523  E :    ASSERT_TRUE(b2->referrers().empty());
1524  E :    ASSERT_TRUE(b3->references().empty());
1525  E :    ASSERT_TRUE(b3->referrers().empty());
1526    :  
1527    :    // Add a reference from b2 to b1 and from b3 to b1.
1528  E :    BlockGraph::Reference ref_b2_b1(BlockGraph::PC_RELATIVE_REF, 1, b1, 0, 0);
1529  E :    BlockGraph::Reference ref_b3_b1(BlockGraph::PC_RELATIVE_REF, 1, b1, 1, 1);
1530  E :    ASSERT_TRUE(b2->SetReference(0, ref_b2_b1));
1531  E :    ASSERT_TRUE(b3->SetReference(1, ref_b3_b1));
1532    :  
1533  E :    EXPECT_EQ(2U, b1->referrers().size());
1534    :  
1535  E :    size_t num_blocks_pre_transform = block_graph_.blocks().size();
1536  E :    size_t num_sections_pre_transform = block_graph_.sections().size();
1537    :  
1538    :    // Get the block hash.
1539  E :    block_graph::BlockHash b1_hash(b1);
1540  E :    std::string b1_hash_str = base::MD5DigestToBase16(b1_hash.md5_digest);
1541  E :    MD5Hash b1_hashes[2] = {};
1542  E :    strncpy(b1_hashes[0].hash, b1_hash_str.c_str(), sizeof(b1_hashes[0].hash));
1543    :  
1544    :    AsanIntercept b1_intercepts[] = {
1545  E :      { "testAsan_b1", "_testAsan_b1", "foo.dll", b1_hashes, true },
1546  E :      { NULL },
1547    :    };
1548    :  
1549    :    // Find statically linked functions.
1550  E :    asan_transform_.use_interceptors_ = true;
1551  E :    asan_transform_.PeFindStaticallyLinkedFunctionsToIntercept(b1_intercepts,
1552    :                                                               &block_graph_);
1553    :  
1554  E :    ASSERT_EQ(1U, asan_transform_.static_intercepted_blocks_.size());
1555  E :    EXPECT_EQ(b1, *(asan_transform_.static_intercepted_blocks_.begin()));
1556    :  
1557    :    // Intercept all calls to b1.
1558  E :    EXPECT_TRUE(asan_transform_.PeInterceptFunctions(b1_intercepts,
1559    :                                                     policy_,
1560    :                                                     &block_graph_,
1561  E :                                                     header_block_));
1562    :  
1563    :    // The block graph should have grown by 3 blocks:
1564    :    //     - the Import Address Table (IAT),
1565    :    //     - the Import Name Table (INT),
1566    :    //     - the thunk.
1567  E :    EXPECT_EQ(num_blocks_pre_transform + 3, block_graph_.blocks().size());
1568    :  
1569    :    // The .thunks section should have been added.
1570  E :    EXPECT_EQ(num_sections_pre_transform + 1, block_graph_.sections().size());
1571    :  
1572  E :    BlockGraph::Section* thunk_section = block_graph_.FindSection(
1573    :        common::kThunkSectionName);
1574  E :    ASSERT_TRUE(thunk_section != NULL);
1575    :  
1576  E :    const BlockGraph::Block* block_in_thunk_section = NULL;
1577    :    BlockGraph::BlockMap::const_iterator iter_blocks =
1578  E :        block_graph_.blocks().begin();
1579  E :    for (; iter_blocks != block_graph_.blocks().end(); ++iter_blocks) {
1580  E :      if (iter_blocks->second.section() == thunk_section->id()) {
1581    :        // There should be only one block in the thunk section.
1582  E :        EXPECT_TRUE(block_in_thunk_section == NULL);
1583  E :        block_in_thunk_section = &iter_blocks->second;
1584    :      }
1585  E :    }
1586    :  
1587    :    // Only the entry in the IAT should refer to b1.
1588  E :    EXPECT_EQ(1U, b1->referrers().size());
1589  E :  }
1590    :  
1591  E :  TEST_F(AsanTransformTest, CoffInterceptFunctions) {
1592  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDllObj());
1593    :  
1594  E :    size_t num_blocks_pre_transform = block_graph_.blocks().size();
1595  E :    size_t num_sections_pre_transform = block_graph_.sections().size();
1596    :  
1597    :    AsanIntercept intercepts[] = {
1598  E :      { "function2", "?function2@@YAHXZ", "", NULL, true },
1599  E :      { NULL },
1600    :    };
1601    :  
1602    :    // Intercept all calls to b1.
1603  E :    asan_transform_.use_interceptors_ = true;
1604  E :    EXPECT_TRUE(asan_transform_.CoffInterceptFunctions(intercepts,
1605    :                                                       policy_,
1606    :                                                       &block_graph_,
1607  E :                                                       header_block_));
1608    :  
1609    :    // The block graph should not have grown at all, as no thunks are necessary
1610    :    // in the COFF instrumentation mode.
1611  E :    EXPECT_EQ(num_blocks_pre_transform, block_graph_.blocks().size());
1612    :  
1613    :    // No sections should have been added.
1614  E :    EXPECT_EQ(num_sections_pre_transform, block_graph_.sections().size());
1615  E :  }
1616    :  
1617    :  namespace {
1618    :  
1619  E :  void GetImageSizeSubsampledInstrumentation(double rate, size_t* size) {
1620  E :    ASSERT_LE(0.0, rate);
1621  E :    ASSERT_GE(1.0, rate);
1622  E :    ASSERT_TRUE(size != NULL);
1623    :  
1624  E :    base::FilePath test_dll_path = ::testing::GetOutputRelativePath(
1625    :        testing::kTestDllName);
1626    :  
1627  E :    pe::PEFile pe_file;
1628  E :    ASSERT_TRUE(pe_file.Init(test_dll_path));
1629    :  
1630  E :    BlockGraph block_graph;
1631  E :    pe::ImageLayout layout(&block_graph);
1632  E :    pe::Decomposer decomposer(pe_file);
1633  E :    ASSERT_TRUE(decomposer.Decompose(&layout));
1634    :  
1635  E :    BlockGraph::Block* header_block = layout.blocks.GetBlockByAddress(
1636    :        core::RelativeAddress(0));
1637  E :    ASSERT_TRUE(header_block != NULL);
1638    :  
1639  E :    AsanTransform tx;
1640  E :    tx.set_instrumentation_rate(rate);
1641    :  
1642  E :    pe::PETransformPolicy policy;
1643  E :    ASSERT_TRUE(tx.TransformBlockGraph(&policy, &block_graph, header_block));
1644    :  
1645  E :    *size = 0;
1646  E :    BlockGraph::BlockMap::const_iterator block_it = block_graph.blocks().begin();
1647  E :    for (; block_it != block_graph.blocks().end(); ++block_it) {
1648  E :      *size += block_it->second.size();
1649  E :    }
1650  E :  }
1651    :  
1652    :  }  // namespace
1653    :  
1654  E :  TEST_F(AsanTransformTest, SubsampledInstrumentationTestDll) {
1655  E :    size_t rate0 = 0;
1656  E :    ASSERT_NO_FATAL_FAILURE(GetImageSizeSubsampledInstrumentation(0.0, &rate0));
1657    :  
1658  E :    size_t rate50 = 0;
1659  E :    ASSERT_NO_FATAL_FAILURE(GetImageSizeSubsampledInstrumentation(0.5, &rate50));
1660    :  
1661  E :    size_t rate100 = 0;
1662  E :    ASSERT_NO_FATAL_FAILURE(GetImageSizeSubsampledInstrumentation(1.0, &rate100));
1663    :  
1664  E :    size_t size100 = rate100 - rate0;
1665  E :    size_t size50 = rate50 - rate0;
1666    :  
1667    :    // This could theoretically fail, but that would imply an extremely bad
1668    :    // implementation of the underlying random number generator. There are about
1669    :    // 1850 instructions being instrumented. Since this is effectively a fair
1670    :    // coin toss we expect a standard deviation of 0.5 * sqrt(1850) = 22
1671    :    // instructions. A 10% margin is 185 / 22 = 8.4 standard deviations. For
1672    :    // |z| > 8.4, the p-value is 4.5e-17, or 17 nines of confidence. That should
1673    :    // keep any flake largely at bay. Thus, if this fails it's pretty much certain
1674    :    // the implementation is at fault.
1675  E :    EXPECT_LE(40 * size100 / 100, size50);
1676  E :    EXPECT_GE(60 * size100 / 100, size50);
1677  E :  }
1678    :  
1679  E :  TEST_F(AsanTransformTest, PeInjectAsanParametersNoStackIds) {
1680  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
1681    :  
1682  E :    common::InflatedAsanParameters params;
1683  E :    asan_transform_.set_asan_parameters(&params);
1684  E :    EXPECT_TRUE(asan_transform_.PeInjectAsanParameters(
1685  E :        policy_, &block_graph_, header_block_));
1686    :  
1687    :    // There should be a block containing parameters with the appropriate size.
1688  E :    ASSERT_TRUE(asan_transform_.asan_parameters_block_ != NULL);
1689  E :    EXPECT_EQ(sizeof(common::AsanParameters),
1690  E :              asan_transform_.asan_parameters_block_->size());
1691    :  
1692    :    // The block should contain no references.
1693  E :    EXPECT_TRUE(asan_transform_.asan_parameters_block_->references().empty());
1694    :  
1695    :    // The block should not be referred to at all.
1696  E :    EXPECT_TRUE(asan_transform_.asan_parameters_block_->referrers().empty());
1697  E :  }
1698    :  
1699  E :  TEST_F(AsanTransformTest, PeInjectAsanParametersStackIds) {
1700  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
1701    :  
1702  E :    common::InflatedAsanParameters params;
1703  E :    params.ignored_stack_ids_set.insert(0xDEADBEEF);
1704    :  
1705  E :    asan_transform_.set_asan_parameters(&params);
1706  E :    EXPECT_TRUE(asan_transform_.PeInjectAsanParameters(
1707  E :        policy_, &block_graph_, header_block_));
1708    :  
1709    :    // There should be a block containing parameters with the appropriate size.
1710  E :    ASSERT_TRUE(asan_transform_.asan_parameters_block_ != NULL);
1711  E :    EXPECT_EQ(sizeof(common::AsanParameters) + 2 * sizeof(common::AsanStackId),
1712  E :              asan_transform_.asan_parameters_block_->size());
1713    :  
1714    :    // The block should contain one reference to itself, from and to the
1715    :    // appropriate place.
1716  E :    EXPECT_EQ(1u, asan_transform_.asan_parameters_block_->references().size());
1717  E :    BlockGraph::Reference ignored_stack_ids_ref(
1718    :        BlockGraph::ABSOLUTE_REF,
1719    :        BlockGraph::Reference::kMaximumSize,
1720    :        asan_transform_.asan_parameters_block_,
1721    :        sizeof(common::AsanParameters),
1722    :        sizeof(common::AsanParameters));
1723    :    BlockGraph::Block::ReferenceMap::const_iterator ignored_stack_ids_ref_it =
1724  E :        asan_transform_.asan_parameters_block_->references().begin();
1725  E :    EXPECT_EQ(offsetof(common::AsanParameters, ignored_stack_ids),
1726  E :              ignored_stack_ids_ref_it->first);
1727  E :    EXPECT_EQ(ignored_stack_ids_ref, ignored_stack_ids_ref_it->second);
1728    :  
1729    :    // The block should only be referred to by itself.
1730  E :    EXPECT_EQ(1u, asan_transform_.asan_parameters_block_->referrers().size());
1731  E :  }
1732    :  
1733  E :  TEST_F(AsanTransformTest, FindHeapInitAndCrtHeapBlocks) {
1734  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
1735    :  
1736  E :    asan_transform_.FindHeapInitAndCrtHeapBlocks(&block_graph_);
1737    :  
1738  E :    ASSERT_FALSE(asan_transform_.heap_init_blocks_.empty());
1739  E :    for (const auto& iter : asan_transform_.heap_init_blocks_)
1740  E :      EXPECT_NE(std::string::npos, iter->name().find("_acrt_initialize_heap"));
1741  E :  }
1742    :  
1743  E :  TEST_F(AsanTransformTest, ShouldSkipBlock) {
1744  E :    testing::DummyTransformPolicy policy;
1745    :  
1746    :    BlockGraph::Block* b1 =
1747  E :        block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 0x20, "testAsan_b1");
1748    :    BlockGraph::Block* b2 =
1749  E :        block_graph_.AddBlock(BlockGraph::DATA_BLOCK, 0x20, "testAsan_b2");
1750  E :    ASSERT_TRUE(b1 != NULL);
1751  E :    ASSERT_TRUE(b2 != NULL);
1752    :  
1753    :    // A code block should not be skipped according to the dummy policy.
1754  E :    EXPECT_FALSE(asan_transform_.ShouldSkipBlock(&policy, b1));
1755    :  
1756    :    // _heap_init block should be skipped.
1757  E :    asan_transform_.heap_init_blocks_.push_back(b1);
1758  E :    EXPECT_TRUE(asan_transform_.ShouldSkipBlock(&policy, b1));
1759  E :    asan_transform_.heap_init_blocks_.clear();
1760  E :    EXPECT_FALSE(asan_transform_.ShouldSkipBlock(&policy, b1));
1761    :  
1762    :    // A block in static_intercepted_blocks_ should be skipped.
1763  E :    asan_transform_.static_intercepted_blocks_.insert(b1);
1764  E :    EXPECT_TRUE(asan_transform_.ShouldSkipBlock(&policy, b1));
1765  E :    asan_transform_.static_intercepted_blocks_.erase(b1);
1766  E :    EXPECT_FALSE(asan_transform_.ShouldSkipBlock(&policy, b1));
1767    :  
1768    :    // A data block should be skipped according to the dummy policy.
1769  E :    EXPECT_TRUE(asan_transform_.ShouldSkipBlock(&policy, b2));
1770  E :  }
1771    :  
1772  E :  TEST_F(AsanTransformTest, PatchCRTHeapInitialization) {
1773  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
1774    :  
1775    :    // Keep a reference to all the heap initialization blocks that should be
1776    :    // patched.
1777    :  
1778    :    std::map<const BlockGraph::Block*,
1779    :             std::pair<BlockGraph::Offset, BlockGraph::Reference>>
1780  E :        heap_init_blocks;
1781    :  
1782  E :    pe::transforms::ImportedModule kernel32("kernel32.dll");
1783  E :    pe::transforms::PEAddImportsTransform kernel32_transform;
1784    :  
1785  E :    size_t get_process_heap_idx = kernel32.AddSymbol(
1786    :        "GetProcessHeap", pe::transforms::ImportedModule::kFindOnly);
1787  E :    kernel32_transform.AddModule(&kernel32);
1788    :  
1789  E :    EXPECT_TRUE(block_graph::ApplyBlockGraphTransform(&kernel32_transform,
1790    :                                                      policy_,
1791    :                                                      &block_graph_,
1792  E :                                                      header_block_));
1793  E :    BlockGraph::Reference get_process_heap_ref;
1794  E :    EXPECT_TRUE(kernel32.GetSymbolReference(get_process_heap_idx,
1795  E :        &get_process_heap_ref));
1796    :  
1797  E :    for (const auto& iter : block_graph_.blocks()) {
1798  E :      if (iter.second.name().find("_acrt_initialize_heap") == std::string::npos)
1799  E :        continue;
1800  E :      for (const auto& ref : iter.second.references()) {
1801  E :        if (ref.second == get_process_heap_ref)
1802  E :          heap_init_blocks[&iter.second] = ref;
1803  E :      }
1804  E :    }
1805  E :    EXPECT_FALSE(heap_init_blocks.empty());
1806    :  
1807    :    // Apply the Asan transform.
1808  E :    asan_transform_.use_interceptors_ = true;
1809  E :    asan_transform_.use_liveness_analysis_ = true;
1810  E :    ASSERT_TRUE(block_graph::ApplyBlockGraphTransform(
1811  E :        &asan_transform_, &pe_policy_, &block_graph_, header_block_));
1812    :  
1813    :    // Get a referenece to the heap create function that has been used to patch
1814    :    // these blocks.
1815  E :    pe::transforms::ImportedModule asan_module(
1816    :        AsanTransform::kSyzyAsanDll);
1817  E :    pe::transforms::PEAddImportsTransform asan_import_transform;
1818  E :    size_t asan_heap_create_idx = asan_module.AddSymbol(
1819    :        "asan_HeapCreate", pe::transforms::ImportedModule::kFindOnly);
1820  E :    asan_import_transform.AddModule(&asan_module);
1821  E :    EXPECT_TRUE(block_graph::ApplyBlockGraphTransform(&asan_import_transform,
1822    :                                                      policy_,
1823    :                                                      &block_graph_,
1824  E :                                                      header_block_));
1825  E :    BlockGraph::Reference asan_heap_create_ref;
1826  E :    EXPECT_TRUE(asan_module.GetSymbolReference(asan_heap_create_idx,
1827  E :                                               &asan_heap_create_ref));
1828    :  
1829    :    // Verify that the patched blocks contains a reference to this heap create
1830    :    // function.
1831  E :    for (const auto& iter : heap_init_blocks) {
1832  E :      const BlockGraph::Block* block = iter.first;
1833  E :      BlockGraph::Offset offset = iter.second.first;
1834    :  
1835    :      // The blocks should contain a reference to a data block in the Syzygy thunk
1836    :      // section.
1837  E :      BlockGraph::Reference thunk_data_ref;
1838  E :      EXPECT_TRUE(block->GetReference(offset, &thunk_data_ref));
1839    :      BlockGraph::SectionId syzygy_section =
1840  E :          block_graph_.FindSection(common::kThunkSectionName)->id();
1841  E :      EXPECT_EQ(syzygy_section, thunk_data_ref.referenced()->section());
1842  E :      EXPECT_EQ(BlockGraph::DATA_BLOCK, thunk_data_ref.referenced()->type());
1843  E :      EXPECT_EQ(1, thunk_data_ref.referenced()->references().size());
1844    :  
1845    :      // This data block should refer to a code block also in the Syzygy thunk
1846    :      // section.
1847  E :      BlockGraph::Reference thunk_code_ref;
1848  E :      EXPECT_TRUE(thunk_data_ref.referenced()->GetReference(0,
1849    :                                                            &thunk_code_ref));
1850  E :      EXPECT_EQ(syzygy_section, thunk_code_ref.referenced()->section());
1851  E :      EXPECT_EQ(BlockGraph::CODE_BLOCK, thunk_code_ref.referenced()->type());
1852  E :      EXPECT_EQ(1, thunk_code_ref.referenced()->references().size());
1853    :  
1854    :      // And lastly, this code block should refer to the HeapCreate function.
1855  E :      BlockGraph::Reference thunk_heap_create_ref;
1856    :      BlockGraph::Offset ref_idx =
1857  E :          thunk_code_ref.referenced()->references().begin()->first;
1858  E :      EXPECT_TRUE(thunk_code_ref.referenced()->GetReference(ref_idx,
1859    :          &thunk_heap_create_ref));
1860  E :      EXPECT_EQ(asan_heap_create_ref, thunk_heap_create_ref);
1861  E :    }
1862  E :  }
1863    :  
1864  E :  TEST_F(AsanTransformTest, HotPatchingSection) {
1865  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
1866    :  
1867  E :    asan_transform_.set_hot_patching(true);
1868  E :    ASSERT_TRUE(block_graph::ApplyBlockGraphTransform(
1869  E :        &asan_transform_, policy_, &block_graph_, header_block_));
1870    :  
1871    :    // Look for the presence of the hot patching section.
1872  E :    const BlockGraph::Section* hp_section = nullptr;
1873  E :    for (const auto& entry : block_graph_.sections()) {
1874  E :      const BlockGraph::Section* sect = &entry.second;
1875  E :      if (sect->name() == common::kHotPatchingMetadataSectionName) {
1876  E :        hp_section = sect;
1877    :      }
1878  E :    }
1879  E :    ASSERT_NE(nullptr, hp_section);
1880    :  
1881    :    // We iterate over the blocks and check that a block is in the list of hot
1882    :    // patched blocks iff it has been prepared for hot patching.
1883  E :    std::unordered_set<const BlockGraph::Block*> hot_patched_set_(
1884    :        asan_transform_.hot_patched_blocks_.begin(),
1885    :        asan_transform_.hot_patched_blocks_.end());
1886  E :    for (const auto& entry : block_graph_.blocks()) {
1887  E :      const BlockGraph::Block* block = &entry.second;
1888    :  
1889    :      // We check |padding_before| to see if the block has been prepared for hot
1890    :      // patching.
1891  E :      size_t expected_padding = hot_patched_set_.count(block) ? 5U : 0U;
1892  E :      EXPECT_EQ(expected_padding, block->padding_before());
1893  E :    }
1894  E :  }
1895    :  
1896    :  }  // namespace transforms
1897    :  }  // namespace instrument

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