Beispiel #1
0
DexField* resolve_field(
    const DexType* owner,
    const DexString* name,
    const DexType* type,
    FieldSearch fs) {
  auto field_eq =
      [&](const DexField* a) {
        return a->get_name() == name && a->get_type() == type;
      };

  const DexClass* cls = type_class(owner);
  while (cls) {
    if (fs == FieldSearch::Instance || fs == FieldSearch::Any) {
      for (auto ifield : cls->get_ifields()) {
        if (field_eq(ifield)) {
          return ifield;
        }
      }
    }
    if (fs == FieldSearch::Static || fs == FieldSearch::Any) {
      for (auto sfield : cls->get_sfields()) {
        if (field_eq(sfield)) {
          return sfield;
        }
      }
    }
    cls = type_class(cls->get_super_class());
  }
  return nullptr;
}
Beispiel #2
0
std::vector<const DexMethod*> select_from(const VirtualScope* scope,
                                          const DexType* type) {
  std::vector<const DexMethod*> refined_scope;
  std::unordered_map<const DexType*, DexMethod*> non_child_methods;
  bool found_root_method = false;
  for (const auto& method : scope->methods) {
    if (check_cast(method.first->get_class(), type)) {
      found_root_method =
          found_root_method || type == method.first->get_class();
      refined_scope.emplace_back(method.first);
    } else {
      non_child_methods[method.first->get_class()] = method.first;
    }
  }
  if (!found_root_method) {
    auto cls = type_class(type);
    while (cls != nullptr) {
      const auto super = cls->get_super_class();
      const auto& meth = non_child_methods.find(super);
      if (meth != non_child_methods.end()) {
        refined_scope.emplace_back(meth->second);
        return refined_scope;
      }
      cls = type_class(super);
    }
  }
  return refined_scope;
}
Beispiel #3
0
void unmark_keep(const Scope& scope,
                 const std::vector<std::string>& package_list,
                 const std::vector<std::string>& supercls_list) {
  if (package_list.size() == 0 && supercls_list.size() == 0) {
    return;
  }
  std::unordered_set<const DexType*> superclasses;
  std::unordered_set<const DexType*> interface_list;
  for (auto& cls_name : supercls_list) {
    const DexType* supercls_type = DexType::get_type(cls_name);
    if (supercls_type) {
      DexClass* supercls = type_class(supercls_type);
      if (supercls && is_interface(supercls)) {
        interface_list.emplace(supercls_type);
      } else {
        superclasses.emplace(supercls_type);
      }
    }
  }
  TypeSystem ts(scope);
  // Unmark proguard keep rule for interface implementors like
  // "-keep class * extend xxx".
  for (const DexType* intf_type : interface_list) {
    for (const DexType* implementor : ts.get_implementors(intf_type)) {
      DexClass* implementor_cls = type_class(implementor);
      if (implementor_cls) {
        implementor_cls->rstate.force_unset_allowshrinking();
      }
    }
  }
  walk::parallel::classes(
      scope, [&ts, &superclasses, &package_list](DexClass* cls) {
        // Unmark proguard keep rule for classes under path from package list.
        for (const auto& package : package_list) {
          if (strstr(cls->get_name()->c_str(), package.c_str()) != nullptr) {
            cls->rstate.force_unset_allowshrinking();
            return;
          }
        }
        if (!is_interface(cls)) {
          // Unmark proguard keep for classes that extend class from superclass
          // list for proguard keep rule like "-keep class * extend xxx".
          const auto& parents_chain = ts.parent_chain(cls->get_type());
          if (parents_chain.size() <= 2) {
            // The class's direct super class is java.lang.Object, no need
            // to proceed.
            return;
          }
          // We only need to find class started at the second of parents_chain
          // because first is java.lang.Object, and end at second to last,
          // because last one is itself.
          for (uint32_t index = 1; index < parents_chain.size() - 1; ++index) {
            if (superclasses.find(parents_chain[index]) != superclasses.end()) {
              cls->rstate.force_unset_allowshrinking();
              return;
            }
          }
        }
      });
}
Beispiel #4
0
/**
 * The callee contains an invoke to a virtual method we either do not know
 * or it's not public. Given the caller may not be in the same
 * hierarchy/package we cannot inline it unless we make the method public.
 * But we need to make all methods public across the hierarchy and for methods
 * we don't know we have no idea whether the method was public or not anyway.
 */
