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; }
DexMethod* MethodCreator::make_static_from(DexString* name, DexProto* proto, DexMethod* meth, DexClass* target_cls) { assert(!(meth->get_access() & ACC_STATIC)); assert(!is_init(meth) && !is_clinit(meth)); auto smeth = DexMethod::make_method(target_cls->get_type(), name, proto); smeth->make_concrete( meth->get_access() | ACC_STATIC, std::move(meth->get_code()), false); target_cls->add_method(smeth); return smeth; }
DexMethod* MethodCreator::make_static_from(DexString* name, DexProto* proto, DexMethod* meth, DexClass* target_cls) { assert(!(meth->get_access() & ACC_STATIC)); assert(!is_init(meth) && !is_clinit(meth)); auto smeth = DexMethod::make_method(target_cls->get_type(), name, proto); smeth->make_concrete( meth->get_access() | ACC_STATIC, meth->get_code(), false); insert_sorted(target_cls->get_dmethods(), smeth, compare_dexmethods); meth->set_code(nullptr); return smeth; }
/* * There's no "good way" to differentiate blank vs. non-blank * finals. So, we just scan the code in the CL-init. If * it's sput there, then it's a blank. Lame, agreed, but functional. * */ void get_sput_in_clinit(DexClass* clazz, std::unordered_map<DexField*, bool>& blank_statics) { auto methods = clazz->get_dmethods(); for (auto method : methods) { if (is_clinit(method)) { always_assert_log(is_static(method) && is_constructor(method), "static constructor doesn't have the proper access bits set\n"); auto& code = method->get_code(); auto opcodes = code->get_instructions(); for (auto opcode : opcodes) { if (opcode->has_fields() && is_sput(opcode->opcode())) { auto fieldop = static_cast<DexOpcodeField*>(opcode); auto field = resolve_field(fieldop->field(), FieldSearch::Static); if (field == nullptr || !field->is_concrete()) continue; if (field->get_class() != clazz->get_type()) continue; blank_statics[field] = true; } } } } }