Beispiel #1
0
 void exclude_referenced_bridgees() {
   walk_code(*m_scope,
             [](DexMethod*) { return true; },
             [&](DexMethod* m, DexCode& code) {
               exclude_referenced_bridgee(m, code);
             });
 }
Beispiel #2
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 #3
0
/**
 * Walks all the code of the app, finding classes that are reachable from
 * code.
 *
 * Note that as code is changed or removed by Redex, this information will
 * become stale, so this method should be called periodically, for example
 * after each pass.
 */
void recompute_classes_reachable_from_code(const Scope& scope) {
  for (auto clazz : scope) {
    clazz->rstate.clear_if_compute();
  }

  std::unordered_set<DexString*> maybetypes;
  walk_annotations(scope,
                   [&](DexAnnotation* anno) {
                     static DexType* dalviksig =
                         DexType::get_type("Ldalvik/annotation/Signature;");
                     // Signature annotations contain strings that Jackson uses
                     // to construct the underlying types.  We capture the
                     // full list here, and mark them later.  (There are many
                     // duplicates, so de-duping before we look it up as a class
                     // makes sense)
                     if (anno->type() == dalviksig) {
                       auto elems = anno->anno_elems();
                       for (auto const& elem : elems) {
                         auto ev = elem.encoded_value;
                         if (ev->evtype() != DEVT_ARRAY) continue;
                         auto arrayev = static_cast<DexEncodedValueArray*>(ev);
                         auto const& evs = arrayev->evalues();
                         for (auto strev : *evs) {
                           if (strev->evtype() != DEVT_STRING) continue;
                           auto stringev =
                               static_cast<DexEncodedValueString*>(strev);
                           maybetypes.insert((DexString*)stringev->string());
                         }
                       }
                       return;
                     }
                     // Class literals in annotations.
                     //
                     // Example:
                     //    @JsonDeserialize(using=MyJsonDeserializer.class)
                     //                                   ^^^^
                     if (anno->runtime_visible()) {
                       auto elems = anno->anno_elems();
                       for (auto const& dae : elems) {
                         auto evalue = dae.encoded_value;
                         std::vector<DexType*> ltype;
                         evalue->gather_types(ltype);
                         if (ltype.size()) {
                           for (auto dextype : ltype) {
                             mark_reachable_directly(dextype);
                           }
                         }
                       }
                     }
                   });

  // Now we process the strings that were in the signature
  // annotations.
  // Note: We do not mark these as ref'd by string, because
  // these cases are handleable for renaming.
  for (auto dstring : maybetypes) {
    const char* cstr = dstring->c_str();
    int len = strlen(cstr);
    if (len < 3) continue;
    if (cstr[0] != 'L') continue;
    if (cstr[len - 1] == ';') {
      auto dtype = DexType::get_type(dstring);
      mark_reachable_directly(dtype);
      continue;
    }
    std::string buf(cstr);
    buf += ';';
    auto dtype = DexType::get_type(buf.c_str());
    mark_reachable_directly(dtype);
  }

  // Matches methods marked as native
  walk_methods(scope,
               [&](DexMethod* meth) {
                 if (meth->get_access() & DexAccessFlags::ACC_NATIVE) {
                   mark_reachable_by_classname(meth->get_class(), true);
                 }
               });

  walk_code(scope,
            [](DexMethod*) { return true; },
            [&](DexMethod* meth, DexCode* code) {
              auto opcodes = code->get_instructions();
              for (const auto& opcode : opcodes) {
                // Matches any stringref that name-aliases a type.
                if (opcode->has_strings()) {
                  auto stringop = static_cast<DexOpcodeString*>(opcode);
                  DexString* dsclzref = stringop->get_string();
                  DexType* dtexclude =
                      get_dextype_from_dotname(dsclzref->c_str());
                  if (dtexclude == nullptr) continue;
                  mark_reachable_by_classname(dtexclude, true);
                }
                if (opcode->has_types()) {
                  // Matches the following instructions (from most to least
                  // common):
                  // check-cast, new-instance, const-class, instance-of
                  // new-instance should not be on this list, and
                  // we should not allow these to operate on themselves.
                  // TODO(snay/dalves)
                  auto typeop = static_cast<DexOpcodeType*>(opcode);
                  mark_reachable_directly(typeop->get_type());
                }
              }
            });
}