bool MultiMethodInliner::unknown_virtual(DexInstruction* insn, DexMethod* context) {
  if (insn->opcode() == OPCODE_INVOKE_VIRTUAL ||
      insn->opcode() == OPCODE_INVOKE_VIRTUAL_RANGE) {
    auto method = static_cast<DexOpcodeMethod*>(insn)->get_method();
    auto res_method = resolver(method, MethodSearch::Virtual);
    if (res_method == nullptr) {
      // if it's not known to redex but it's a common java/android API method
      if (method_ok(method->get_class(), method)) {
        return false;
      }
      auto type = method->get_class();
      if (type_ok(type)) return false;

      // the method ref is bound to a type known to redex but the method does
      // not exist in the hierarchy known to redex. Essentially the method
      // is from an external type i.e. A.equals(Object)
      auto cls = type_class(type);
      while (cls != nullptr) {
        type = cls->get_super_class();
        cls = type_class(type);
      }
      if (type_ok(type)) return false;
      if (method_ok(type, method)) return false;
      assert(track(method));
      info.escaped_virtual++;
      return true;
    }
    if (res_method->is_external() && !is_public(res_method)) {
      info.non_pub_virtual++;
      return true;
    }
  }
  return false;
}
Beispiel #5
0
const std::vector<DexMethod*>& get_vmethods(const DexType* type) {
  const DexClass* cls = type_class(type);
  if (cls == nullptr) {
    always_assert_log(
        type == get_object_type(), "Unknown type %s\n", SHOW(type));
    create_object_class();
    cls = type_class(type);
  }
  return cls->get_vmethods();
}
Beispiel #6
0
void relocate_method(DexMethod* method, DexType* to_type) {
  auto from_cls = type_class(method->get_class());
  auto to_cls = type_class(to_type);
  from_cls->remove_method(method);
  DexMethodSpec spec;
  spec.cls = to_type;
  method->change(spec,
                 true /* rename on collision */,
                 true /* update deobfuscated name */);
  to_cls->add_method(method);
}
Beispiel #7
0
bool is_assignable_to(const DexType* child, const DexType* parent) {
  // Check class hierarchy
  auto super = child;
  while (super != nullptr) {
    if (parent == super) return true;
    const auto cls = type_class(super);
    if (cls == nullptr) break;
    super = cls->get_super_class();
  }
  // Check interface hierarchy
  DexClass* parent_cls = type_class(parent);
  return parent_cls &&
    is_interface(parent_cls) &&
    is_assignable_to_interface(child, parent);
}
Beispiel #8
0
/**
 * Return whether the method is in an Enum class.
 * Enum methods are invoked in different magic ways and should never
 * be removed.
 */
