[veridex] Reflection detection improvements.
- Handle invoke range instructions.
- Implement parameter substitution.
bug: 77513322
Test: m
(cherry picked from commit 5de2ff26d448629082ffe3058a0a76fc38362daa)
Change-Id: Ib7bb1b3ff9b28f0ecfc8b338ef4cf08e5c9b159f
diff --git a/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc
index 736abb7..e2833bf 100644
--- a/tools/veridex/flow_analysis.cc
+++ b/tools/veridex/flow_analysis.cc
@@ -243,43 +243,7 @@
case Instruction::INVOKE_STATIC:
case Instruction::INVOKE_SUPER:
case Instruction::INVOKE_VIRTUAL: {
- VeriMethod method = resolver_->GetMethod(instruction.VRegB_35c());
- uint32_t args[5];
- instruction.GetVarArgs(args);
- if (method == VeriClass::forName_) {
- RegisterValue value = GetRegister(args[0]);
- last_result_ = RegisterValue(
- value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
- } else if (IsGetField(method)) {
- RegisterValue cls = GetRegister(args[0]);
- RegisterValue name = GetRegister(args[1]);
- field_uses_.push_back(std::make_pair(cls, name));
- last_result_ = GetReturnType(instruction.VRegB_35c());
- } else if (IsGetMethod(method)) {
- RegisterValue cls = GetRegister(args[0]);
- RegisterValue name = GetRegister(args[1]);
- method_uses_.push_back(std::make_pair(cls, name));
- last_result_ = GetReturnType(instruction.VRegB_35c());
- } else if (method == VeriClass::getClass_) {
- RegisterValue obj = GetRegister(args[0]);
- const VeriClass* cls = obj.GetType();
- if (cls != nullptr && cls->GetClassDef() != nullptr) {
- const DexFile::ClassDef* def = cls->GetClassDef();
- last_result_ = RegisterValue(
- RegisterSource::kClass,
- DexFileReference(&resolver_->GetDexFileOf(*cls), def->class_idx_.index_),
- VeriClass::class_);
- } else {
- last_result_ = RegisterValue(
- obj.GetSource(), obj.GetDexFileReference(), VeriClass::class_);
- }
- } else if (method == VeriClass::loadClass_) {
- RegisterValue value = GetRegister(args[1]);
- last_result_ = RegisterValue(
- value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
- } else {
- last_result_ = GetReturnType(instruction.VRegB_35c());
- }
+ last_result_ = AnalyzeInvoke(instruction, /* is_range */ false);
break;
}
@@ -288,7 +252,7 @@
case Instruction::INVOKE_STATIC_RANGE:
case Instruction::INVOKE_SUPER_RANGE:
case Instruction::INVOKE_VIRTUAL_RANGE: {
- last_result_ = GetReturnType(instruction.VRegB_3rc());
+ last_result_ = AnalyzeInvoke(instruction, /* is_range */ true);
break;
}
@@ -520,6 +484,7 @@
case Instruction::IPUT_BYTE:
case Instruction::IPUT_CHAR:
case Instruction::IPUT_SHORT: {
+ AnalyzeFieldSet(instruction);
break;
}
@@ -541,6 +506,7 @@
case Instruction::SPUT_BYTE:
case Instruction::SPUT_CHAR:
case Instruction::SPUT_SHORT: {
+ AnalyzeFieldSet(instruction);
break;
}
@@ -613,7 +579,112 @@
void VeriFlowAnalysis::Run() {
FindBranches();
+ uint32_t number_of_registers = code_item_accessor_.RegistersSize();
+ uint32_t number_of_parameters = code_item_accessor_.InsSize();
+ std::vector<RegisterValue>& initial_values = *dex_registers_[0].get();
+ for (uint32_t i = 0; i < number_of_parameters; ++i) {
+ initial_values[number_of_registers - number_of_parameters + i] = RegisterValue(
+ RegisterSource::kParameter,
+ i,
+ DexFileReference(&resolver_->GetDexFile(), method_id_),
+ nullptr);
+ }
AnalyzeCode();
}
+static uint32_t GetParameterAt(const Instruction& instruction,
+ bool is_range,
+ uint32_t* args,
+ uint32_t index) {
+ return is_range ? instruction.VRegC() + index : args[index];
+}
+
+RegisterValue FlowAnalysisCollector::AnalyzeInvoke(const Instruction& instruction, bool is_range) {
+ uint32_t id = is_range ? instruction.VRegB_3rc() : instruction.VRegB_35c();
+ VeriMethod method = resolver_->GetMethod(id);
+ uint32_t args[5];
+ if (!is_range) {
+ instruction.GetVarArgs(args);
+ }
+
+ if (method == VeriClass::forName_) {
+ // Class.forName. Fetch the first parameter.
+ RegisterValue value = GetRegister(GetParameterAt(instruction, is_range, args, 0));
+ return RegisterValue(
+ value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
+ } else if (IsGetField(method)) {
+ // Class.getField or Class.getDeclaredField. Fetch the first parameter for the class, and the
+ // second parameter for the field name.
+ RegisterValue cls = GetRegister(GetParameterAt(instruction, is_range, args, 0));
+ RegisterValue name = GetRegister(GetParameterAt(instruction, is_range, args, 1));
+ uses_.push_back(ReflectAccessInfo(cls, name, /* is_method */ false));
+ return GetReturnType(id);
+ } else if (IsGetMethod(method)) {
+ // Class.getMethod or Class.getDeclaredMethod. Fetch the first parameter for the class, and the
+ // second parameter for the field name.
+ RegisterValue cls = GetRegister(GetParameterAt(instruction, is_range, args, 0));
+ RegisterValue name = GetRegister(GetParameterAt(instruction, is_range, args, 1));
+ uses_.push_back(ReflectAccessInfo(cls, name, /* is_method */ true));
+ return GetReturnType(id);
+ } else if (method == VeriClass::getClass_) {
+ // Get the type of the first parameter.
+ RegisterValue obj = GetRegister(GetParameterAt(instruction, is_range, args, 0));
+ const VeriClass* cls = obj.GetType();
+ if (cls != nullptr && cls->GetClassDef() != nullptr) {
+ const DexFile::ClassDef* def = cls->GetClassDef();
+ return RegisterValue(
+ RegisterSource::kClass,
+ DexFileReference(&resolver_->GetDexFileOf(*cls), def->class_idx_.index_),
+ VeriClass::class_);
+ } else {
+ return RegisterValue(
+ obj.GetSource(), obj.GetDexFileReference(), VeriClass::class_);
+ }
+ } else if (method == VeriClass::loadClass_) {
+ // ClassLoader.loadClass. Fetch the first parameter.
+ RegisterValue value = GetRegister(GetParameterAt(instruction, is_range, args, 1));
+ return RegisterValue(
+ value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
+ } else {
+ // Return a RegisterValue referencing the method whose type is the return type
+ // of the method.
+ return GetReturnType(id);
+ }
+}
+
+void FlowAnalysisCollector::AnalyzeFieldSet(const Instruction& instruction ATTRIBUTE_UNUSED) {
+ // There are no fields that escape reflection uses.
+}
+
+RegisterValue FlowAnalysisSubstitutor::AnalyzeInvoke(const Instruction& instruction,
+ bool is_range) {
+ uint32_t id = is_range ? instruction.VRegB_3rc() : instruction.VRegB_35c();
+ MethodReference method(&resolver_->GetDexFile(), id);
+ // TODO: doesn't work for multidex
+ // TODO: doesn't work for overriding (but maybe should be done at a higher level);
+ if (accesses_.find(method) == accesses_.end()) {
+ return GetReturnType(id);
+ }
+ uint32_t args[5];
+ if (!is_range) {
+ instruction.GetVarArgs(args);
+ }
+ for (const ReflectAccessInfo& info : accesses_.at(method)) {
+ if (info.cls.IsParameter() || info.name.IsParameter()) {
+ RegisterValue cls = info.cls.IsParameter()
+ ? GetRegister(GetParameterAt(instruction, is_range, args, info.cls.GetParameterIndex()))
+ : info.cls;
+ RegisterValue name = info.name.IsParameter()
+ ? GetRegister(GetParameterAt(instruction, is_range, args, info.name.GetParameterIndex()))
+ : info.name;
+ uses_.push_back(ReflectAccessInfo(cls, name, info.is_method));
+ }
+ }
+ return GetReturnType(id);
+}
+
+void FlowAnalysisSubstitutor::AnalyzeFieldSet(const Instruction& instruction ATTRIBUTE_UNUSED) {
+ // TODO: analyze field sets.
+}
+
} // namespace art