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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
99.8%4674680.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 <vector>
  21    :  
  22    :  #include "base/scoped_native_library.h"
  23    :  #include "base/string_util.h"
  24    :  #include "base/stringprintf.h"
  25    :  #include "base/files/scoped_temp_dir.h"
  26    :  #include "base/win/pe_image.h"
  27    :  #include "gtest/gtest.h"
  28    :  #include "syzygy/block_graph/basic_block_assembler.h"
  29    :  #include "syzygy/common/defs.h"
  30    :  #include "syzygy/core/unittest_util.h"
  31    :  #include "syzygy/instrument/transforms/unittest_util.h"
  32    :  #include "syzygy/pe/decomposer.h"
  33    :  #include "syzygy/pe/pe_file.h"
  34    :  #include "syzygy/pe/pe_relinker.h"
  35    :  #include "syzygy/pe/pe_utils.h"
  36    :  #include "syzygy/pe/unittest_util.h"
  37    :  #include "syzygy/pe/transforms/pe_add_imports_transform.h"
  38    :  #include "third_party/distorm/files/include/mnemonics.h"
  39    :  
  40    :  namespace instrument {
  41    :  namespace transforms {
  42    :  
  43    :  namespace {
  44    :  
  45    :  using block_graph::BasicBlock;
  46    :  using block_graph::BasicCodeBlock;
  47    :  using block_graph::BasicBlockSubGraph;
  48    :  using block_graph::BlockGraph;
  49    :  using block_graph::Instruction;
  50    :  using block_graph::RelativeAddressFilter;
  51    :  using core::RelativeAddress;
  52    :  typedef AsanBasicBlockTransform::MemoryAccessMode AsanMemoryAccessMode;
  53    :  typedef AsanBasicBlockTransform::AsanHookMap HookMap;
  54    :  typedef AsanBasicBlockTransform::AsanHookMapEntryKey HookMapEntryKey;
  55    :  
  56    :  // A derived class to expose protected members for unit-testing.
  57    :  class TestAsanBasicBlockTransform : public AsanBasicBlockTransform {
  58    :   public:
  59    :    using AsanBasicBlockTransform::InstrumentBasicBlock;
  60    :  
  61  E :    explicit TestAsanBasicBlockTransform(AsanHookMap* hooks_check_access)
  62    :        : AsanBasicBlockTransform(hooks_check_access) {
  63  E :    }
  64    :  };
  65    :  
  66    :  // A derived class to expose protected members for unit-testing.
  67    :  class TestAsanTransform : public AsanTransform {
  68    :   public:
  69    :    using AsanTransform::FunctionInterceptionSet;
  70    :    using AsanTransform::InterceptFunctions;
  71    :  };
  72    :  
  73    :  class AsanTransformTest : public testing::TestDllTransformTest {
  74    :   public:
  75  E :    AsanTransformTest() : basic_block_(NULL) {
  76  E :      basic_block_ = subgraph_.AddBasicCodeBlock("dummy");
  77    :      bb_asm_.reset(new block_graph::BasicBlockAssembler(
  78    :          basic_block_->instructions().begin(),
  79  E :          &basic_block_->instructions()));
  80  E :    }
  81    :  
  82    :    void AddHookRef(const std::string& hook_name,
  83    :                    AsanBasicBlockTransform::MemoryAccessMode access_kind,
  84    :                    int access_size,
  85    :                    uint16_t opcode,
  86  E :                    bool save_flags) {
  87    :        HookMapEntryKey map_key = {
  88  E :            access_kind,
  89  E :            access_size,
  90  E :            opcode,
  91    :            save_flags
  92  E :        };
  93    :        hooks_check_access_[map_key] =
  94  E :            block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 4, hook_name);
  95    :        // Set up the references to the hooks needed by SyzyAsan.
  96    :        hooks_check_access_ref_[map_key] =
  97    :            BlockGraph::Reference(BlockGraph::ABSOLUTE_REF, 4,
  98  E :                                  hooks_check_access_[map_key], 0, 0);
  99  E :    }
 100    :  
 101  E :    void InitHooksRefs() {
 102    :      // Initialize the read access hooks.
 103  E :      for (int access_size = 1; access_size <= 8; access_size *= 2) {
 104    :        std::string name =
 105  E :            base::StringPrintf("asan_check_%d_byte_read_access", access_size);
 106    :        AddHookRef(name, AsanBasicBlockTransform::kReadAccess, access_size, 0,
 107  E :                   true);
 108  E :        name += "_no_flags";
 109    :        AddHookRef(name, AsanBasicBlockTransform::kReadAccess, access_size, 0,
 110  E :                   false);
 111  E :      }
 112    :      // Initialize the write access hooks.
 113  E :      for (int access_size = 1; access_size <= 8; access_size *= 2) {
 114    :        std::string name =
 115  E :            base::StringPrintf("asan_check_%d_byte_write_access", access_size);
 116    :        AddHookRef(name, AsanBasicBlockTransform::kWriteAccess, access_size, 0,
 117  E :                   true);
 118  E :        name += "_no_flags";
 119    :        AddHookRef(name, AsanBasicBlockTransform::kWriteAccess, access_size, 0,
 120  E :                   false);
 121  E :      }
 122    :  
 123  E :      const _InstructionType strings[] = { I_CMPS, I_MOVS, I_STOS };
 124  E :      int strings_length = arraysize(strings);
 125    :  
 126  E :      for (int access_size = 1; access_size <= 4; access_size *= 2) {
 127  E :        for (int inst = 0; inst < strings_length; ++inst) {
 128  E :          uint16_t opcode = strings[inst];
 129    :          const char* opcode_str =
 130  E :              reinterpret_cast<const char*>(GET_MNEMONIC_NAME(opcode));
 131    :          std::string name =
 132    :              base::StringPrintf("asan_check_repz_%d_byte_%s_access",
 133  E :                                 access_size, opcode_str);
 134  E :          StringToLowerASCII(&name);
 135    :          AddHookRef(name, AsanBasicBlockTransform::kRepzAccess, access_size,
 136  E :                     opcode, true);
 137  E :        }
 138  E :      }
 139    :  
 140    :      // Initialize special instruction hooks.
 141  E :      for (int access_size = 1; access_size <= 4; access_size *= 2) {
 142  E :        for (int inst = 0; inst < strings_length; ++inst) {
 143  E :          uint16_t opcode = strings[inst];
 144    :          const char* opcode_str =
 145  E :              reinterpret_cast<const char*>(GET_MNEMONIC_NAME(opcode));
 146    :  
 147    :          // Initialize the strings without prefix access hooks.
 148    :          std::string name =
 149    :              base::StringPrintf("asan_check_%d_byte_%s_access",
 150  E :                                 access_size, opcode_str);
 151  E :          StringToLowerASCII(&name);
 152    :          AddHookRef(name, AsanBasicBlockTransform::kInstrAccess, access_size,
 153  E :                     opcode, true);
 154    :  
 155    :          // Initialize the strings with prefix access hooks.
 156    :           std::string repz_name =
 157    :              base::StringPrintf("asan_check_repz_%d_byte_%s_access",
 158  E :                                 access_size, opcode_str);
 159  E :          StringToLowerASCII(&repz_name);
 160    :          AddHookRef(repz_name, AsanBasicBlockTransform::kRepzAccess, access_size,
 161  E :                     opcode, true);
 162  E :        }
 163  E :      }
 164  E :    }
 165    :  
 166  E :    bool AddInstructionFromBuffer(const uint8* data, size_t length) {
 167  E :      DCHECK(data != NULL);
 168  E :      DCHECK(length < core::AssemblerImpl::kMaxInstructionLength);
 169    :  
 170  E :      block_graph::Instruction temp;
 171  E :      if (!block_graph::Instruction::FromBuffer(data, length, &temp))
 172  i :        return false;
 173    :  
 174    :      // Append this instruction to the basic block.
 175  E :      basic_block_->instructions().push_back(temp);
 176    :  
 177  E :      return true;
 178  E :    }
 179    :  
 180    :    // Some handy constants we'll use throughout the tests.
 181    :    // @{
 182    :    static const BasicBlock::Size kDataSize;
 183    :    static const uint8 kBlockData[];
 184    :    // @}
 185    :  
 186    :   protected:
 187    :    base::ScopedTempDir temp_dir_;
 188    :    TestAsanTransform asan_transform_;
 189    :    HookMap hooks_check_access_ref_;
 190    :    std::map<HookMapEntryKey, BlockGraph::Block*> hooks_check_access_;
 191    :    BasicBlockSubGraph subgraph_;
 192    :    BasicCodeBlock* basic_block_;
 193    :    scoped_ptr<block_graph::BasicBlockAssembler> bb_asm_;
 194    :  };
 195    :  
 196    :  const BasicBlock::Size AsanTransformTest::kDataSize = 32;
 197    :  const uint8 AsanTransformTest::kBlockData[AsanTransformTest::kDataSize] = {};
 198    :  
 199    :  }  // namespace
 200    :  
 201  E :  TEST_F(AsanTransformTest, SetInstrumentDLLName) {
 202  E :    asan_transform_.set_instrument_dll_name("foo");
 203  E :    ASSERT_EQ(strcmp(asan_transform_.instrument_dll_name(), "foo"), 0);
 204  E :  }
 205    :  
 206  E :  TEST_F(AsanTransformTest, SetUseLivenessFlag) {
 207  E :    EXPECT_FALSE(asan_transform_.use_liveness_analysis());
 208  E :    asan_transform_.set_use_liveness_analysis(true);
 209  E :    EXPECT_TRUE(asan_transform_.use_liveness_analysis());
 210  E :    asan_transform_.set_use_liveness_analysis(false);
 211  E :    EXPECT_FALSE(asan_transform_.use_liveness_analysis());
 212    :  
 213  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 214  E :    EXPECT_FALSE(bb_transform.use_liveness_analysis());
 215  E :    bb_transform.set_use_liveness_analysis(true);
 216  E :    EXPECT_TRUE(bb_transform.use_liveness_analysis());
 217  E :    bb_transform.set_use_liveness_analysis(false);
 218  E :    EXPECT_FALSE(bb_transform.use_liveness_analysis());
 219  E :  }
 220    :  
 221  E :  TEST_F(AsanTransformTest, SetInterceptCRTFuntionsFlag) {
 222  E :    EXPECT_FALSE(asan_transform_.use_interceptors());
 223  E :    asan_transform_.set_use_interceptors(true);
 224  E :    EXPECT_TRUE(asan_transform_.use_interceptors());
 225  E :    asan_transform_.set_use_interceptors(false);
 226  E :    EXPECT_FALSE(asan_transform_.use_interceptors());
 227  E :  }
 228    :  
 229  E :  TEST_F(AsanTransformTest, SetRemoveRedundantChecksFlag) {
 230  E :    EXPECT_FALSE(asan_transform_.remove_redundant_checks());
 231  E :    asan_transform_.set_remove_redundant_checks(true);
 232  E :    EXPECT_TRUE(asan_transform_.remove_redundant_checks());
 233  E :    asan_transform_.set_remove_redundant_checks(false);
 234  E :    EXPECT_FALSE(asan_transform_.remove_redundant_checks());
 235    :  
 236  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 237  E :    EXPECT_FALSE(bb_transform.remove_redundant_checks());
 238  E :    bb_transform.set_remove_redundant_checks(true);
 239  E :    EXPECT_TRUE(bb_transform.remove_redundant_checks());
 240  E :    bb_transform.set_remove_redundant_checks(false);
 241  E :    EXPECT_FALSE(bb_transform.remove_redundant_checks());
 242  E :  }
 243    :  
 244  E :  TEST_F(AsanTransformTest, ApplyAsanTransform) {
 245  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
 246    :  
 247    :    ASSERT_TRUE(block_graph::ApplyBlockGraphTransform(
 248  E :        &asan_transform_, &policy_, &block_graph_, dos_header_block_));
 249    :  
 250    :    // TODO(sebmarchand): Ensure that each memory access is instrumented by
 251    :    // decomposing each block of the new block-graph into basic blocks and walk
 252    :    // through their instructions. For now it's not possible due to an issue with
 253    :    // the labels in the new block-graph.
 254  E :  }
 255    :  
 256  E :  TEST_F(AsanTransformTest, InjectAsanHooks) {
 257    :    // Add a read access to the memory.
 258  E :    bb_asm_->mov(core::eax, block_graph::Operand(core::ebx));
 259    :    // Add a write access to the memory.
 260  E :    bb_asm_->mov(block_graph::Operand(core::ecx), core::edx);
 261    :  
 262    :    // Add source ranges to the instruction.
 263  E :    block_graph::Instruction& i1 = *basic_block_->instructions().begin();
 264    :    Instruction::SourceRange source_range =
 265  E :        Instruction::SourceRange(RelativeAddress(1000), i1.size());
 266  E :    i1.set_source_range(source_range);
 267    :  
 268    :    // Instrument this basic block.
 269  E :    InitHooksRefs();
 270  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 271    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 272  E :        basic_block_, AsanBasicBlockTransform::kSafeStackAccess));
 273    :  
 274    :    // Ensure that the basic block is instrumented.
 275    :  
 276    :    // We had 2 instructions initially, and for each of them we add 3
 277    :    // instructions, so we expect to have 2 + 3 * 2 = 8 instructions.
 278  E :    ASSERT_EQ(basic_block_->instructions().size(), 8);
 279    :  
 280    :    // Walk through the instructions to ensure that the Asan hooks have been
 281    :    // injected.
 282    :    BasicBlock::Instructions::const_iterator iter_inst =
 283  E :        basic_block_->instructions().begin();
 284    :  
 285  E :    Instruction::SourceRange empty_source_range;
 286  E :    ASSERT_TRUE(empty_source_range != source_range);
 287    :  
 288    :    // First we check if the first memory access is instrumented as a 4 byte read
 289    :    // access. We also validate that the instrumentation has not had source range
 290    :    // information added.
 291  E :    ASSERT_EQ(empty_source_range, iter_inst->source_range());
 292  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_PUSH);
 293  E :    ASSERT_EQ(empty_source_range, iter_inst->source_range());
 294  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_LEA);
 295  E :    ASSERT_EQ(empty_source_range, iter_inst->source_range());
 296  E :    ASSERT_EQ(iter_inst->references().size(), 1);
 297    :    HookMapEntryKey check_4_byte_read_key =
 298  E :        { AsanBasicBlockTransform::kReadAccess, 4, 0, true };
 299    :    ASSERT_TRUE(iter_inst->references().begin()->second.block()
 300  E :        == hooks_check_access_[check_4_byte_read_key]);
 301  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_CALL);
 302  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_MOV);
 303    :  
 304    :    // Then we check if the second memory access is well instrumented as a 4 byte
 305    :    // write access.
 306  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_PUSH);
 307  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_LEA);
 308  E :    ASSERT_EQ(iter_inst->references().size(), 1);
 309    :    HookMapEntryKey check_4_byte_write_key =
 310  E :        { AsanBasicBlockTransform::kWriteAccess, 4, 0, true };
 311    :    ASSERT_TRUE(iter_inst->references().begin()->second.block()
 312  E :        == hooks_check_access_[check_4_byte_write_key]);
 313  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_CALL);
 314  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_MOV);
 315    :  
 316  E :    ASSERT_TRUE(iter_inst == basic_block_->instructions().end());
 317  E :  }
 318    :  
 319  E :  TEST_F(AsanTransformTest, InjectAsanHooksWithSourceRange) {
 320    :    // Add a read access to the memory.
 321  E :    bb_asm_->mov(core::eax, block_graph::Operand(core::ebx));
 322    :  
 323    :    // Add a source range to the instruction.
 324  E :    block_graph::Instruction& i1 = *basic_block_->instructions().begin();
 325    :    Instruction::SourceRange source_range =
 326  E :        Instruction::SourceRange(RelativeAddress(1000), i1.size());
 327  E :    i1.set_source_range(source_range);
 328    :  
 329    :    // Keep track of basic block size.
 330  E :    uint32 before_instructions_count = basic_block_->instructions().size();
 331    :  
 332    :    // Instrument this basic block.
 333  E :    InitHooksRefs();
 334  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 335  E :    bb_transform.set_debug_friendly(true);
 336    :  
 337    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 338  E :          basic_block_, AsanBasicBlockTransform::kSafeStackAccess));
 339    :  
 340    :    // Ensure this basic block is instrumented.
 341  E :    uint32 after_instructions_count = basic_block_->instructions().size();
 342  E :    ASSERT_LT(before_instructions_count, after_instructions_count);
 343    :  
 344    :    // Walk through the instructions and validate the source range.
 345    :    BasicBlock::Instructions::const_iterator iter_inst =
 346  E :        basic_block_->instructions().begin();
 347    :  
 348  E :    for ( ; iter_inst != basic_block_->instructions().end(); ++iter_inst)
 349  E :      EXPECT_EQ(source_range, iter_inst->source_range());
 350  E :  }
 351    :  
 352  E :  TEST_F(AsanTransformTest, InstrumentDifferentKindOfInstructions) {
 353  E :    uint32 instrumentable_instructions = 0;
 354    :  
 355    :    // Generate a bunch of instrumentable and non instrumentable instructions.
 356  E :    bb_asm_->mov(core::eax, block_graph::Operand(core::ebx));
 357  E :    instrumentable_instructions++;
 358  E :    bb_asm_->mov(block_graph::Operand(core::ecx), core::edx);
 359  E :    instrumentable_instructions++;
 360  E :    bb_asm_->call(block_graph::Operand(core::ecx));
 361  E :    instrumentable_instructions++;
 362  E :    bb_asm_->jmp(block_graph::Operand(core::ecx));
 363  E :    instrumentable_instructions++;
 364  E :    bb_asm_->push(block_graph::Operand(core::eax));
 365  E :    instrumentable_instructions++;
 366    :  
 367    :    // Non-instrumentable.
 368  E :    bb_asm_->lea(core::eax, block_graph::Operand(core::ecx));
 369    :  
 370    :    uint32 expected_instructions_count = basic_block_->instructions().size()
 371  E :        + 3 * instrumentable_instructions;
 372    :    // Instrument this basic block.
 373  E :    InitHooksRefs();
 374  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 375    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 376  E :        basic_block_, AsanBasicBlockTransform::kSafeStackAccess));
 377  E :    ASSERT_EQ(basic_block_->instructions().size(), expected_instructions_count);
 378  E :  }
 379    :  
 380  E :  TEST_F(AsanTransformTest, InstrumentAndRemoveRedundantChecks) {
 381  E :    uint32 instrumentable_instructions = 0;
 382    :  
 383    :    // Generate a bunch of instrumentable and non instrumentable instructions.
 384    :    // We generate operand [ecx] multiple time as a redundant memory access.
 385  E :    bb_asm_->mov(core::eax, block_graph::Operand(core::ecx));
 386  E :    instrumentable_instructions++;
 387  E :    bb_asm_->mov(block_graph::Operand(core::ecx), core::edx);
 388    :    // Validate that indirect call clear the memory state.
 389  E :    bb_asm_->call(block_graph::Operand(core::ecx));
 390  E :    bb_asm_->push(block_graph::Operand(core::eax));
 391  E :    instrumentable_instructions++;
 392  E :    bb_asm_->mov(core::eax, block_graph::Operand(core::ecx));
 393  E :    instrumentable_instructions++;
 394  E :    bb_asm_->jmp(block_graph::Operand(core::ecx));
 395    :  
 396    :    uint32 expected_instructions_count = basic_block_->instructions().size()
 397  E :        + 3 * instrumentable_instructions;
 398    :    // Instrument this basic block.
 399  E :    InitHooksRefs();
 400  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 401  E :    bb_transform.set_remove_redundant_checks(true);
 402    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 403  E :        basic_block_, AsanBasicBlockTransform::kSafeStackAccess));
 404  E :    ASSERT_EQ(basic_block_->instructions().size(), expected_instructions_count);
 405  E :  }
 406    :  
 407  E :  TEST_F(AsanTransformTest, NonInstrumentableStackBasedInstructions) {
 408    :    // DEC DWORD [EBP - 0x2830]
 409    :    static const uint8 kDec1[6] = { 0xff, 0x8d, 0xd0, 0xd7, 0xff, 0xff };
 410    :    // INC DWORD [EBP - 0x31c]
 411    :    static const uint8 kInc1[6] = { 0xff, 0x85, 0xe4, 0xfc, 0xff, 0xff };
 412    :    // INC DWORD [ESP + 0x1c]
 413    :    static const uint8 kInc2[4] = { 0xff, 0x44, 0x24, 0x1c };
 414    :    // NEG DWORD [EBP + 0x24]
 415    :    static const uint8 kNeg1[3] = { 0xf7, 0x5d, 0x24 };
 416    :    // FILD QWORD [EBP - 0x8]
 417    :    static const uint8 kFild1[3] = { 0xdf, 0x6d, 0xf8 };
 418    :    // FISTP QWORD [ESP + 0x28]
 419    :    static const uint8 kFistp1[4] = { 0xdf, 0x7c, 0x24, 0x28 };
 420    :    // MOV EDI, [EBP - 0x4]
 421    :    static const uint8 kMov1[3] = { 0x8b, 0x7d, 0xfc };
 422    :    // MOV EAX, [EBP - 0x104]
 423    :    static const uint8 kMov2[6] = { 0x8b, 0x85, 0xfc, 0xfe, 0xff, 0xff };
 424    :  
 425  E :    ASSERT_TRUE(AddInstructionFromBuffer(kDec1, sizeof(kDec1)));
 426  E :    ASSERT_TRUE(AddInstructionFromBuffer(kInc1, sizeof(kInc1)));
 427  E :    ASSERT_TRUE(AddInstructionFromBuffer(kInc2, sizeof(kInc2)));
 428  E :    ASSERT_TRUE(AddInstructionFromBuffer(kNeg1, sizeof(kNeg1)));
 429  E :    ASSERT_TRUE(AddInstructionFromBuffer(kFild1, sizeof(kFild1)));
 430  E :    ASSERT_TRUE(AddInstructionFromBuffer(kFistp1, sizeof(kFistp1)));
 431  E :    ASSERT_TRUE(AddInstructionFromBuffer(kMov1, sizeof(kMov1)));
 432  E :    ASSERT_TRUE(AddInstructionFromBuffer(kMov2, sizeof(kMov2)));
 433    :  
 434    :    // Keep track of the basic block size before Asan transform.
 435  E :    uint32 expected_basic_block_size = basic_block_->instructions().size();
 436    :  
 437    :    // Instrument this basic block.
 438  E :    InitHooksRefs();
 439  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 440    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 441  E :          basic_block_, AsanBasicBlockTransform::kSafeStackAccess));
 442    :  
 443    :    // Non-instrumentable instructions implies no change.
 444  E :    EXPECT_EQ(expected_basic_block_size, basic_block_->instructions().size());
 445  E :  }
 446    :  
 447  E :  TEST_F(AsanTransformTest, InstrumentableStackBasedUnsafeInstructions) {
 448    :    // DEC DWORD [EBP - 0x2830]
 449    :    static const uint8 kDec1[6] = { 0xff, 0x8d, 0xd0, 0xd7, 0xff, 0xff };
 450    :  
 451  E :    ASSERT_TRUE(AddInstructionFromBuffer(kDec1, sizeof(kDec1)));
 452    :  
 453    :    // Keep track of the basic block size before Asan transform.
 454  E :    uint32 previous_basic_block_size = basic_block_->instructions().size();
 455    :  
 456    :    // Instrument this basic block considering invalid stack manipulation.
 457  E :    InitHooksRefs();
 458  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 459    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 460  E :          basic_block_, AsanBasicBlockTransform::kUnsafeStackAccess));
 461    :  
 462    :    // This instruction should have been instrumented, and we must observe
 463    :    // a increase in size.
 464  E :    EXPECT_LT(previous_basic_block_size, basic_block_->instructions().size());
 465  E :  }
 466    :  
 467  E :  TEST_F(AsanTransformTest, NonInstrumentableSegmentBasedInstructions) {
 468    :    // add eax, fs:[eax]
 469    :    static const uint8 kAdd1[3] = { 0x64, 0x03, 0x00 };
 470    :    // inc gs:[eax]
 471    :    static const uint8 kInc1[3] = { 0x65, 0xFE, 0x00 };
 472    :  
 473  E :    ASSERT_TRUE(AddInstructionFromBuffer(kAdd1, sizeof(kAdd1)));
 474  E :    ASSERT_TRUE(AddInstructionFromBuffer(kInc1, sizeof(kInc1)));
 475    :  
 476    :    // Keep track of the basic block size before Asan transform.
 477  E :    uint32 expected_basic_block_size = basic_block_->instructions().size();
 478    :  
 479    :    // Instrument this basic block.
 480  E :    InitHooksRefs();
 481  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 482    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 483    :          basic_block_,
 484  E :          AsanBasicBlockTransform::kSafeStackAccess));
 485    :  
 486    :    // Non-instrumentable instructions implies no change.
 487  E :    EXPECT_EQ(expected_basic_block_size, basic_block_->instructions().size());
 488  E :  }
 489    :  
 490  E :  TEST_F(AsanTransformTest, FilteredInstructionsNotInstrumented) {
 491    :    // Add a read access to the memory.
 492  E :    bb_asm_->mov(core::eax, block_graph::Operand(core::ebx));
 493    :    // Add a write access to the memory.
 494  E :    bb_asm_->mov(block_graph::Operand(core::ecx), core::edx);
 495    :  
 496    :    // Add a source range to the first instruction.
 497  E :    block_graph::Instruction& i1 = *basic_block_->instructions().begin();
 498    :    i1.set_source_range(Instruction::SourceRange(
 499  E :        RelativeAddress(1000), i1.size()));
 500    :  
 501    :    // Create a filter that blocks out that source range.
 502    :    RelativeAddressFilter filter(
 503  E :        RelativeAddressFilter::Range(RelativeAddress(0), 2000));
 504  E :    filter.Mark(RelativeAddressFilter::Range(RelativeAddress(995), 50));
 505    :  
 506    :    // Pass the filter to the BB transform.
 507  E :    InitHooksRefs();
 508  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 509  E :    bb_transform.set_filter(&filter);
 510    :  
 511    :    // Instrument this basic block.
 512    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 513  E :          basic_block_, AsanBasicBlockTransform::kSafeStackAccess));
 514    :  
 515    :    // Ensure that the basic block is instrumented, but only the second
 516    :    // instruction.
 517    :  
 518    :    // We had 2 instructions initially. For the second one we add 3
 519    :    // instructions, so we expect to have 1 + (1 + 3) = 5 instructions.
 520  E :    ASSERT_EQ(basic_block_->instructions().size(), 5);
 521    :  
 522    :    // Walk through the instructions to ensure that the Asan hooks have been
 523    :    // injected.
 524    :    BasicBlock::Instructions::const_iterator iter_inst =
 525  E :        basic_block_->instructions().begin();
 526    :  
 527    :    // Ensure the first instruction is not instrumented at all.
 528  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_MOV);
 529    :  
 530    :    // Then we check if the second memory access is well instrumented as a 4 byte
 531    :    // write access.
 532  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_PUSH);
 533  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_LEA);
 534  E :    ASSERT_EQ(iter_inst->references().size(), 1);
 535    :    HookMapEntryKey check_4_byte_write_key =
 536  E :        { AsanBasicBlockTransform::kWriteAccess, 4, 0, true };
 537    :    ASSERT_TRUE(iter_inst->references().begin()->second.block()
 538  E :        == hooks_check_access_[check_4_byte_write_key]);
 539  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_CALL);
 540  E :    ASSERT_TRUE((iter_inst++)->representation().opcode == I_MOV);
 541    :  
 542  E :    ASSERT_TRUE(iter_inst == basic_block_->instructions().end());
 543  E :  }
 544    :  
 545  E :  TEST_F(AsanTransformTest, InstrumentableStringInstructions) {
 546    :    static const uint8 movsd[1] = { 0xA5 };
 547    :    static const uint8 movsw[2] = { 0x66, 0xA5 };
 548    :    static const uint8 movsb[1] = { 0xA4 };
 549    :  
 550    :    static const uint8 cmpsd[1] = { 0xA7 };
 551    :    static const uint8 cmpsw[2] = { 0x66, 0xA7 };
 552    :    static const uint8 cmpsb[1] = { 0xA6 };
 553    :  
 554    :    static const uint8 stosd[1] = { 0xAB };
 555    :    static const uint8 stosw[2] = { 0x66, 0xAB };
 556    :    static const uint8 stosb[1] = { 0xAA };
 557    :  
 558  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsd, sizeof(movsd)));
 559  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsw, sizeof(movsw)));
 560  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsb, sizeof(movsb)));
 561  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsd, sizeof(cmpsd)));
 562  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsw, sizeof(cmpsw)));
 563  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsb, sizeof(cmpsb)));
 564  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosd, sizeof(stosd)));
 565  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosw, sizeof(stosw)));
 566  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosb, sizeof(stosb)));
 567    :  
 568    :    // Keep number of instrumentable instructions.
 569  E :    uint32 count_instructions = basic_block_->instructions().size();
 570    :  
 571    :    // Keep track of the basic block size before Asan transform.
 572  E :    uint32 basic_block_size = basic_block_->instructions().size();
 573    :  
 574    :    // Instrument this basic block.
 575  E :    InitHooksRefs();
 576  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 577    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 578  E :          basic_block_, AsanBasicBlockTransform::kSafeStackAccess));
 579    :  
 580    :    // Each instrumentable instructions implies 1 new instructions.
 581  E :    uint32 expected_basic_block_size = count_instructions + basic_block_size;
 582    :  
 583    :    // Validate basic block size.
 584  E :    ASSERT_EQ(basic_block_->instructions().size(), expected_basic_block_size);
 585  E :  }
 586    :  
 587  E :  TEST_F(AsanTransformTest, InstrumentableRepzStringInstructions) {
 588    :    static const uint8 movsd[2] = { 0xF3, 0xA5 };
 589    :    static const uint8 movsw[3] = { 0xF3, 0x66, 0xA5 };
 590    :    static const uint8 movsb[2] = { 0xF3, 0xA4 };
 591    :  
 592    :    static const uint8 cmpsd[2] = { 0xF3, 0xA7 };
 593    :    static const uint8 cmpsw[3] = { 0xF3, 0x66, 0xA7 };
 594    :    static const uint8 cmpsb[2] = { 0xF3, 0xA6 };
 595    :  
 596    :    static const uint8 stosd[2] = { 0xF3, 0xAB };
 597    :    static const uint8 stosw[3] = { 0xF3, 0x66, 0xAB };
 598    :    static const uint8 stosb[2] = { 0xF3, 0xAA };
 599    :  
 600  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsd, sizeof(movsd)));
 601  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsw, sizeof(movsw)));
 602  E :    EXPECT_TRUE(AddInstructionFromBuffer(movsb, sizeof(movsb)));
 603  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsd, sizeof(cmpsd)));
 604  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsw, sizeof(cmpsw)));
 605  E :    EXPECT_TRUE(AddInstructionFromBuffer(cmpsb, sizeof(cmpsb)));
 606  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosd, sizeof(stosd)));
 607  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosw, sizeof(stosw)));
 608  E :    EXPECT_TRUE(AddInstructionFromBuffer(stosb, sizeof(stosb)));
 609    :  
 610    :    // Keep number of instrumentable instructions.
 611  E :    uint32 count_instructions = basic_block_->instructions().size();
 612    :  
 613    :    // Keep track of the basic block size before Asan transform.
 614  E :    uint32 basic_block_size = basic_block_->instructions().size();
 615    :  
 616    :    // Instrument this basic block.
 617  E :    InitHooksRefs();
 618  E :    TestAsanBasicBlockTransform bb_transform(&hooks_check_access_ref_);
 619    :    ASSERT_TRUE(bb_transform.InstrumentBasicBlock(
 620  E :          basic_block_, AsanBasicBlockTransform::kSafeStackAccess));
 621    :  
 622    :    // Each instrumentable instructions implies 1 new instructions.
 623  E :    uint32 expected_basic_block_size = count_instructions + basic_block_size;
 624    :  
 625    :    // Validate basic block size.
 626  E :    ASSERT_EQ(basic_block_->instructions().size(), expected_basic_block_size);
 627  E :  }
 628    :  
 629    :  namespace {
 630    :  
 631    :  using base::win::PEImage;
 632    :  typedef std::set<std::string> StringSet;
 633    :  typedef std::set<void*> FunctionsIATAddressSet;
 634    :  typedef std::vector<std::string> StringVector;
 635    :  
 636    :  const char kAsanRtlDll[] = "syzyasan_rtl.dll";
 637    :  
 638    :  bool EnumKernel32HeapImports(const PEImage &image,
 639    :                               const char* module,
 640    :                               unsigned long ordinal,
 641    :                               const char* name,
 642    :                               unsigned long hint,
 643    :                               PIMAGE_THUNK_DATA iat,
 644  E :                               void* cookie) {
 645  E :    DCHECK(module != NULL);
 646  E :    DCHECK(cookie != NULL);
 647    :  
 648  E :    StringVector* modules = reinterpret_cast<StringVector*>(cookie);
 649    :  
 650  E :    if (_stricmp("kernel32.dll", module) == 0 && strncmp("Heap", name, 4) == 0) {
 651  E :      DCHECK(name != NULL);
 652  E :      modules->push_back(name);
 653    :    }
 654    :  
 655  E :    return true;
 656  E :  }
 657    :  
 658    :  bool EnumKernel32InterceptedFunctionsImports(const PEImage &image,
 659    :                                               const char* module,
 660    :                                               unsigned long ordinal,
 661    :                                               const char* name,
 662    :                                               unsigned long hint,
 663    :                                               PIMAGE_THUNK_DATA iat,
 664  E :                                               void* cookie) {
 665  E :    DCHECK(module != NULL);
 666  E :    DCHECK(cookie != NULL);
 667    :  
 668  E :    StringVector* modules = reinterpret_cast<StringVector*>(cookie);
 669    :    static const char* kInterceptedFunctions[] = {
 670    :      "ReadFile",
 671    :      "WriteFile",
 672    :    };
 673    :  
 674  E :    if (_stricmp("kernel32.dll", module) == 0) {
 675  E :      for (size_t i = 0; i < arraysize(kInterceptedFunctions); ++i) {
 676  E :        if (base::strcasecmp(kInterceptedFunctions[i], name) == 0) {
 677  E :          DCHECK(name != NULL);
 678  E :          modules->push_back(name);
 679  E :          return true;
 680    :        }
 681  E :      }
 682    :    }
 683    :  
 684  E :    return true;
 685  E :  }
 686    :  
 687    :  bool EnumAsanImports(const PEImage &image,
 688    :                       const char* module,
 689    :                       unsigned long ordinal,
 690    :                       const char* name,
 691    :                       unsigned long hint,
 692    :                       PIMAGE_THUNK_DATA iat,
 693  E :                       void* cookie) {
 694  E :    DCHECK(module != NULL);
 695  E :    DCHECK(cookie != NULL);
 696    :  
 697  E :    StringSet* modules = reinterpret_cast<StringSet*>(cookie);
 698    :  
 699  E :    if (strcmp(kAsanRtlDll, module) == 0) {
 700  E :      DCHECK(name != NULL);
 701  E :      modules->insert(name);
 702    :    }
 703    :  
 704  E :    return true;
 705  E :  }
 706    :  
 707    :  bool GetAsanHooksIATEntries(const PEImage &image,
 708    :                              const char* module,
 709    :                              unsigned long ordinal,
 710    :                              const char* name,
 711    :                              unsigned long hint,
 712    :                              PIMAGE_THUNK_DATA iat,
 713  E :                              void* cookie) {
 714  E :    DCHECK(module != NULL);
 715  E :    DCHECK(cookie != NULL);
 716    :  
 717    :    FunctionsIATAddressSet* hooks_iat_entries =
 718  E :        reinterpret_cast<FunctionsIATAddressSet*>(cookie);
 719    :  
 720  E :    if (strcmp(kAsanRtlDll, module) != 0)
 721  E :      return true;
 722    :  
 723  E :    DCHECK(name != NULL);
 724    :  
 725    :    // Ensures that the function is an asan_check_access hook.
 726  E :    if (StartsWithASCII(name, "asan_check_", true /* case sensitive */))
 727  E :      hooks_iat_entries->insert(reinterpret_cast<PVOID>(iat->u1.Function));
 728    :  
 729  E :    return true;
 730  E :  }
 731    :  
 732    :  }  // namespace
 733    :  
 734  E :  TEST_F(AsanTransformTest, ImportsAreRedirected) {
 735    :    base::FilePath asan_instrumented_dll = testing::GetExeTestDataRelativePath(
 736  E :        testing::kAsanInstrumentedTestDllName);
 737    :  
 738    :    // Load the transformed module without resolving its dependencies.
 739    :    base::NativeLibrary lib =
 740    :        ::LoadLibraryEx(asan_instrumented_dll.value().c_str(),
 741    :                        NULL,
 742  E :                        DONT_RESOLVE_DLL_REFERENCES);
 743  E :    ASSERT_TRUE(lib != NULL);
 744    :    // Make sure it's unloaded on failure.
 745  E :    base::ScopedNativeLibrary lib_keeper(lib);
 746    :  
 747  E :    PEImage image(lib);
 748  E :    ASSERT_TRUE(image.VerifyMagic());
 749  E :    StringSet imports;
 750  E :    ASSERT_TRUE(image.EnumAllImports(&EnumAsanImports, &imports));
 751    :  
 752  E :    StringVector heap_imports;
 753  E :    ASSERT_TRUE(image.EnumAllImports(&EnumKernel32HeapImports, &heap_imports));
 754  E :    StringVector intercepted_functions_imports;
 755    :    ASSERT_TRUE(image.EnumAllImports(&EnumKernel32InterceptedFunctionsImports,
 756  E :                                     &intercepted_functions_imports));
 757    :  
 758    :    // This isn't strictly speaking a full test, as we only check that the new
 759    :    // imports have been added. It's however more trouble than it's worth to
 760    :    // test this fully for now.
 761  E :    StringSet expected;
 762  E :    for (size_t i = 0; i < heap_imports.size(); ++i) {
 763  E :      std::string asan_import = "asan_";
 764  E :      asan_import.append(heap_imports[i]);
 765  E :      expected.insert(asan_import);
 766  E :    }
 767  E :    for (size_t i = 0; i < intercepted_functions_imports.size(); ++i) {
 768  E :      std::string asan_import = "asan_";
 769  E :      asan_import.append(intercepted_functions_imports[i]);
 770  E :      expected.insert(asan_import);
 771  E :    }
 772  E :    expected.insert("asan_check_1_byte_read_access");
 773  E :    expected.insert("asan_check_2_byte_read_access");
 774  E :    expected.insert("asan_check_4_byte_read_access");
 775  E :    expected.insert("asan_check_8_byte_read_access");
 776  E :    expected.insert("asan_check_10_byte_read_access");
 777  E :    expected.insert("asan_check_16_byte_read_access");
 778  E :    expected.insert("asan_check_32_byte_read_access");
 779  E :    expected.insert("asan_check_1_byte_write_access");
 780  E :    expected.insert("asan_check_2_byte_write_access");
 781  E :    expected.insert("asan_check_4_byte_write_access");
 782  E :    expected.insert("asan_check_8_byte_write_access");
 783  E :    expected.insert("asan_check_10_byte_write_access");
 784  E :    expected.insert("asan_check_16_byte_write_access");
 785  E :    expected.insert("asan_check_32_byte_write_access");
 786    :  
 787  E :    expected.insert("asan_check_1_byte_read_access_no_flags");
 788  E :    expected.insert("asan_check_2_byte_read_access_no_flags");
 789  E :    expected.insert("asan_check_4_byte_read_access_no_flags");
 790  E :    expected.insert("asan_check_8_byte_read_access_no_flags");
 791  E :    expected.insert("asan_check_10_byte_read_access_no_flags");
 792  E :    expected.insert("asan_check_16_byte_read_access_no_flags");
 793  E :    expected.insert("asan_check_32_byte_read_access_no_flags");
 794  E :    expected.insert("asan_check_1_byte_write_access_no_flags");
 795  E :    expected.insert("asan_check_2_byte_write_access_no_flags");
 796  E :    expected.insert("asan_check_4_byte_write_access_no_flags");
 797  E :    expected.insert("asan_check_8_byte_write_access_no_flags");
 798  E :    expected.insert("asan_check_10_byte_write_access_no_flags");
 799  E :    expected.insert("asan_check_16_byte_write_access_no_flags");
 800  E :    expected.insert("asan_check_32_byte_write_access_no_flags");
 801    :  
 802  E :    expected.insert("asan_check_repz_4_byte_cmps_access");
 803  E :    expected.insert("asan_check_repz_4_byte_movs_access");
 804  E :    expected.insert("asan_check_repz_4_byte_stos_access");
 805  E :    expected.insert("asan_check_repz_2_byte_cmps_access");
 806  E :    expected.insert("asan_check_repz_2_byte_movs_access");
 807  E :    expected.insert("asan_check_repz_2_byte_stos_access");
 808  E :    expected.insert("asan_check_repz_1_byte_cmps_access");
 809  E :    expected.insert("asan_check_repz_1_byte_movs_access");
 810  E :    expected.insert("asan_check_repz_1_byte_stos_access");
 811    :  
 812  E :    expected.insert("asan_check_4_byte_cmps_access");
 813  E :    expected.insert("asan_check_4_byte_movs_access");
 814  E :    expected.insert("asan_check_4_byte_stos_access");
 815  E :    expected.insert("asan_check_2_byte_cmps_access");
 816  E :    expected.insert("asan_check_2_byte_movs_access");
 817  E :    expected.insert("asan_check_2_byte_stos_access");
 818  E :    expected.insert("asan_check_1_byte_cmps_access");
 819  E :    expected.insert("asan_check_1_byte_movs_access");
 820  E :    expected.insert("asan_check_1_byte_stos_access");
 821    :  
 822  E :    expected.insert("asan_memcpy");
 823  E :    expected.insert("asan_memmove");
 824  E :    expected.insert("asan_memset");
 825  E :    expected.insert("asan_memchr");
 826  E :    expected.insert("asan_strcspn");
 827  E :    expected.insert("asan_strlen");
 828  E :    expected.insert("asan_strrchr");
 829  E :    expected.insert("asan_strcmp");
 830  E :    expected.insert("asan_strpbrk");
 831  E :    expected.insert("asan_strstr");
 832  E :    expected.insert("asan_strspn");
 833  E :    expected.insert("asan_strncpy");
 834  E :    expected.insert("asan_strncat");
 835    :  
 836  E :    EXPECT_EQ(expected, imports);
 837  E :  }
 838    :  
 839  E :  TEST_F(AsanTransformTest, AsanHooksAreStubbed) {
 840    :    base::FilePath asan_instrumented_dll = testing::GetExeTestDataRelativePath(
 841  E :        testing::kAsanInstrumentedTestDllName);
 842    :  
 843    :    // Load the transformed module without resolving its dependencies.
 844    :    base::NativeLibrary lib =
 845    :        ::LoadLibraryEx(asan_instrumented_dll.value().c_str(),
 846    :                        NULL,
 847  E :                        DONT_RESOLVE_DLL_REFERENCES);
 848  E :    ASSERT_TRUE(lib != NULL);
 849    :    // Make sure it's unloaded on failure.
 850  E :    base::ScopedNativeLibrary lib_keeper(lib);
 851    :  
 852  E :    PEImage image(lib);
 853  E :    ASSERT_TRUE(image.VerifyMagic());
 854    :  
 855    :    // Iterate over the image import descriptors. We want to make sure the
 856    :    // one for syzyasan_rtl.dll is bound.
 857  E :    DWORD size = image.GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT);
 858  E :    PIMAGE_IMPORT_DESCRIPTOR iid = image.GetFirstImportChunk();
 859  E :    ASSERT_TRUE(iid != NULL);
 860  E :    ASSERT_GE(size, sizeof(IMAGE_IMPORT_DESCRIPTOR));
 861  E :    for (; iid->FirstThunk; ++iid) {
 862    :      std::string module_name(reinterpret_cast<LPCSTR>(
 863  E :          image.RVAToAddr(iid->Name)));
 864  E :      if (module_name == kAsanRtlDll)
 865  E :        ASSERT_NE(0u, iid->TimeDateStamp);
 866  E :    }
 867    :  
 868    :    // As all the hooks may refer to only two kinds of stubs, we expect to have
 869    :    // exactly two entries in the set.
 870  E :    FunctionsIATAddressSet hooks_iat_set;
 871  E :    ASSERT_TRUE(image.EnumAllImports(&GetAsanHooksIATEntries, &hooks_iat_set));
 872  E :    ASSERT_EQ(hooks_iat_set.size(), 2U);
 873    :  
 874    :    // Ensures that all stubs are in the thunks section.
 875  E :    FunctionsIATAddressSet::iterator hook = hooks_iat_set.begin();
 876  E :    for (; hook != hooks_iat_set.end(); ++hook) {
 877  E :      PVOID stub_address = *hook;
 878    :      PIMAGE_SECTION_HEADER stub_sec =
 879  E :          image.GetImageSectionFromAddr(stub_address);
 880    :      ASSERT_STREQ(common::kThunkSectionName,
 881  E :                   reinterpret_cast<const char*>(stub_sec->Name));
 882  E :    }
 883  E :  }
 884    :  
 885  E :  TEST_F(AsanTransformTest, InterceptFunctions) {
 886  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
 887    :  
 888    :    BlockGraph::Block* b1 =
 889  E :        block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 0x20, "testAsan_b1");
 890    :    BlockGraph::Block* b2 =
 891  E :        block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 0x20, "testAsan_b2");
 892    :    BlockGraph::Block* b3 =
 893  E :        block_graph_.AddBlock(BlockGraph::CODE_BLOCK, 0x20, "testAsan_b3");
 894  E :    ASSERT_TRUE(b1 != NULL);
 895  E :    ASSERT_TRUE(b2 != NULL);
 896  E :    ASSERT_TRUE(b3 != NULL);
 897    :  
 898  E :    ASSERT_TRUE(b1->references().empty());
 899  E :    ASSERT_TRUE(b1->referrers().empty());
 900  E :    ASSERT_TRUE(b2->references().empty());
 901  E :    ASSERT_TRUE(b2->referrers().empty());
 902  E :    ASSERT_TRUE(b3->references().empty());
 903  E :    ASSERT_TRUE(b3->referrers().empty());
 904    :  
 905    :    // Add a reference from b2 to b1 and from b3 to b1.
 906  E :    BlockGraph::Reference ref_b2_b1(BlockGraph::PC_RELATIVE_REF, 1, b1, 0, 0);
 907  E :    BlockGraph::Reference ref_b3_b1(BlockGraph::PC_RELATIVE_REF, 1, b1, 1, 1);
 908  E :    ASSERT_TRUE(b2->SetReference(0, ref_b2_b1));
 909  E :    ASSERT_TRUE(b3->SetReference(1, ref_b3_b1));
 910    :  
 911  E :    EXPECT_EQ(2U, b1->referrers().size());
 912    :  
 913  E :    pe::transforms::ImportedModule import_module("foo.dll");
 914    :  
 915  E :    size_t num_blocks_pre_transform = block_graph_.blocks().size();
 916  E :    size_t num_sections_pre_transform = block_graph_.sections().size();
 917    :    // Intercept the calls to b1.
 918  E :    TestAsanTransform::FunctionInterceptionSet function_set;
 919  E :    function_set.insert("testAsan_b1");
 920    :    EXPECT_TRUE(asan_transform_.InterceptFunctions(&import_module,
 921    :                                                   &policy_,
 922    :                                                   &block_graph_,
 923    :                                                   dos_header_block_,
 924  E :                                                   function_set));
 925    :  
 926    :    // The block graph should have grown by 3 blocks:
 927    :    //     - the Import Address Table (IAT),
 928    :    //     - the Import Name Table (INT),
 929    :    //     - the thunk.
 930  E :    EXPECT_EQ(num_blocks_pre_transform + 3, block_graph_.blocks().size());
 931    :  
 932    :    // The .thunks section should have been added.
 933  E :    EXPECT_EQ(num_sections_pre_transform + 1, block_graph_.sections().size());
 934    :  
 935    :    BlockGraph::Section* thunk_section = block_graph_.FindSection(
 936  E :        common::kThunkSectionName);
 937  E :    EXPECT_TRUE(thunk_section != NULL);
 938    :  
 939  E :    const BlockGraph::Block* block_in_thunk_section = NULL;
 940    :    BlockGraph::BlockMap::const_iterator iter_blocks =
 941  E :        block_graph_.blocks().begin();
 942  E :    for (; iter_blocks != block_graph_.blocks().end(); ++iter_blocks) {
 943  E :      if (iter_blocks->second.section() == thunk_section->id()) {
 944    :        // There should be only one block in the thunk section.
 945  E :        EXPECT_TRUE(block_in_thunk_section == NULL);
 946  E :        block_in_thunk_section = &iter_blocks->second;
 947    :      }
 948  E :    }
 949    :  
 950    :    // Only the entry in the IAT should refer to b1.
 951  E :    EXPECT_EQ(1U, b1->referrers().size());
 952  E :  }
 953    :  
 954    :  }  // namespace transforms
 955    :  }  // namespace instrument

Coverage information generated Wed Dec 11 11:34:16 2013.