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

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

Coverage information generated Thu Mar 26 16:15:41 2015.