bool MultiMethodInliner::is_enum_method(DexMethod* callee) {
  if (type_class(callee->get_class())->get_super_class() == get_enum_type()) {
    info.enum_callee++;
    return true;
  }
  return false;
}
Beispiel #9
0
size_t delete_methods(
    std::vector<DexClass*>& scope, std::unordered_set<DexMethod*>& removable,
    std::function<DexMethod*(DexMethod*, MethodSearch search)> resolver) {

  // if a removable candidate is invoked do not delete
  walk_opcodes(scope, [](DexMethod* meth) { return true; },
      [&](DexMethod* meth, DexInstruction* insn) {
        if (is_invoke(insn->opcode())) {
          const auto mop = static_cast<DexOpcodeMethod*>(insn);
          auto callee = resolver(mop->get_method(), opcode_to_search(insn));
          if (callee != nullptr) {
            removable.erase(callee);
          }
        }
      });

  size_t deleted = 0;
  for (auto callee : removable) {
    if (!callee->is_concrete()) continue;
    if (do_not_strip(callee)) continue;
    auto cls = type_class(callee->get_class());
    always_assert_log(cls != nullptr,
        "%s is concrete but does not have a DexClass\n",
        SHOW(callee));
    if (callee->is_virtual()) {
      cls->get_vmethods().remove(callee);
    } else {
      cls->get_dmethods().remove(callee);
    }
    deleted++;
    TRACE(DELMET, 4, "removing %s\n", SHOW(callee));
  }
  return deleted;
}
/*
 * Check that analyze_enum_clinit returns the correct enum field -> ordinal
 * mapping.
 */
TEST_F(RedexTest, OrdinalAnalysis) {
  always_assert(load_class_file(std::getenv("enum_class_file")));

  auto dexfile = std::getenv("dexfile");
  std::vector<DexStore> stores;
  DexMetadata dm;
  dm.set_id("classes");
  DexStore root_store(dm);
  root_store.add_classes(load_classes_from_dex(dexfile));
  auto scope = build_class_scope(root_store.get_dexen());

  auto enumA = type_class(DexType::get_type(ENUM_A));
  auto enum_field_to_ordinal = optimize_enums::analyze_enum_clinit(enumA);
  auto enumA_zero = static_cast<DexField*>(
      DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_0:Lcom/"
                          "facebook/redextest/EnumA;"));
  auto enumA_one = static_cast<DexField*>(
      DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_1:Lcom/"
                          "facebook/redextest/EnumA;"));
  auto enumA_two = static_cast<DexField*>(
      DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_2:Lcom/"
                          "facebook/redextest/EnumA;"));
  EXPECT_EQ(enum_field_to_ordinal.at(enumA_zero), 0);
  EXPECT_EQ(enum_field_to_ordinal.at(enumA_one), 1);
  EXPECT_EQ(enum_field_to_ordinal.at(enumA_two), 2);
}
Beispiel #11
0
DexMethod* find_collision_excepting(const DexMethod* except,
                                    const DexString* name,
                                    const DexProto* proto,
                                    const DexClass* cls,
                                    bool is_virtual,
                                    bool check_direct) {
  for (auto& method : cls->get_dmethods()) {
    if (match(name, proto, method) && method != except) return method;
  }
  for (auto& method : cls->get_vmethods()) {
    if (match(name, proto, method) && method != except) return method;
  }
  if (!is_virtual) return nullptr;

  auto super = type_class(cls->get_super_class());
  if (super) {
    auto method = resolve_virtual(super, name, proto);
    if (method && method != except) return method;
  }

  TypeVector children;
  get_all_children(cls->get_type(), children);
  for (const auto& child : children) {
    auto vmethod = check_vmethods(name, proto, child);
    if (vmethod && vmethod != except) return vmethod;
    if (check_direct) {
      auto dmethod = check_dmethods(name, proto, child);
      if (dmethod && dmethod != except) return dmethod;
    }
  }
  return nullptr;
}
Beispiel #12
0
std::unique_ptr<intraprocedural::FixpointIterator> analyze_procedure(
    const DexMethod* method,
    const WholeProgramState& wps,
    ArgumentDomain args) {
  always_assert(method->get_code() != nullptr);
  auto& code = *method->get_code();
  // Currently, our callgraph does not include calls to non-devirtualizable
  // virtual methods. So those methods may appear unreachable despite being
  // reachable.
  if (args.is_bottom()) {
    args.set_to_top();
  } else if (!args.is_top()) {
    TRACE(ICONSTP, 3, "Have args for %s: %s\n", SHOW(method), SHOW(args));
  }

  auto env = env_with_params(&code, args);
  DexType* class_under_init{nullptr};
  if (is_clinit(method)) {
    class_under_init = method->get_class();
    set_encoded_values(type_class(class_under_init), &env);
  }
  TRACE(ICONSTP, 5, "%s\n", SHOW(code.cfg()));

  auto intra_cp = std::make_unique<intraprocedural::FixpointIterator>(
      code.cfg(),
      CombinedAnalyzer(class_under_init,
                       &wps,
                       EnumFieldAnalyzerState(),
                       BoxedBooleanAnalyzerState(),
                       nullptr));
  intra_cp->run(env);

  return intra_cp;
}
Beispiel #13
0
DexClass* LevelChecker::get_outer_class(const DexClass* cls) {
  const std::string& cls_name = cls->get_deobfuscated_name();
  auto cash_idx = cls_name.find_last_of('$');
  if (cash_idx == std::string::npos) {
    // this is not an inner class
    return nullptr;
  }
  auto slash_idx = cls_name.find_last_of('/');
  if (slash_idx == std::string::npos || slash_idx < cash_idx) {
    // there's a $ in the class name
    const std::string& outer_name = cls_name.substr(0, cash_idx) + ';';
    DexType* outer = DexType::get_type(outer_name);
    if (outer == nullptr) {
      TRACE(MMINL, 4, "Can't find outer class! %s -> %s\n", cls_name.c_str(),
            outer_name.c_str());
      return nullptr;
    }
    DexClass* outer_cls = type_class(outer);
    if (cls == nullptr) {
      TRACE(MMINL, 4, "outer class %s is external?\n", SHOW(outer));
      return nullptr;
    }
    return outer_cls;
  }
  return nullptr;
}
Beispiel #14
0
DexMethod* resolve_method(
    const DexClass* cls, const DexString* name,
    const DexProto* proto, MethodSearch search) {
  while (cls) {
    if (search == MethodSearch::Virtual || search == MethodSearch::Any) {
      for (auto& vmeth : cls->get_vmethods()) {
        if (match(name, proto, vmeth)) {
          return vmeth;
        }
      }
    }
    if (search == MethodSearch::Direct || search == MethodSearch::Static
        || search == MethodSearch::Any) {
      for (auto& dmeth : cls->get_dmethods()) {
        if (match(name, proto, dmeth)) {
          return dmeth;
        }
      }
    }
    // direct methods only look up the given class
    cls = search != MethodSearch::Direct ? type_class(cls->get_super_class())
        : nullptr;
  }
  return nullptr;
}
Beispiel #15
0
/**
 * Remove annotation classes that are marked explicitly with a removable
 * annotation (specified as "kill_annos" in config).  Facebook uses these to
 * remove DI binding annotations.
 */
