[veridex] Reflective usage detection improvements.
- Convert a string name to the internal name
- Recognize ClassLoader.loadClass.
- Do a dummy merge in VeriFlow by just overwriting registers.
bug: 77513322
Test: m
(cherry picked from commit 295cba006e5212c06fde5ec956c81c507b2974e6)
Change-Id: I888ff742197f4aec9aee68a03daca84f165e4114
diff --git a/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc
index abd0b9b..a4553f9 100644
--- a/tools/veridex/flow_analysis.cc
+++ b/tools/veridex/flow_analysis.cc
@@ -41,7 +41,11 @@
bool VeriFlowAnalysis::MergeRegisterValues(uint32_t dex_pc) {
// TODO: Do the merging. Right now, just return that we should continue
// the iteration if the instruction has not been visited.
- return !instruction_infos_[dex_pc].has_been_visited;
+ if (!instruction_infos_[dex_pc].has_been_visited) {
+ dex_registers_[dex_pc]->assign(current_registers_.begin(), current_registers_.end());
+ return true;
+ }
+ return false;
}
void VeriFlowAnalysis::SetVisited(uint32_t dex_pc) {
@@ -260,6 +264,10 @@
RegisterValue obj = GetRegister(args[0]);
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());
}
diff --git a/tools/veridex/flow_analysis.h b/tools/veridex/flow_analysis.h
index c065fb8..80ae5fc 100644
--- a/tools/veridex/flow_analysis.h
+++ b/tools/veridex/flow_analysis.h
@@ -20,6 +20,7 @@
#include "dex/code_item_accessors.h"
#include "dex/dex_file_reference.h"
#include "dex/method_reference.h"
+#include "hidden_api.h"
#include "veridex.h"
namespace art {
@@ -52,10 +53,19 @@
DexFileReference GetDexFileReference() const { return reference_; }
const VeriClass* GetType() const { return type_; }
- const char* ToString() const {
+ std::string ToString() const {
switch (source_) {
- case RegisterSource::kString:
- return reference_.dex_file->StringDataByIdx(dex::StringIndex(reference_.index));
+ case RegisterSource::kString: {
+ const char* str = reference_.dex_file->StringDataByIdx(dex::StringIndex(reference_.index));
+ if (type_ == VeriClass::class_) {
+ // Class names at the Java level are of the form x.y.z, but the list encodes
+ // them of the form Lx/y/z;. Inner classes have '$' for both Java level class
+ // names in strings, and hidden API lists.
+ return HiddenApi::ToInternalName(str);
+ } else {
+ return str;
+ }
+ }
case RegisterSource::kClass:
return reference_.dex_file->StringByTypeIdx(dex::TypeIndex(reference_.index));
default:
diff --git a/tools/veridex/hidden_api.h b/tools/veridex/hidden_api.h
index 4c67768..b1c8559 100644
--- a/tools/veridex/hidden_api.h
+++ b/tools/veridex/hidden_api.h
@@ -63,6 +63,12 @@
return HiddenApi::GetApiMethodName(*ref.dex_file, ref.index);
}
+ static std::string ToInternalName(const std::string& str) {
+ std::string val = str;
+ std::replace(val.begin(), val.end(), '.', '/');
+ return "L" + val + ";";
+ }
+
private:
static bool IsInList(const std::string& name, const std::set<std::string>& list) {
return list.find(name) != list.end();
diff --git a/tools/veridex/hidden_api_finder.cc b/tools/veridex/hidden_api_finder.cc
index b9be618..b1ae7dd 100644
--- a/tools/veridex/hidden_api_finder.cc
+++ b/tools/veridex/hidden_api_finder.cc
@@ -95,9 +95,7 @@
// Class names at the Java level are of the form x.y.z, but the list encodes
// them of the form Lx/y/z;. Inner classes have '$' for both Java level class
// names in strings, and hidden API lists.
- std::string str = name;
- std::replace(str.begin(), str.end(), '.', '/');
- str = "L" + str + ";";
+ std::string str = HiddenApi::ToInternalName(name);
// Note: we can query the lists directly, as HiddenApi added classes that own
// private methods and fields in them.
// We don't add class names to the `strings_` set as we know method/field names
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index 6e72faa..dc7ea94 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -52,6 +52,7 @@
// Will be set after boot classpath has been resolved.
VeriClass* VeriClass::object_ = nullptr;
VeriClass* VeriClass::class_ = nullptr;
+VeriClass* VeriClass::class_loader_ = nullptr;
VeriClass* VeriClass::string_ = nullptr;
VeriClass* VeriClass::throwable_ = nullptr;
VeriMethod VeriClass::forName_ = nullptr;
@@ -60,6 +61,7 @@
VeriMethod VeriClass::getMethod_ = nullptr;
VeriMethod VeriClass::getDeclaredMethod_ = nullptr;
VeriMethod VeriClass::getClass_ = nullptr;
+VeriMethod VeriClass::loadClass_ = nullptr;
struct VeridexOptions {
const char* dex_file = nullptr;
@@ -176,6 +178,7 @@
// methods.
VeriClass::object_ = type_map["Ljava/lang/Object;"];
VeriClass::class_ = type_map["Ljava/lang/Class;"];
+ VeriClass::class_loader_ = type_map["Ljava/lang/ClassLoader;"];
VeriClass::string_ = type_map["Ljava/lang/String;"];
VeriClass::throwable_ = type_map["Ljava/lang/Throwable;"];
VeriClass::forName_ = boot_resolvers[0]->LookupDeclaredMethodIn(
@@ -194,6 +197,8 @@
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
VeriClass::getClass_ = boot_resolvers[0]->LookupDeclaredMethodIn(
*VeriClass::object_, "getClass", "()Ljava/lang/Class;");
+ VeriClass::loadClass_ = boot_resolvers[0]->LookupDeclaredMethodIn(
+ *VeriClass::class_loader_, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
std::vector<std::unique_ptr<VeridexResolver>> app_resolvers;
Resolve(app_dex_files, resolver_map, type_map, &app_resolvers);
diff --git a/tools/veridex/veridex.h b/tools/veridex/veridex.h
index 75e4845..9c0a158 100644
--- a/tools/veridex/veridex.h
+++ b/tools/veridex/veridex.h
@@ -65,6 +65,7 @@
static VeriClass* object_;
static VeriClass* class_;
+ static VeriClass* class_loader_;
static VeriClass* string_;
static VeriClass* throwable_;
static VeriClass* boolean_;
@@ -83,6 +84,7 @@
static VeriMethod getMethod_;
static VeriMethod getDeclaredMethod_;
static VeriMethod getClass_;
+ static VeriMethod loadClass_;
private:
Primitive::Type kind_;