Example #1
0
void init_seed_classes(const std::string seeds_filename) {
    TRACE(PGR, 1, "Reading seed classes from %s\n", seeds_filename.c_str());
    auto start = std::chrono::high_resolution_clock::now();
    std::ifstream seeds_file(seeds_filename);
    uint count = 0;
    if (!seeds_file) {
      TRACE(PGR, 1, "Seeds file %s was not found (ignoring error).",
          seeds_filename.c_str());
    } else {
      std::string line;
      while (getline(seeds_file, line)) {
        if (line.find(":") == std::string::npos && line.find("$") ==
            std::string::npos) {
          auto dex_type = get_dextype_from_dotname(line.c_str());
          if (dex_type != nullptr) {
            mark_reachable_by_seed(dex_type);
            count++;
          } else {
            TRACE(PGR, 2,
                "Seed file contains class for which "
                "Dex type can't be found: %s\n",
                line.c_str());
          }
        }
      }
      seeds_file.close();
    }
    auto end = std::chrono::high_resolution_clock::now();
    TRACE(PGR, 1, "Read %d seed classes in %.1lf seconds\n", count,
          std::chrono::duration<double>(end - start).count());
}
Example #2
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());
                }
              }
            });
}