void kill_annotation_classes(
  Scope& scope,
  const std::unordered_set<DexType*>& kill_annos
) {
  // Determine which annotation classes are removable.
  class_set_t bannotations;
  for (auto clazz : scope) {
    if (!(clazz->get_access() & DexAccessFlags::ACC_ANNOTATION)) continue;
    auto aset = clazz->get_anno_set();
    if (aset == nullptr) continue;
    auto& annos = aset->get_annotations();
    for (auto anno : annos) {
      if (kill_annos.count(anno->type())) {
        bannotations.insert(clazz);
        TRACE(CLASSKILL, 5, "removable annotation class %s\n",
              SHOW(clazz->get_type()));
      }
    }
  }

  // Annotation classes referenced explicitly can't be removed.
  walk_code(
    scope,
    [](DexMethod*) { return true; },
    [&](DexMethod* meth, DexCode* code) {
      auto opcodes = code->get_instructions();
      for (const auto& opcode : opcodes) {
        if (opcode->has_types()) {
          auto typeop = static_cast<DexOpcodeType*>(opcode);
          auto dtexclude = typeop->get_type();
          DexClass* exclude = type_class(dtexclude);
          if (exclude != nullptr && bannotations.count(exclude)) {
            bannotations.erase(exclude);
          }
        }
      }
    });

  // Do the removal.
  int annotations_removed_count = 0;
  if (bannotations.size()) {
    // We have some annotations we can kill.  First let's clear all annotation
    // references to the classes.
    annotations_removed_count =
        clear_annotation_references(scope, bannotations);
    scope.erase(
      std::remove_if(
        scope.begin(), scope.end(),
        [&](DexClass* cls) { return bannotations.count(cls); }),
      scope.end());
  }
  TRACE(CLASSKILL, 1,
          "Annotation classes removed %lu\n",
          bannotations.size());
  TRACE(CLASSKILL, 1,
          "Method param annotations removed %d\n",
          annotations_removed_count);
}
Beispiel #16
0
/**
 * Change the visibility of members accessed in a callee as they are moved
 * to the caller context.
 * We make everything public but we could be more precise and only
 * relax visibility as needed.
 */
