예제 #1
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;
}
예제 #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;
}
예제 #3
0
파일: DexUtil.cpp 프로젝트: facebook/redex
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;
}
예제 #4
0
파일: DexUtil.cpp 프로젝트: facebook/redex
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;
}
예제 #5
0
파일: Match.cpp 프로젝트: JoelMarcey/redex
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);
}
예제 #6
0
파일: Class.cpp 프로젝트: dacut/juliet
Field* Class::lookup_field_recursive(const String* name, const String* desc)
{
    // Step 1: lookup in self
    Field* field = lookup_field(name, desc);
    if(field) return field;

    // Step 2: lookup in direct superinterfaces recursively
    for(uint16 in = 0; in < m_num_superinterfaces; in++) {
        field = get_superinterface(in)->lookup_field_recursive(name, desc);
        if(field) return field;
    }

    // Step 3: lookup in super classes recursively
    if(has_super_class()) {
        field = get_super_class()->lookup_field_recursive(name, desc);
    }

    return field;
} // Class::lookup_field_recursive
예제 #7
0
// Can "other_clss" access the field or method "member"?
bool Class::can_access_member(Class_Member *member)
{
    Class* member_clss = member->get_class();
    // check access permissions
    if(member->is_public() || (this == member_clss)) {
        // no problemo
        return true;
    } else if(member->is_private()) {
        // IllegalAccessError
        return false;
    } else if(member->is_protected()) {
        // When a member is protected, it can be accessed by classes
        // in the same runtime package
        if(m_package == member_clss->m_package)
            return true;
        // Otherwise, when this class is not in the same package,
        // the class containing the member (member_clss) must be
        // a superclass of this class
        // ppervov: FIXME: this can be made a method of struct Class
        // smth. like:
        //if(!is_extending_class(member_clss)) {
        //    // IllegalAccessError
        //    return false;
        //}
        //return true;
        Class* c;
        for(c = get_super_class(); c != NULL; c = c->get_super_class()) {
            if(c == member_clss)
                break;
        }
        if(c == NULL) {
            // IllegalAccessError
            return false;
        }
        return true;
    } else {
        // When a member has default (or package private) access,
        // it can only be accessed by classes in the same package
        if(m_package == member_clss->m_package)
            return true;
        return false;
    }
} // Class::can_access_member
예제 #8
0
파일: Class.cpp 프로젝트: dacut/juliet
bool Class::load_ancestors(Global_Env* env)
{
    m_state = ST_LoadingAncestors;

    const String* superName = get_super_class_name();

    if(superName == NULL) {
        if(env->InBootstrap() || get_name() != env->JavaLangClass_String) {
            // This class better be java.lang.Object
            if(get_name() != env->JavaLangObject_String) {
                // ClassFormatError
                std::stringstream ss;
                ss << get_name()->bytes
                    << ": class does not have superclass "
                    << "but the class is not java.lang.Object";
                REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
                    "java/lang/ClassFormatError", ss.str().c_str());
                return false;
            }
        }
    } else {
        // Load super class
        Class* superClass;
        m_super_class.name = NULL;
        superClass = m_class_loader->LoadVerifyAndPrepareClass(env, superName);
        if(superClass == NULL) {
            assert(exn_raised());
            return false;
        }

        if(superClass->is_interface()) {
            REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
                "java/lang/IncompatibleClassChangeError",
                "class " << m_name->bytes << " has interface "
                << superClass->get_name()->bytes << " as super class");
            return false;
        }
        if(superClass->is_final()) {
            REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
                "java/lang/VerifyError",
                m_name->bytes << " cannot inherit from final class "
                << superClass->get_name()->bytes);
            return false;
        }

        // super class was successfully loaded
        m_super_class.clss = superClass;
        if(m_super_class.cp_index) {
            m_const_pool.resolve_entry(m_super_class.cp_index, superClass);
        }

        // if it's an interface, its superclass must be java/lang/Object
        if(is_interface()) {
            if((env->JavaLangObject_Class != NULL) && (superClass != env->JavaLangObject_Class)) {
                std::stringstream ss;
                ss << get_name()->bytes << ": interface superclass is not java.lang.Object";
                REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
                    "java/lang/ClassFormatError", ss.str().c_str());
                return false;
            }
        }

        // Update the cha_first_child and cha_next_sibling fields.
        m_cha_first_child = NULL;
        if(has_super_class())
        {
            m_cha_next_sibling = get_super_class()->m_cha_first_child;
            get_super_class()->m_cha_first_child = this;
        }
    }

    //
    // load in super interfaces
    //
    for(unsigned i = 0; i < m_num_superinterfaces; i++ ) {
        const String* intfc_name = m_superinterfaces[i].name;
        Class* intfc = m_class_loader->LoadVerifyAndPrepareClass(env, intfc_name);
        if(intfc == NULL) {
            assert(exn_raised());
            return false;
        }
        if(!intfc->is_interface()) {
            REPORT_FAILED_CLASS_CLASS(m_class_loader, this,
                "java/lang/IncompatibleClassChangeError",
                get_name()->bytes << ": " << intfc->get_name()->bytes
                << " is not an interface");
            return false;
        }

        // superinterface was successfully loaded
        m_superinterfaces[i].clss = intfc;
        if(m_superinterfaces[i].cp_index != 0) {
            // there are no constant pool entries for array classes
            m_const_pool.resolve_entry(m_superinterfaces[i].cp_index, intfc);
        }
    }
    // class, superclass, and superinterfaces successfully loaded

    m_state = ST_Loaded;
    if(!is_array())
        m_package = m_class_loader->ProvidePackage(env, m_name, NULL);

    return true;
}
예제 #9
0
파일: Bridge.cpp 프로젝트: dutao-88/redex
  void search_hierarchy_for_matches(DexMethod* bridge, DexMethod* bridgee) {
    /*
     * Direct reference.  The only one if it's non-virtual.
     */
    auto clstype = bridgee->get_class();
    auto name = bridgee->get_name();
    auto proto = bridgee->get_proto();
    TRACE(BRIDGE, 5, "   %s %s %s\n", SHOW(clstype), SHOW(name), SHOW(proto));
    m_potential_bridgee_refs.emplace(MethodRef(clstype, name, proto), bridge);
    if (!bridgee->is_virtual()) return;

    /*
     * Search super classes
     *
     *   A bridge method in a derived class may be referred to using the name
     *   of a super class if a method with a matching signature is defined in
     *   that super class.
     *
     *   To build the set of potential matches, we accumulate potential refs in
     *   maybe_refs, and when we find a matching signature in a super class, we
     *   add everything in maybe_refs to the set.
     */
    std::vector<std::pair<MethodRef, DexMethod*>> maybe_refs;
    for (auto super = type_class(type_class(clstype)->get_super_class());
         super != nullptr;
         super = type_class(super->get_super_class())) {
      maybe_refs.emplace_back(
          MethodRef(super->get_type(), name, proto), bridge);
      for (auto vmethod : super->get_vmethods()) {
        if (signature_matches(bridgee, vmethod)) {
          for (auto DEBUG_ONLY refp : maybe_refs) {
            TRACE(BRIDGE,
                  5,
                  "    %s %s %s\n",
                  SHOW(std::get<0>(refp.first)),
                  SHOW(std::get<1>(refp.first)),
                  SHOW(std::get<2>(refp.first)));
          }
          m_potential_bridgee_refs.insert(maybe_refs.begin(), maybe_refs.end());
          maybe_refs.clear();
        }
      }
    }

    /*
     * Search sub classes
     *
     *   Easy.  Any subclass can refer to the bridgee.
     */
    TypeVector subclasses;
    get_all_children(clstype, subclasses);
    for (auto subclass : subclasses) {
      m_potential_bridgee_refs.emplace(MethodRef(subclass, name, proto),
                                       bridge);
      TRACE(BRIDGE,
            5,
            "    %s %s %s\n",
            SHOW(subclass),
            SHOW(name),
            SHOW(proto));
    }
  }