예제 #1
0
TEST(DedupBlocksTest, useSwitch) {
  g_redex = new RedexContext();

  const char* dexfile = std::getenv("dexfile");
  EXPECT_NE(nullptr, dexfile);

  std::vector<DexStore> stores;
  DexMetadata dm;
  dm.set_id("classes");
  DexStore root_store(dm);
  root_store.add_classes(load_classes_from_dex(dexfile));
  DexClasses& classes = root_store.get_dexen().back();
  stores.emplace_back(std::move(root_store));

  TRACE(RME, 1, "Code before:\n");
  for (const auto& cls : classes) {
    TRACE(RME, 1, "Class %s\n", SHOW(cls));
    for (const auto& m : cls->get_vmethods()) {
      TRACE(RME, 1, "\nmethod %s:\n", SHOW(m));
      IRCode* code = m->get_code();
      code->build_cfg(true);
      EXPECT_EQ(2, count_sgets(code->cfg()));
      code->clear_cfg();
    }
  }

  auto copy_prop = new CopyPropagationPass();
  copy_prop->m_config.static_finals = true;
  copy_prop->m_config.wide_registers = true;
  std::vector<Pass*> passes = {
    copy_prop
  };

  PassManager manager(passes);
  manager.set_testing_mode();

  Json::Value conf_obj = Json::nullValue;
  Scope external_classes;
  ConfigFiles dummy_cfg(conf_obj);
  manager.run_passes(stores, external_classes, dummy_cfg);

  TRACE(RME, 1, "Code after:\n");
  for (const auto& cls : classes) {
    for (const auto& m : cls->get_vmethods()) {
      TRACE(RME, 1, "\nmethod %s:\n", SHOW(m));
      IRCode* code = m->get_code();
      code->build_cfg(true);
      if (strcmp(m->get_name()->c_str(), "remove") == 0) {
        EXPECT_EQ(1, count_sgets(code->cfg()));
      } else {
        EXPECT_EQ(2, count_sgets(code->cfg()));
      }
      code->clear_cfg();
    }
  }
}
예제 #2
0
TEST_F(PostVerify, ConstantPropagation) {
  TRACE(CONSTP, 1, "------------- post ---------------\n");
  auto cls = find_class_named(classes, "Lredex/ConstantPropagationTest;");
  ASSERT_NE(cls, nullptr);
  for (auto& meth : cls->get_vmethods()) {
    if(meth->get_name()->str().find("if") == std::string::npos) {
      continue;
    }
    IRCode* code = new IRCode(meth);
    EXPECT_NE(code, nullptr);
    code->build_cfg(/* editable */ true);
    if (meth->get_name()->str().find("plus_one") != std::string::npos) {
      TRACE(CONSTP, 1, "%s\n", SHOW(meth));
      TRACE(CONSTP, 1, "%s\n", SHOW(code));
    }

    EXPECT_EQ(0, count_ifs(code->cfg()));
    if (meth->get_name()->str().find("plus_one") != std::string::npos) {
      EXPECT_EQ(0, count_ops(code->cfg(), OPCODE_ADD_INT_LIT8));
    }

    if (meth->get_name()->str().find("overflow") != std::string::npos) {
      // make sure we don't fold overflow at compile time
      EXPECT_EQ(1, count_ops(code->cfg(), OPCODE_ADD_INT_LIT8));
    }
    code->clear_cfg();
  }
}
예제 #3
0
void BasicBlockProfilePass::run_pass(DexStoresVector& stores,
                                     ConfigFiles& /* conf */,
                                     PassManager& pm) {

  std::unordered_set<cfg::Block*> bb_profiled;

  auto scope = build_class_scope(stores);
  walk::methods(scope, [&](DexMethod* method) {
    IRCode* code = method->get_code();
    if (code == nullptr) {
      return;
    }
    code->build_cfg(/* editable */ false);
    const auto& blocks = code->cfg().blocks();

    TRACE(BBPROFILE, 5, "M,%s,%zu,%zu,%d\n",
          method->get_deobfuscated_name().c_str(), blocks.size(),
          code->count_opcodes(), method->is_virtual());

    for (cfg::Block* block : blocks) {
      // Only if the current block is a multi-sink block, its predecessors are
      // profiled. This is for tracing the path back.
      if (block->preds().size() > 1) {
        for (const auto& pred : block->preds()) {
          bb_profiled.insert(pred->src());
        }
      }
      TRACE(BBPROFILE, 5,
            "B,%zu,%zu,%zu,"
            "%zu,%d\n",
            block->id(), num_opcodes_bb(block), block->succs().size(),
            block->preds().size(), bb_profiled.count(block) != 0);
    }
  });
}
예제 #4
0
void IRTypeChecker::run() {
  IRCode* code = m_dex_method->get_code();
  if (m_complete) {
    // The type checker can only be run once on any given method.
    return;
  }

  if (code == nullptr) {
    // If the method has no associated code, the type checking trivially
    // succeeds.
    m_complete = true;
    return;
  }

  auto result = check_structure(m_dex_method, m_check_no_overwrite_this);
  if (result != Result::Ok()) {
    m_complete = true;
    m_good = false;
    m_what = result.error_message();
    return;
  }

  // We then infer types for all the registers used in the method.
  code->build_cfg(/* editable */ false);
  const cfg::ControlFlowGraph& cfg = code->cfg();
  m_type_inference =
      std::make_unique<TypeInference>(cfg, m_enable_polymorphic_constants);
  m_type_inference->run(m_dex_method);

  // Finally, we use the inferred types to type-check each instruction in the
  // method. We stop at the first type error encountered.
  auto& type_envs = m_type_inference->get_type_environments();
  for (const MethodItemEntry& mie : InstructionIterable(code)) {
    IRInstruction* insn = mie.insn;
    try {
      auto it = type_envs.find(insn);
      always_assert(it != type_envs.end());
      check_instruction(insn, &it->second);
    } catch (const TypeCheckingException& e) {
      m_good = false;
      std::ostringstream out;
      out << "Type error in method " << m_dex_method->get_deobfuscated_name()
          << " at instruction '" << SHOW(insn) << "' @ " << std::hex
          << static_cast<const void*>(&mie) << " for " << e.what();
      m_what = out.str();
      m_complete = true;
      return;
    }
  }
  m_complete = true;

  if (traceEnabled(TYPE, 5)) {
    std::ostringstream out;
    m_type_inference->print(out);
    TRACE(TYPE, 5, "%s\n", out.str().c_str());
  }
}
예제 #5
0
TEST_F(PostVerify, IPConstantPropagation) {
  auto test_cls =
      find_class_named(classes, "Lredex/IPConstantPropagationTest;");
  size_t count = 0;
  for (auto& meth : test_cls->get_vmethods()) {
    IRCode* code = new IRCode(meth);
    ASSERT_NE(code, nullptr);
    code->build_cfg(/* editable */ true);
    if (meth->get_name()->str() == "two_ctors") {
      EXPECT_EQ(0, count_igets(code->cfg(), "a"));
      EXPECT_EQ(2, count_igets(code->cfg(), "b"));
      ++count;
    } else if (meth->get_name()->str() == "modified_elsewhere") {
      EXPECT_EQ(0, count_igets(code->cfg(), "a"));
      EXPECT_EQ(1, count_igets(code->cfg(), "b"));
      ++count;
    }
  }
  // Make sure the two functions are there.
  ASSERT_EQ(count, 2);
}
예제 #6
0
TEST(ResultPropagationTest, useSwitch) {
  g_redex = new RedexContext();

  const char* dexfile = std::getenv("dexfile");
  EXPECT_NE(nullptr, dexfile);

  std::vector<DexStore> stores;
  DexMetadata dm;
  dm.set_id("classes");
  DexStore root_store(dm);
  root_store.add_classes(load_classes_from_dex(dexfile));
  DexClasses& classes = root_store.get_dexen().back();
  stores.emplace_back(std::move(root_store));

  std::vector<Pass*> passes = {
      new ResultPropagationPass(),
  };

  PassManager manager(passes);
  manager.set_testing_mode();

  Json::Value conf_obj = Json::nullValue;
  ConfigFiles dummy_cfg(conf_obj);
  manager.run_passes(stores, dummy_cfg);

  int num_test_classes = 0;
  const char* test_class_prefix = "Lcom/facebook/redextest/ResultPropagation$";
  const char* test_method_prefix = "returns_";
  for (const auto& cls : classes) {
    if (strncmp(cls->get_name()->c_str(), test_class_prefix,
                strlen(test_class_prefix)) == 0) {
      TRACE(RP, 1, "test class %s\n", cls->get_name()->c_str());
      num_test_classes++;
      int num_tests_in_class = 0;
      for (const auto& m : cls->get_vmethods()) {
        const auto method_name = m->get_name()->c_str();
        TRACE(RP, 1, " test method %s\n", method_name);
        EXPECT_EQ(strncmp(method_name, test_method_prefix,
                          strlen(test_method_prefix)),
                  0);
        const auto suffix = method_name + strlen(test_method_prefix);
        boost::optional<ParamIndex> expected;
        if (strcmp(suffix, "none") != 0) {
          expected = atoi(suffix);
        }

        IRCode* code = m->get_code();
        code->build_cfg(/* editable */ true);
        auto actual = find_return_param_index(code->cfg());
        code->clear_cfg();
        if (expected) {
          EXPECT_TRUE(actual);
          EXPECT_EQ(*actual, *expected);
        } else {
          EXPECT_FALSE(actual);
        }
        num_tests_in_class++;
      }
      EXPECT_EQ(num_tests_in_class, 1);
    }
  }
  EXPECT_EQ(num_test_classes, 6);
}