void MultiMethodInliner::change_visibility(DexMethod* callee) {
  TRACE(MMINL, 6, "checking visibility usage of members in %s\n",
      SHOW(callee));
  for (auto insn : callee->get_code()->get_instructions()) {
    if (insn->has_fields()) {
      auto fop = static_cast<DexOpcodeField*>(insn);
      auto field = fop->field();
      field = resolve_field(field, is_sfield_op(insn->opcode())
          ? FieldSearch::Static : FieldSearch::Instance);
      if (field != nullptr && field->is_concrete()) {
        TRACE(MMINL, 6, "changing visibility of %s.%s %s\n",
            SHOW(field->get_class()), SHOW(field->get_name()),
            SHOW(field->get_type()));
        set_public(field);
        set_public(type_class(field->get_class()));
        fop->rewrite_field(field);
      }
      continue;
    }
    if (insn->has_methods()) {
      auto mop = static_cast<DexOpcodeMethod*>(insn);
      auto method = mop->get_method();
      method = resolver(method, opcode_to_search(insn));
      if (method != nullptr && method->is_concrete()) {
        TRACE(MMINL, 6, "changing visibility of %s.%s: %s\n",
            SHOW(method->get_class()), SHOW(method->get_name()),
            SHOW(method->get_proto()));
        set_public(method);
        set_public(type_class(method->get_class()));
        mop->rewrite_method(method);
      }
      continue;
    }
    if (insn->has_types()) {
      auto type = static_cast<DexOpcodeType*>(insn)->get_type();
      auto cls = type_class(type);
      if (cls != nullptr && !cls->is_external()) {
        TRACE(MMINL, 6, "changing visibility of %s\n", SHOW(type));
        set_public(cls);
      }
      continue;
    }
  }
}
Beispiel #17
0
bool is_subclass(const DexType* parent, const DexType* child) {
  auto super = child;
  while (super != nullptr) {
    if (parent == super) return true;
    const auto cls = type_class(super);
    if (cls == nullptr) break;
    super = cls->get_super_class();
  }
  return false;
}
Beispiel #18
0
int show_to(var self, var out, int pos) {
  
  if (not type_implements(type_of(self), Show)) {
    return print_to(out, 0, "<'%s' At 0x%p>", type_of(self), self);
  } else {
    Show* ishow = type_class(type_of(self), Show);
    return ishow->show(self, out, pos);
  }
  
}
Beispiel #19
0
bool check_cast(const DexType* type, const DexType* base_type) {
  if (type == base_type) return true;
  const auto cls = type_class(type);
  if (cls == nullptr) return false;
  if (check_cast(cls->get_super_class(), base_type)) return true;
  auto intfs = cls->get_interfaces();
  for (auto intf : intfs->get_type_list()) {
    if (check_cast(intf, base_type)) return true;
  }
  return false;
}
Beispiel #20
0
/**
 * Builds the ClassScope for type and children.
 * Calling with get_object_type() builds the ClassScope
 * for the entire system as redex knows it.
 */
void ClassScopes::build_class_scopes(const DexType* type) {
  auto cls = type_class(type);
  always_assert(cls != nullptr || type == get_object_type());
  get_root_scopes(m_sig_map, type, m_scopes);

  const auto& children_it = m_hierarchy.find(type);
  if (children_it != m_hierarchy.end()) {
    for (const auto& child : children_it->second) {
      build_class_scopes(child);
    }
  }
}
Beispiel #21
0
bool is_assignable_to_interface(const DexType* type, const DexType* iface) {
  if (type == iface) return true;
  auto cls = type_class(type);
  if (cls) {
    for (auto extends : cls->get_interfaces()->get_type_list()) {
      if (is_assignable_to_interface(extends, iface)) {
        return true;
      }
    }
  }
  return false;
}
Beispiel #22
0
DexClass* create_class(const DexType* type,
                       const DexType* super_type,
                       const std::string& pkg_name,
                       std::vector<DexField*> fields,
                       const TypeSet& interfaces,
                       bool with_default_ctor,
                       DexAccessFlags access) {
  DexType* t = const_cast<DexType*>(type);
  always_assert(!pkg_name.empty());
  auto name = std::string(type->get_name()->c_str());
  name = pkg_name + "/" + name.substr(1);
  t->set_name(DexString::make_string(name));
  // Create class.
  ClassCreator creator(t);
  creator.set_access(access);
  always_assert(super_type != nullptr);
  creator.set_super(const_cast<DexType*>(super_type));
  for (const auto& itf : interfaces) {
    creator.add_interface(const_cast<DexType*>(itf));
  }
  for (const auto& field : fields) {
    creator.add_field(field);
  }
  auto cls = creator.create();
  // Keeping type-erasure generated classes from being renamed.
  cls->rstate.set_keep_name();

  if (!with_default_ctor) {
    return cls;
  }
  // Create ctor.
  auto super_ctors = type_class(super_type)->get_ctors();
  for (auto super_ctor : super_ctors) {
    auto mc = new MethodCreator(t,
                                DexString::make_string("<init>"),
                                super_ctor->get_proto(),
                                ACC_PUBLIC | ACC_CONSTRUCTOR);
    // Call to super.<init>
    std::vector<Location> args;
    size_t args_size = super_ctor->get_proto()->get_args()->size();
    for (size_t arg_loc = 0; arg_loc < args_size + 1; ++arg_loc) {
      args.push_back(mc->get_local(arg_loc));
    }
    auto mb = mc->get_main_block();
    mb->invoke(OPCODE_INVOKE_DIRECT, super_ctor, args);
    mb->ret_void();
    auto ctor = mc->create();
    TRACE(TERA, 4, " default ctor created %s\n", SHOW(ctor));
    cls->add_method(ctor);
  }
  return cls;
}
Beispiel #23
0
/**
 * In some limited cases we can do type erasure on an interface when
 * implementors of the interface only implement that interface and have no
 * parent class other than java.lang.Object. We create a base class for those
 * implementors and use the new base class as root, and proceed with type
 * erasure as usual.
 */
void handle_interface_as_root(ModelSpec& spec,
                              Scope& scope,
                              DexStoresVector& stores) {
  TypeSet interface_roots;
  for (const auto root : spec.roots) {
    if (is_interface(type_class(root))) {
      interface_roots.insert(root);
    }
  }

  for (const auto interface_root : interface_roots) {
    auto empty_base =
        create_empty_base_type(spec, interface_root, scope, stores);
    if (empty_base != nullptr) {
      TRACE(TERA, 3, "Changing the root from %s to %s.\n", SHOW(interface_root),
            SHOW(empty_base));
      spec.roots.insert(empty_base);
      add_class(type_class(empty_base), scope, stores);
    }
    // Remove interface roots regardless of whether an empty base was added.
    spec.roots.erase(interface_root);
  }
}
Beispiel #24
0
void LevelChecker::init_method(DexMethod* method) {
  int32_t method_level = get_level(method);
  if (method_level == -1) {
    DexClass* cls = type_class(method->get_class());
    if (cls == nullptr) {
      method_level = s_min_level;
    } else {
      method_level = cls->rstate.get_api_level();
      always_assert(method_level != -1);
    }
  }

  method->rstate.set_api_level(method_level);
}
Beispiel #25
0
void change_visibility(DexMethod* method) {
  auto code = method->get_code();
  always_assert(code != nullptr);

  editable_cfg_adapter::iterate(code, [](MethodItemEntry& mie) {
    auto insn = mie.insn;

    if (insn->has_field()) {
      auto cls = type_class(insn->get_field()->get_class());
      if (cls != nullptr && !cls->is_external()) {
        set_public(cls);
      }
      auto field =
          resolve_field(insn->get_field(), is_sfield_op(insn->opcode())
              ? FieldSearch::Static : FieldSearch::Instance);
      if (field != nullptr && field->is_concrete()) {
        set_public(field);
        set_public(type_class(field->get_class()));
        // FIXME no point in rewriting opcodes in the method
        insn->set_field(field);
      }
    } else if (insn->has_method()) {
      auto cls = type_class(insn->get_method()->get_class());
      if (cls != nullptr && !cls->is_external()) {
        set_public(cls);
      }
      auto current_method = resolve_method(
          insn->get_method(), opcode_to_search(insn));
      if (current_method != nullptr && current_method->is_concrete()) {
        set_public(current_method);
        set_public(type_class(current_method->get_class()));
        // FIXME no point in rewriting opcodes in the method
        insn->set_method(current_method);
      }
    } else if (insn->has_type()) {
      auto type = insn->get_type();
      auto cls = type_class(type);
      if (cls != nullptr && !cls->is_external()) {
        set_public(cls);
      }
    }
    return editable_cfg_adapter::LOOP_CONTINUE;
  });

  std::vector<DexType*> types;
  if (code->editable_cfg_built()) {
    code->cfg().gather_catch_types(types);
  } else {
    code->gather_catch_types(types);
  }
  for (auto type : types) {
    auto cls = type_class(type);
    if (cls != nullptr && !cls->is_external()) {
      set_public(cls);
    }
  }
}
Beispiel #26
0
/**
 * Check collisions in method definition.
 */
EscapeReason OptimizationImpl::check_method_collision(DexType* intf,
                                                      SingleImplData& data) {
  for (auto method : data.methoddefs) {
    auto meth_it = new_methods.find(method);
    if (meth_it != new_methods.end()) method = meth_it->second;
    auto proto = get_or_make_proto(intf, data.cls, method->get_proto());
    assert(proto != method->get_proto());
    DexMethod* collision = find_collision(method->get_name(),
                                          proto,
                                          type_class(method->get_class()),
                                          method->is_virtual());
    if (collision) return SIG_COLLISION;
  }
  return NO_ESCAPE;
}
Beispiel #27
0
 void delete_unused_bridgees() {
   for (auto bpair : m_bridges_to_bridgees) {
     auto bridge = bpair.first;
     auto bridgee = bpair.second;
     always_assert_log(bridge->is_virtual(),
                       "bridge: %s\nbridgee: %s",
                       SHOW(bridge),
                       SHOW(bridgee));
     // TODO: Bridgee won't necessarily be direct once we expand this
     // optimization
     assert(!bridgee->is_virtual());
     auto cls = type_class(bridgee->get_class());
     cls->get_dmethods().remove(bridgee);
   }
 }
Beispiel #28
0
/* Allocate space for type, set type entry */
var allocate(var type) {
  type = cast(type, Type);
  
  New* inew = type_class(type, New);
 
  var self;
  if (inew->size <= sizeof(ObjectData)) {
    self = NULL;
  } else {
    self = calloc(1, inew->size);
    if (self == NULL) { throw(OutOfMemoryError, "Cannot create new '%s', out of memory!", type); }
    ((ObjectData*)self)->type = type;
  }
  
  return self;
}
Beispiel #29
0
int clear_annotation_references(Scope& scope, class_set_t& deadclasses) {
  /*
   * These annotations show in up method parameter annotations,
   * but they are still unused.  We have to visit all the
   * method param annotations and remove them.
   */
  int cleared_annos = 0;
  walk_methods(
    scope,
    [&](DexMethod* method) {
      /* Parameter annotations... */
      auto pas = method->get_param_anno();
      if (pas == nullptr) return;
      bool clear_pas = true;
      for (auto pa : *pas) {
        DexAnnotationSet* aset = pa.second;
        if (aset->size() == 0) continue;
        auto& annos = aset->get_annotations();
        auto iter = annos.begin();
        while (iter != annos.end()) {
          auto tokill = iter;
          DexAnnotation* da = *iter++;
          DexClass* clazz = type_class(da->type());
          if (deadclasses.count(clazz)) {
            annos.erase(tokill);
            delete da;
          }
        }
        if (aset->size() != 0) {
          clear_pas = false;
        }
      }
      if (clear_pas) {
        for (auto pa : *pas) {
          delete pa.second;
        }
        pas->clear();
        cleared_annos++;
        TRACE(CLASSKILL,
              5,
              "Cleared parameter annotations for method %s\n",
              SHOW(method));
      }
    });
  return cleared_annos;
}
Beispiel #30
0
/**
 * Rewrite all methods sigs by creating new ones. Remove old methods and push
 * the new to the proper class method list.
 */
void OptimizationImpl::set_method_defs(DexType* intf,
                                       SingleImplData& data) {
  for (auto method : data.methoddefs) {
    TRACE(INTF, 3, "(MDEF) %s\n", SHOW(method));
    auto meth = method;
    auto meth_it = new_methods.find(meth);
    if (meth_it != new_methods.end()) {
      // if a method rewrite existed it must not be on a single impl
      // given we have escaped to next pass all collisions
      always_assert(meth_it->second->is_def());
      meth = static_cast<DexMethod*>(meth_it->second);
      TRACE(INTF, 4, "(MDEF) current: %s\n", SHOW(meth));
      assert(!single_impls->is_single_impl(method->get_class()) ||
             single_impls->is_escaped(method->get_class()));
      assert(!single_impls->is_single_impl(meth->get_class()) ||
             single_impls->is_escaped(meth->get_class()));
    }
    auto proto = get_or_make_proto(intf, data.cls, meth->get_proto());
    TRACE(INTF,
          5,
          "(MDEF) make_method: %s.%s - %s => %s\n",
          SHOW(meth->get_class()),
          SHOW(meth->get_name()),
          SHOW(meth->get_proto()),
          SHOW(proto));
    assert(proto != meth->get_proto());
    auto new_meth = static_cast<DexMethod*>(DexMethod::make_method(
        meth->get_class(), meth->get_name(), proto));
    // new_meth may have already existed in RedexContext, so
    // we need to make sure it isn't concrete.
    // TODO: this is horrible. After we remove methods, we shouldn't
    // have these zombies lying around.
    new_meth->clear_annotations();
    new_meth->make_non_concrete();
    new_meth->set_deobfuscated_name(meth->get_deobfuscated_name());
    new_meth->rstate = meth->rstate;
    assert(new_meth != meth);
    setup_method(meth, new_meth);
    new_methods[method] = new_meth;
    auto owner = type_class(new_meth->get_class());
    owner->remove_method(meth);
    owner->add_method(new_meth);
    TRACE(INTF, 3, "(MDEF)\t=> %s\n", SHOW(new_meth));
  }
}