diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/Android.mk | 2 | ||||
| -rw-r--r-- | tools/art_verifier/Android.bp | 48 | ||||
| -rw-r--r-- | tools/art_verifier/art_verifier.cc | 267 | ||||
| -rw-r--r-- | tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java | 9 | ||||
| -rw-r--r-- | tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java | 137 | ||||
| -rw-r--r-- | tools/hiddenapi/hiddenapi.cc | 154 | ||||
| -rw-r--r-- | tools/jfuzz/jfuzz.cc | 2 | ||||
| -rw-r--r-- | tools/libcore_gcstress_debug_failures.txt | 3 | ||||
| -rw-r--r-- | tools/libcore_gcstress_failures.txt | 34 | ||||
| -rwxr-xr-x | tools/run-libcore-tests.sh | 6 | ||||
| -rw-r--r-- | tools/veridex/flow_analysis.cc | 8 | ||||
| -rw-r--r-- | tools/veridex/flow_analysis.h | 16 | ||||
| -rw-r--r-- | tools/veridex/hidden_api_finder.cc | 42 | ||||
| -rw-r--r-- | tools/veridex/precise_hidden_api_finder.cc | 37 | ||||
| -rw-r--r-- | tools/veridex/precise_hidden_api_finder.h | 2 | ||||
| -rw-r--r-- | tools/veridex/resolver.cc | 91 |
16 files changed, 682 insertions, 176 deletions
diff --git a/tools/Android.mk b/tools/Android.mk index 9ecf0cd7ed..e90f5f5b45 100644 --- a/tools/Android.mk +++ b/tools/Android.mk @@ -32,3 +32,5 @@ LOCAL_MODULE := art-script LOCAL_SRC_FILES := art LOCAL_MODULE_STEM := art include $(BUILD_PREBUILT) + +include $(LOCAL_PATH)/class2greylist/test/Android.mk diff --git a/tools/art_verifier/Android.bp b/tools/art_verifier/Android.bp new file mode 100644 index 0000000000..afd52fbcaa --- /dev/null +++ b/tools/art_verifier/Android.bp @@ -0,0 +1,48 @@ +// +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +art_cc_defaults { + name: "art_verifier-defaults", + defaults: ["art_defaults"], + host_supported: true, + srcs: [ + "art_verifier.cc", + ], + header_libs: [ + "art_cmdlineparser_headers", + ], + static_libs: art_static_dependencies + [ + "libart", + "libartbase", + "libdexfile", + "libprofile", + ], + target: { + android: { + static_libs: [ + "libtombstoned_client_static", + ], + }, + darwin: { + enabled: false, + }, + }, +} + +art_cc_binary { + name: "art_verifier", + defaults: ["art_verifier-defaults"], +} diff --git a/tools/art_verifier/art_verifier.cc b/tools/art_verifier/art_verifier.cc new file mode 100644 index 0000000000..fc62410889 --- /dev/null +++ b/tools/art_verifier/art_verifier.cc @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string> +#include <vector> + +#include "android-base/logging.h" + +#include "base/logging.h" +#include "base/os.h" +#include "class_linker-inl.h" +#include "dex/art_dex_file_loader.h" +#include "dex/class_accessor-inl.h" +#include "dex/dex_file-inl.h" +#include "interpreter/unstarted_runtime.h" +#include "mirror/class-inl.h" +#include "mirror/dex_cache-inl.h" +#include "runtime.h" +#include "scoped_thread_state_change-inl.h" +#include "verifier/method_verifier.h" +#include "well_known_classes.h" + +#include <sys/stat.h> +#include "cmdline.h" + +namespace art { + +namespace { + +bool LoadDexFile(const std::string& dex_filename, + std::vector<std::unique_ptr<const DexFile>>* dex_files) { + const ArtDexFileLoader dex_file_loader; + std::string error_msg; + if (!dex_file_loader.Open(dex_filename.c_str(), + dex_filename.c_str(), + /* verify */ true, + /* verify_checksum */ true, + &error_msg, + dex_files)) { + LOG(ERROR) << error_msg; + return false; + } + return true; +} + +jobject Install(Runtime* runtime, + std::vector<std::unique_ptr<const DexFile>>& in, + std::vector<const DexFile*>* out) + REQUIRES_SHARED(Locks::mutator_lock_) { + Thread* self = Thread::Current(); + CHECK(self != nullptr); + + // Need well-known-classes. + WellKnownClasses::Init(self->GetJniEnv()); + // Need a class loader. Fake that we're a compiler. + // Note: this will run initializers through the unstarted runtime, so make sure it's + // initialized. + interpreter::UnstartedRuntime::Initialize(); + + for (std::unique_ptr<const DexFile>& dex_file : in) { + out->push_back(dex_file.release()); + } + + ClassLinker* class_linker = runtime->GetClassLinker(); + + jobject class_loader = class_linker->CreatePathClassLoader(self, *out); + + // Need to register dex files to get a working dex cache. + for (const DexFile* dex_file : *out) { + ObjPtr<mirror::DexCache> dex_cache = class_linker->RegisterDexFile( + *dex_file, self->DecodeJObject(class_loader)->AsClassLoader()); + CHECK(dex_cache != nullptr); + } + + return class_loader; +} + +struct MethodVerifierArgs : public CmdlineArgs { + protected: + using Base = CmdlineArgs; + + virtual ParseStatus ParseCustom(const StringPiece& option, + std::string* error_msg) OVERRIDE { + { + ParseStatus base_parse = Base::ParseCustom(option, error_msg); + if (base_parse != kParseUnknownArgument) { + return base_parse; + } + } + + if (option.starts_with("--dex-file=")) { + dex_filename_ = option.substr(strlen("--dex-file=")).data(); + } else if (option == "--dex-file-verifier") { + dex_file_verifier_ = true; + } else if (option == "--verbose") { + method_verifier_verbose_ = true; + } else if (option == "--verbose-debug") { + method_verifier_verbose_debug_ = true; + } else if (option.starts_with("--repetitions=")) { + char* end; + repetitions_ = strtoul(option.substr(strlen("--repetitions=")).data(), &end, 10); + } else { + return kParseUnknownArgument; + } + + return kParseOk; + } + + virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE { + // Perform the parent checks. + ParseStatus parent_checks = Base::ParseChecks(error_msg); + if (parent_checks != kParseOk) { + return parent_checks; + } + + // Perform our own checks. + if (dex_filename_ == nullptr) { + *error_msg = "--dex-filename not set"; + return kParseError; + } + + return kParseOk; + } + + virtual std::string GetUsage() const { + std::string usage; + + usage += + "Usage: method_verifier_cmd [options] ...\n" + // Dex file is required. + " --dex-file=<file.dex>: specifies an input dex file.\n" + " Example: --dex-file=app.apk\n" + " --dex-file-verifier: only run dex file verifier.\n" + " --verbose: use verbose verifier mode.\n" + " --verbose-debug: use verbose verifier debug mode.\n" + " --repetitions=<count>: repeat the verification count times.\n" + "\n"; + + usage += Base::GetUsage(); + + return usage; + } + + public: + const char* dex_filename_ = nullptr; + + bool dex_file_verifier_ = false; + + bool method_verifier_verbose_ = false; + bool method_verifier_verbose_debug_ = false; + + size_t repetitions_ = 0u; +}; + +struct MethodVerifierMain : public CmdlineMain<MethodVerifierArgs> { + bool NeedsRuntime() OVERRIDE { + return true; + } + + bool ExecuteWithoutRuntime() OVERRIDE { + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); + } + + bool ExecuteWithRuntime(Runtime* runtime) OVERRIDE { + CHECK(args_ != nullptr); + + const size_t dex_reps = args_->dex_file_verifier_ + // If we're focused on the dex file verifier, use the + // repetitions parameter. + ? std::max(static_cast<size_t>(1u), args_->repetitions_) + // Otherwise just load the dex files once. + : 1; + + std::vector<std::unique_ptr<const DexFile>> unique_dex_files; + for (size_t i = 0; i != dex_reps; ++i) { + if (args_->dex_file_verifier_ && args_->repetitions_ != 0) { + LOG(INFO) << "Repetition " << (i + 1); + } + unique_dex_files.clear(); + if (!LoadDexFile(args_->dex_filename_, &unique_dex_files)) { + return false; + } + } + if (args_->dex_file_verifier_) { + // We're done here. + return true; + } + + ScopedObjectAccess soa(Thread::Current()); + std::vector<const DexFile*> dex_files; + jobject class_loader = Install(runtime, unique_dex_files, &dex_files); + CHECK(class_loader != nullptr); + + StackHandleScope<2> scope(soa.Self()); + Handle<mirror::ClassLoader> h_loader = scope.NewHandle( + soa.Decode<mirror::ClassLoader>(class_loader)); + MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr)); + + if (args_->method_verifier_verbose_) { + gLogVerbosity.verifier = true; + } + if (args_->method_verifier_verbose_debug_) { + gLogVerbosity.verifier_debug = true; + } + + const size_t verifier_reps = std::max(static_cast<size_t>(1u), args_->repetitions_); + + ClassLinker* class_linker = runtime->GetClassLinker(); + for (size_t i = 0; i != verifier_reps; ++i) { + if (args_->repetitions_ != 0) { + LOG(INFO) << "Repetition " << (i + 1); + } + for (const DexFile* dex_file : dex_files) { + for (ClassAccessor accessor : dex_file->GetClasses()) { + const char* descriptor = accessor.GetDescriptor(); + h_klass.Assign(class_linker->FindClass(soa.Self(), descriptor, h_loader)); + if (h_klass == nullptr || h_klass->IsErroneous()) { + if (args_->repetitions_ == 0) { + LOG(ERROR) << "Warning: could not load " << descriptor; + } + soa.Self()->ClearException(); + continue; + } + std::string error_msg; + verifier::FailureKind res = + verifier::MethodVerifier::VerifyClass(soa.Self(), + h_klass.Get(), + runtime->GetCompilerCallbacks(), + true, + verifier::HardFailLogMode::kLogWarning, + &error_msg); + if (args_->repetitions_ == 0) { + LOG(INFO) << descriptor << ": " << res << " " << error_msg; + } + } + } + } + + return true; + } +}; + +} // namespace + +} // namespace art + +int main(int argc, char** argv) { + // Output all logging to stderr. + android::base::SetLogger(android::base::StderrLogger); + + art::MethodVerifierMain main; + return main.Main(argc, argv); +} diff --git a/tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java b/tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java index 66857525aa..6b9ef161eb 100644 --- a/tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java +++ b/tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java @@ -81,14 +81,19 @@ public class AnnotationVisitor extends EmptyVisitor { mStatus.debug("Visit member %s : %s", member.getName(), member.getSignature()); for (AnnotationEntry a : member.getAnnotationEntries()) { if (mAnnotationType.equals(a.getAnnotationType())) { - mStatus.debug("Method has annotation %s", mAnnotationType); + mStatus.debug("Member has annotation %s", mAnnotationType); + boolean bridge = (member.getAccessFlags() & Const.ACC_BRIDGE) != 0; + if (bridge) { + mStatus.debug("Member is a bridge", mAnnotationType); + } String signature = String.format(Locale.US, signatureFormatString, getClassDescriptor(definingClass), member.getName(), member.getSignature()); for (ElementValuePair property : a.getElementValuePairs()) { switch (property.getNameString()) { case EXPECTED_SIGNATURE: String expected = property.getValue().stringifyValue(); - if (!signature.equals(expected)) { + // Don't enforce for bridge methods; they're generated so won't match. + if (!bridge && !signature.equals(expected)) { error(definingClass, member, "Expected signature does not match generated:\n" + "Expected: %s\n" diff --git a/tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java b/tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java index 2d9721803c..a4ad20c605 100644 --- a/tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java +++ b/tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java @@ -19,20 +19,22 @@ package com.android.javac; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; +import static org.mockito.Mockito.withSettings; -import com.android.class2greylist.Status; import com.android.class2greylist.AnnotationVisitor; +import com.android.class2greylist.Status; import com.google.common.base.Joiner; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestName; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import java.io.IOException; @@ -40,13 +42,17 @@ public class AnnotationVisitorTest { private static final String ANNOTATION = "Lannotation/Anno;"; + @Rule + public TestName mTestName = new TestName(); + private Javac mJavac; - @Mock private Status mStatus; @Before public void setup() throws IOException { - initMocks(this); + System.out.println(String.format("\n============== STARTING TEST: %s ==============\n", + mTestName.getMethodName())); + mStatus = mock(Status.class, withSettings().verboseLogging()); mJavac = new Javac(); mJavac.addSource("annotation.Anno", Joiner.on('\n').join( "package annotation;", @@ -199,4 +205,125 @@ public class AnnotationVisitorTest { verify(mStatus, never()).greylistEntry(any(String.class)); } + @Test + public void testMethodArgGenerics() throws IOException { + mJavac.addSource("a.b.Class", Joiner.on('\n').join( + "package a.b;", + "import annotation.Anno;", + "public class Class<T extends String> {", + " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")", + " public void method(T arg) {}", + "}")); + assertThat(mJavac.compile()).isTrue(); + + new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus) + .visit(); + + assertNoErrors(); + ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); + verify(mStatus, times(1)).greylistEntry(greylist.capture()); + assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method(Ljava/lang/String;)V"); + } + + @Test + public void testOverrideMethodWithBridge() throws IOException { + mJavac.addSource("a.b.Base", Joiner.on('\n').join( + "package a.b;", + "abstract class Base<T> {", + " protected abstract void method(T arg);", + "}")); + + mJavac.addSource("a.b.Class", Joiner.on('\n').join( + "package a.b;", + "import annotation.Anno;", + "public class Class<T extends String> extends Base<T> {", + " @Override", + " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")", + " public void method(T arg) {}", + "}")); + assertThat(mJavac.compile()).isTrue(); + + new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), ANNOTATION, mStatus) + .visit(); + new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus) + .visit(); + + assertNoErrors(); + ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); + // A bridge method is generated for the above, so we expect 2 greylist entries. + verify(mStatus, times(2)).greylistEntry(greylist.capture()); + assertThat(greylist.getAllValues()).containsExactly( + "La/b/Class;->method(Ljava/lang/Object;)V", + "La/b/Class;->method(Ljava/lang/String;)V"); + } + + @Test + public void testOverridePublicMethodWithBridge() throws IOException { + mJavac.addSource("a.b.Base", Joiner.on('\n').join( + "package a.b;", + "public abstract class Base<T> {", + " public void method(T arg) {}", + "}")); + + mJavac.addSource("a.b.Class", Joiner.on('\n').join( + "package a.b;", + "import annotation.Anno;", + "public class Class<T extends String> extends Base<T> {", + " @Override", + " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")", + " public void method(T arg) {}", + "}")); + assertThat(mJavac.compile()).isTrue(); + + new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), ANNOTATION, mStatus) + .visit(); + new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus) + .visit(); + + assertNoErrors(); + ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); + // A bridge method is generated for the above, so we expect 2 greylist entries. + verify(mStatus, times(2)).greylistEntry(greylist.capture()); + assertThat(greylist.getAllValues()).containsExactly( + "La/b/Class;->method(Ljava/lang/Object;)V", + "La/b/Class;->method(Ljava/lang/String;)V"); + } + + @Test + public void testBridgeMethodsFromInterface() throws IOException { + mJavac.addSource("a.b.Interface", Joiner.on('\n').join( + "package a.b;", + "public interface Interface {", + " public void method(Object arg);", + "}")); + + mJavac.addSource("a.b.Base", Joiner.on('\n').join( + "package a.b;", + "import annotation.Anno;", + "class Base {", + " @Anno(expectedSignature=\"La/b/Base;->method(Ljava/lang/Object;)V\")", + " public void method(Object arg) {}", + "}")); + + mJavac.addSource("a.b.Class", Joiner.on('\n').join( + "package a.b;", + "public class Class extends Base implements Interface {", + "}")); + assertThat(mJavac.compile()).isTrue(); + + new AnnotationVisitor( + mJavac.getCompiledClass("a.b.Interface"), ANNOTATION, mStatus).visit(); + new AnnotationVisitor( + mJavac.getCompiledClass("a.b.Base"), ANNOTATION, mStatus).visit(); + new AnnotationVisitor( + mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus).visit(); + + assertNoErrors(); + ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); + // A bridge method is generated for the above, so we expect 2 greylist entries. + verify(mStatus, times(2)).greylistEntry(greylist.capture()); + assertThat(greylist.getAllValues()).containsExactly( + "La/b/Class;->method(Ljava/lang/Object;)V", + "La/b/Base;->method(Ljava/lang/Object;)V"); + } } diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc index 0381381bbf..e4bec060f2 100644 --- a/tools/hiddenapi/hiddenapi.cc +++ b/tools/hiddenapi/hiddenapi.cc @@ -75,7 +75,9 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(""); UsageError(" Command \"list\": dump lists of public and private API"); UsageError(" --boot-dex=<filename>: dex file which belongs to boot class path"); - UsageError(" --stub-dex=<filename>: dex/apk file which belongs to SDK API stubs"); + UsageError(" --stub-classpath=<filenames>: colon-separated list of dex/apk files"); + UsageError(" which form API stubs of boot class path. Multiple classpaths can"); + UsageError(" be specified"); UsageError(""); UsageError(" --out-public=<filename>: output file for a list of all public APIs"); UsageError(" --out-private=<filename>: output file for a list of all private APIs"); @@ -121,7 +123,7 @@ class DexClass { return list; } - inline bool IsVisible() const { return HasAccessFlags(kAccPublic); } + inline bool IsPublic() const { return HasAccessFlags(kAccPublic); } inline bool Equals(const DexClass& other) const { bool equals = GetDescriptor() == other.GetDescriptor(); @@ -178,11 +180,10 @@ class DexMember { inline bool IsMethod() const { return it_.IsAtMethod(); } inline bool IsVirtualMethod() const { return it_.IsAtVirtualMethod(); } + inline bool IsConstructor() const { return IsMethod() && HasAccessFlags(kAccConstructor); } - // Returns true if the member is public/protected and is in a public class. - inline bool IsVisible() const { - return GetDeclaringClass().IsVisible() && - (HasAccessFlags(kAccPublic) || HasAccessFlags(kAccProtected)); + inline bool IsPublicOrProtected() const { + return HasAccessFlags(kAccPublic) || HasAccessFlags(kAccProtected); } // Constructs a string with a unique signature of this class member. @@ -344,6 +345,24 @@ class HierarchyClass FINAL { return ForEachResolvableMember_Impl(other, fn) != ResolutionResult::kNotFound; } + // Returns true if this class contains at least one member matching `other`. + bool HasMatchingMember(const DexMember& other) { + return ForEachMatchingMember( + other, [](const DexMember&) { return true; }) != ResolutionResult::kNotFound; + } + + // Recursively iterates over all subclasses of this class and invokes `fn` + // on each one. If `fn` returns false for a particular subclass, exploring its + // subclasses is skipped. + template<typename Fn> + void ForEachSubClass(Fn fn) { + for (HierarchyClass* subclass : extended_by_) { + if (fn(subclass)) { + subclass->ForEachSubClass(fn); + } + } + } + private: // Result of resolution which takes into account whether the member was found // for the first time or not. This is just a performance optimization to prevent @@ -438,7 +457,7 @@ class HierarchyClass FINAL { class Hierarchy FINAL { public: - explicit Hierarchy(ClassPath& class_path) : class_path_(class_path) { + explicit Hierarchy(ClassPath& classpath) : classpath_(classpath) { BuildClassHierarchy(); } @@ -454,6 +473,48 @@ class Hierarchy FINAL { return (klass != nullptr) && klass->ForEachResolvableMember(other, fn); } + // Returns true if `member`, which belongs to this classpath, is visible to + // code in child class loaders. + bool IsMemberVisible(const DexMember& member) { + if (!member.IsPublicOrProtected()) { + // Member is private or package-private. Cannot be visible. + return false; + } else if (member.GetDeclaringClass().IsPublic()) { + // Member is public or protected, and class is public. It must be visible. + return true; + } else if (member.IsConstructor()) { + // Member is public or protected constructor and class is not public. + // Must be hidden because it cannot be implicitly exposed by a subclass. + return false; + } else { + // Member is public or protected method, but class is not public. Check if + // it is exposed through a public subclass. + // Example code (`foo` exposed by ClassB): + // class ClassA { public void foo() { ... } } + // public class ClassB extends ClassA {} + HierarchyClass* klass = FindClass(member.GetDeclaringClass().GetDescriptor()); + CHECK(klass != nullptr); + bool visible = false; + klass->ForEachSubClass([&visible, &member](HierarchyClass* subclass) { + if (subclass->HasMatchingMember(member)) { + // There is a member which matches `member` in `subclass`, either + // a virtual method overriding `member` or a field overshadowing + // `member`. In either case, `member` remains hidden. + CHECK(member.IsVirtualMethod() || !member.IsMethod()); + return false; // do not explore deeper + } else if (subclass->GetOneDexClass().IsPublic()) { + // `subclass` inherits and exposes `member`. + visible = true; + return false; // do not explore deeper + } else { + // `subclass` inherits `member` but does not expose it. + return true; // explore deeper + } + }); + return visible; + } + } + private: HierarchyClass* FindClass(const std::string& descriptor) { auto it = classes_.find(descriptor); @@ -467,7 +528,7 @@ class Hierarchy FINAL { void BuildClassHierarchy() { // Create one HierarchyClass entry in `classes_` per class descriptor // and add all DexClass objects with the same descriptor to that entry. - class_path_.ForEachDexClass([this](DexClass& klass) { + classpath_.ForEachDexClass([this](DexClass& klass) { classes_[klass.GetDescriptor()].AddDexClass(klass); }); @@ -494,7 +555,7 @@ class Hierarchy FINAL { } } - ClassPath& class_path_; + ClassPath& classpath_; std::map<std::string, HierarchyClass> classes_; }; @@ -547,8 +608,9 @@ class HiddenApi FINAL { const StringPiece option(argv[i]); if (option.starts_with("--boot-dex=")) { boot_dex_paths_.push_back(option.substr(strlen("--boot-dex=")).ToString()); - } else if (option.starts_with("--stub-dex=")) { - stub_dex_paths_.push_back(option.substr(strlen("--stub-dex=")).ToString()); + } else if (option.starts_with("--stub-classpath=")) { + stub_classpaths_.push_back(android::base::Split( + option.substr(strlen("--stub-classpath=")).ToString(), ":")); } else if (option.starts_with("--out-public=")) { out_public_path_ = option.substr(strlen("--out-public=")).ToString(); } else if (option.starts_with("--out-private=")) { @@ -578,10 +640,10 @@ class HiddenApi FINAL { OpenApiFile(blacklist_path_, api_list, HiddenApiAccessFlags::kBlacklist); // Open all dex files. - ClassPath boot_class_path(boot_dex_paths_, /* open_writable */ true); + ClassPath boot_classpath(boot_dex_paths_, /* open_writable */ true); // Set access flags of all members. - boot_class_path.ForEachDexMember([&api_list](DexMember& boot_member) { + boot_classpath.ForEachDexMember([&api_list](DexMember& boot_member) { auto it = api_list.find(boot_member.GetApiEntry()); if (it == api_list.end()) { boot_member.SetHidden(HiddenApiAccessFlags::kWhitelist); @@ -590,7 +652,7 @@ class HiddenApi FINAL { } }); - boot_class_path.UpdateDexChecksums(); + boot_classpath.UpdateDexChecksums(); } void OpenApiFile(const std::string& path, @@ -614,7 +676,7 @@ class HiddenApi FINAL { void ListApi() { if (boot_dex_paths_.empty()) { Usage("No boot DEX files specified"); - } else if (stub_dex_paths_.empty()) { + } else if (stub_classpaths_.empty()) { Usage("No stub DEX files specified"); } else if (out_public_path_.empty()) { Usage("No public API output path specified"); @@ -630,39 +692,42 @@ class HiddenApi FINAL { std::set<std::string> unresolved; // Open all dex files. - ClassPath stub_class_path(stub_dex_paths_, /* open_writable */ false); - ClassPath boot_class_path(boot_dex_paths_, /* open_writable */ false); - Hierarchy boot_hierarchy(boot_class_path); + ClassPath boot_classpath(boot_dex_paths_, /* open_writable */ false); + Hierarchy boot_hierarchy(boot_classpath); // Mark all boot dex members private. - boot_class_path.ForEachDexMember([&boot_members](DexMember& boot_member) { + boot_classpath.ForEachDexMember([&boot_members](DexMember& boot_member) { boot_members[boot_member.GetApiEntry()] = false; }); // Resolve each SDK dex member against the framework and mark it white. - stub_class_path.ForEachDexMember( - [&boot_hierarchy, &boot_members, &unresolved](DexMember& stub_member) { - if (!stub_member.IsVisible()) { - // Typically fake constructors and inner-class `this` fields. - return; - } - bool resolved = boot_hierarchy.ForEachResolvableMember( - stub_member, - [&boot_members](DexMember& boot_member) { - std::string entry = boot_member.GetApiEntry(); - auto it = boot_members.find(entry); - CHECK(it != boot_members.end()); - if (it->second) { - return false; // has been marked before - } else { - it->second = true; - return true; // marked for the first time - } - }); - if (!resolved) { - unresolved.insert(stub_member.GetApiEntry()); - } - }); + for (const std::vector<std::string>& stub_classpath_dex : stub_classpaths_) { + ClassPath stub_classpath(stub_classpath_dex, /* open_writable */ false); + Hierarchy stub_hierarchy(stub_classpath); + stub_classpath.ForEachDexMember( + [&stub_hierarchy, &boot_hierarchy, &boot_members, &unresolved](DexMember& stub_member) { + if (!stub_hierarchy.IsMemberVisible(stub_member)) { + // Typically fake constructors and inner-class `this` fields. + return; + } + bool resolved = boot_hierarchy.ForEachResolvableMember( + stub_member, + [&boot_members](DexMember& boot_member) { + std::string entry = boot_member.GetApiEntry(); + auto it = boot_members.find(entry); + CHECK(it != boot_members.end()); + if (it->second) { + return false; // has been marked before + } else { + it->second = true; + return true; // marked for the first time + } + }); + if (!resolved) { + unresolved.insert(stub_member.GetApiEntry()); + } + }); + } // Print errors. for (const std::string& str : unresolved) { @@ -685,7 +750,10 @@ class HiddenApi FINAL { // Paths to DEX files which should be processed. std::vector<std::string> boot_dex_paths_; - std::vector<std::string> stub_dex_paths_; + + // Set of public API stub classpaths. Each classpath is formed by a list + // of DEX/APK files in the order they appear on the classpath. + std::vector<std::vector<std::string>> stub_classpaths_; // Paths to text files which contain the lists of API members. std::string light_greylist_path_; diff --git a/tools/jfuzz/jfuzz.cc b/tools/jfuzz/jfuzz.cc index 60c62752ef..a97a99ce4b 100644 --- a/tools/jfuzz/jfuzz.cc +++ b/tools/jfuzz/jfuzz.cc @@ -1302,7 +1302,7 @@ class JFuzz { int32_t main(int32_t argc, char** argv) { // Time-based seed. struct timeval tp; - gettimeofday(&tp, NULL); + gettimeofday(&tp, nullptr); // Defaults. uint32_t seed = (tp.tv_sec * 1000000 + tp.tv_usec); diff --git a/tools/libcore_gcstress_debug_failures.txt b/tools/libcore_gcstress_debug_failures.txt index 06f6339d76..942a4e0fc6 100644 --- a/tools/libcore_gcstress_debug_failures.txt +++ b/tools/libcore_gcstress_debug_failures.txt @@ -9,13 +9,14 @@ result: EXEC_FAILED, modes: [device], names: ["jsr166.CompletableFutureTest#testCompleteOnTimeout_completed", + "jsr166.CompletableFutureTest#testDelayedExecutor", "libcore.libcore.icu.TransliteratorTest#testAll", "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_bug25821045", "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_bug25883157", "libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndTimeout", - "libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndNoTimeout", "libcore.java.util.TimeZoneTest#testSetDefaultDeadlock", "libcore.javax.crypto.CipherBasicsTest#testBasicEncryption", + "org.apache.harmony.tests.java.text.MessageFormatTest#test_parseLjava_lang_String", "org.apache.harmony.tests.java.util.TimerTest#testThrowingTaskKillsTimerThread"] }, { diff --git a/tools/libcore_gcstress_failures.txt b/tools/libcore_gcstress_failures.txt index e049cb3ee9..6840f9ebec 100644 --- a/tools/libcore_gcstress_failures.txt +++ b/tools/libcore_gcstress_failures.txt @@ -9,5 +9,39 @@ result: EXEC_FAILED, modes: [device], names: ["libcore.javax.crypto.CipherBasicsTest#testGcmEncryption"] +}, +{ + description: "Timeouts.", + result: EXEC_FAILED, + names: ["libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndNoTimeout"] +}, +{ + description: "Timeouts.", + result: EXEC_FAILED, + modes: [host], + names: ["libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndTimeout", + "org.apache.harmony.luni.tests.internal.net.www.protocol.http.HttpURLConnectionTest#testGetOutputStream", + "org.apache.harmony.luni.tests.internal.net.www.protocol.http.HttpURLConnectionTest#testProxyAuthorization"] +}, +{ + description: "Timeouts.", + result: EXEC_FAILED, + modes: [device], + names: ["libcore.java.lang.StringTest#testFastPathString_wellFormedUtf8Sequence", + "org.apache.harmony.tests.java.lang.ref.ReferenceQueueTest#test_remove", + "org.apache.harmony.tests.java.util.TimerTest#testOverdueTaskExecutesImmediately", + "org.apache.harmony.tests.java.util.WeakHashMapTest#test_keySet_hasNext", + "libcore.java.text.DecimalFormatTest#testCurrencySymbolSpacing", + "libcore.java.text.SimpleDateFormatTest#testLocales"] +}, +{ + description: "GC crash", + result: EXEC_FAILED, + bug: 111545159, + names: ["org.apache.harmony.tests.java.util.AbstractSequentialListTest#test_addAllILjava_util_Collection", + "org.apache.harmony.tests.java.util.HashtableTest#test_putLjava_lang_ObjectLjava_lang_Object", + "org.apache.harmony.tests.java.util.VectorTest#test_addAllILjava_util_Collection", + "org.apache.harmony.tests.java.util.VectorTest#test_addAllLjava_util_Collection", + "org.apache.harmony.tests.java.io.BufferedWriterTest#test_write_LStringII_Exception"] } ] diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh index aff009abb6..240d63c6d3 100755 --- a/tools/run-libcore-tests.sh +++ b/tools/run-libcore-tests.sh @@ -156,7 +156,11 @@ fi # Increase the timeout, as vogar cannot set individual test # timeout when being asked to run packages, and some tests go above # the default timeout. -vogar_args="$vogar_args --timeout 480" +if $gcstress && $debug && $device_mode; then + vogar_args="$vogar_args --timeout 960" +else + vogar_args="$vogar_args --timeout 480" +fi # set the toolchain to use. vogar_args="$vogar_args --toolchain d8 --language CUR" diff --git a/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc index d4f7e5f91d..f5eb4ea67d 100644 --- a/tools/veridex/flow_analysis.cc +++ b/tools/veridex/flow_analysis.cc @@ -17,6 +17,7 @@ #include "flow_analysis.h" #include "dex/bytecode_utils.h" +#include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_instruction-inl.h" #include "dex/dex_file-inl.h" @@ -26,6 +27,13 @@ namespace art { +VeriFlowAnalysis::VeriFlowAnalysis(VeridexResolver* resolver, + const ClassAccessor::Method& method) + : resolver_(resolver), + method_id_(method.GetIndex()), + code_item_accessor_(method.GetInstructionsAndData()), + dex_registers_(code_item_accessor_.InsnsSizeInCodeUnits()), + instruction_infos_(code_item_accessor_.InsnsSizeInCodeUnits()) {} void VeriFlowAnalysis::SetAsBranchTarget(uint32_t dex_pc) { if (dex_registers_[dex_pc] == nullptr) { diff --git a/tools/veridex/flow_analysis.h b/tools/veridex/flow_analysis.h index fc093600c3..9c86024711 100644 --- a/tools/veridex/flow_analysis.h +++ b/tools/veridex/flow_analysis.h @@ -17,6 +17,7 @@ #ifndef ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_ #define ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_ +#include "dex/class_accessor.h" #include "dex/code_item_accessors.h" #include "dex/dex_file_reference.h" #include "dex/method_reference.h" @@ -108,12 +109,7 @@ struct InstructionInfo { class VeriFlowAnalysis { public: - VeriFlowAnalysis(VeridexResolver* resolver, const ClassDataItemIterator& it) - : resolver_(resolver), - method_id_(it.GetMemberIndex()), - code_item_accessor_(resolver->GetDexFile(), it.GetMethodCodeItem()), - dex_registers_(code_item_accessor_.InsnsSizeInCodeUnits()), - instruction_infos_(code_item_accessor_.InsnsSizeInCodeUnits()) {} + VeriFlowAnalysis(VeridexResolver* resolver, const ClassAccessor::Method& method); void Run(); @@ -189,8 +185,8 @@ struct ReflectAccessInfo { // Collects all reflection uses. class FlowAnalysisCollector : public VeriFlowAnalysis { public: - FlowAnalysisCollector(VeridexResolver* resolver, const ClassDataItemIterator& it) - : VeriFlowAnalysis(resolver, it) {} + FlowAnalysisCollector(VeridexResolver* resolver, const ClassAccessor::Method& method) + : VeriFlowAnalysis(resolver, method) {} const std::vector<ReflectAccessInfo>& GetUses() const { return uses_; @@ -208,9 +204,9 @@ class FlowAnalysisCollector : public VeriFlowAnalysis { class FlowAnalysisSubstitutor : public VeriFlowAnalysis { public: FlowAnalysisSubstitutor(VeridexResolver* resolver, - const ClassDataItemIterator& it, + const ClassAccessor::Method& method, const std::map<MethodReference, std::vector<ReflectAccessInfo>>& accesses) - : VeriFlowAnalysis(resolver, it), accesses_(accesses) {} + : VeriFlowAnalysis(resolver, method), accesses_(accesses) {} const std::vector<ReflectAccessInfo>& GetUses() const { return uses_; diff --git a/tools/veridex/hidden_api_finder.cc b/tools/veridex/hidden_api_finder.cc index 8c6139f75a..4eba10e764 100644 --- a/tools/veridex/hidden_api_finder.cc +++ b/tools/veridex/hidden_api_finder.cc @@ -16,6 +16,7 @@ #include "hidden_api_finder.h" +#include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_instruction-inl.h" #include "dex/dex_file.h" @@ -62,23 +63,9 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { } // Note: we collect strings constants only referenced in code items as the string table // contains other kind of strings (eg types). - size_t class_def_count = dex_file.NumClassDefs(); - for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { - // Empty class. - continue; - } - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); - for (; it.HasNextMethod(); it.Next()) { - const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); - if (code_item == nullptr) { - continue; - } - CodeItemDataAccessor code_item_accessor(dex_file, code_item); - for (const DexInstructionPcPair& inst : code_item_accessor) { + for (ClassAccessor accessor : dex_file.GetClasses()) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + for (const DexInstructionPcPair& inst : method.GetInstructions()) { switch (inst->Opcode()) { case Instruction::CONST_STRING: { dex::StringIndex string_index(inst->VRegB_21c()); @@ -103,8 +90,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { // We only keep track of the location for strings, as these will be the // field/method names the user is interested in. strings_.insert(name); - reflection_locations_[name].push_back( - MethodReference(&dex_file, it.GetMemberIndex())); + reflection_locations_[name].push_back(method.GetReference()); } } break; @@ -114,8 +100,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { case Instruction::INVOKE_STATIC: case Instruction::INVOKE_SUPER: case Instruction::INVOKE_VIRTUAL: { - CheckMethod( - inst->VRegB_35c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); + CheckMethod(inst->VRegB_35c(), resolver, method.GetReference()); break; } @@ -124,8 +109,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { case Instruction::INVOKE_STATIC_RANGE: case Instruction::INVOKE_SUPER_RANGE: case Instruction::INVOKE_VIRTUAL_RANGE: { - CheckMethod( - inst->VRegB_3rc(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); + CheckMethod(inst->VRegB_3rc(), resolver, method.GetReference()); break; } @@ -136,8 +120,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { case Instruction::IGET_BYTE: case Instruction::IGET_CHAR: case Instruction::IGET_SHORT: { - CheckField( - inst->VRegC_22c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); + CheckField(inst->VRegC_22c(), resolver, method.GetReference()); break; } @@ -148,8 +131,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { case Instruction::IPUT_BYTE: case Instruction::IPUT_CHAR: case Instruction::IPUT_SHORT: { - CheckField( - inst->VRegC_22c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); + CheckField(inst->VRegC_22c(), resolver, method.GetReference()); break; } @@ -160,8 +142,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { case Instruction::SGET_BYTE: case Instruction::SGET_CHAR: case Instruction::SGET_SHORT: { - CheckField( - inst->VRegB_21c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); + CheckField(inst->VRegB_21c(), resolver, method.GetReference()); break; } @@ -172,8 +153,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { case Instruction::SPUT_BYTE: case Instruction::SPUT_CHAR: case Instruction::SPUT_SHORT: { - CheckField( - inst->VRegB_21c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); + CheckField(inst->VRegB_21c(), resolver, method.GetReference()); break; } diff --git a/tools/veridex/precise_hidden_api_finder.cc b/tools/veridex/precise_hidden_api_finder.cc index 89754c2cdf..445221e8f7 100644 --- a/tools/veridex/precise_hidden_api_finder.cc +++ b/tools/veridex/precise_hidden_api_finder.cc @@ -16,6 +16,7 @@ #include "precise_hidden_api_finder.h" +#include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_instruction-inl.h" #include "dex/dex_file.h" @@ -31,25 +32,13 @@ namespace art { void PreciseHiddenApiFinder::RunInternal( const std::vector<std::unique_ptr<VeridexResolver>>& resolvers, - const std::function<void(VeridexResolver*, const ClassDataItemIterator&)>& action) { + const std::function<void(VeridexResolver*, const ClassAccessor::Method&)>& action) { for (const std::unique_ptr<VeridexResolver>& resolver : resolvers) { - const DexFile& dex_file = resolver->GetDexFile(); - size_t class_def_count = dex_file.NumClassDefs(); - for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { - // Empty class. - continue; - } - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); - for (; it.HasNextMethod(); it.Next()) { - const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); - if (code_item == nullptr) { - continue; + for (ClassAccessor accessor : resolver->GetDexFile().GetClasses()) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + if (method.GetCodeItem() != nullptr) { + action(resolver.get(), method); } - action(resolver.get(), it); } } } @@ -68,10 +57,10 @@ void PreciseHiddenApiFinder::AddUsesAt(const std::vector<ReflectAccessInfo>& acc void PreciseHiddenApiFinder::Run(const std::vector<std::unique_ptr<VeridexResolver>>& resolvers) { // Collect reflection uses. - RunInternal(resolvers, [this] (VeridexResolver* resolver, const ClassDataItemIterator& it) { - FlowAnalysisCollector collector(resolver, it); + RunInternal(resolvers, [this] (VeridexResolver* resolver, const ClassAccessor::Method& method) { + FlowAnalysisCollector collector(resolver, method); collector.Run(); - AddUsesAt(collector.GetUses(), MethodReference(&resolver->GetDexFile(), it.GetMemberIndex())); + AddUsesAt(collector.GetUses(), method.GetReference()); }); // For non-final reflection uses, do a limited fixed point calculation over the code to try @@ -84,11 +73,11 @@ void PreciseHiddenApiFinder::Run(const std::vector<std::unique_ptr<VeridexResolv std::map<MethodReference, std::vector<ReflectAccessInfo>> current_uses = std::move(abstract_uses_); RunInternal(resolvers, - [this, current_uses] (VeridexResolver* resolver, const ClassDataItemIterator& it) { - FlowAnalysisSubstitutor substitutor(resolver, it, current_uses); + [this, current_uses] (VeridexResolver* resolver, + const ClassAccessor::Method& method) { + FlowAnalysisSubstitutor substitutor(resolver, method, current_uses); substitutor.Run(); - AddUsesAt(substitutor.GetUses(), - MethodReference(&resolver->GetDexFile(), it.GetMemberIndex())); + AddUsesAt(substitutor.GetUses(), method.GetReference()); }); } } diff --git a/tools/veridex/precise_hidden_api_finder.h b/tools/veridex/precise_hidden_api_finder.h index 1c4d0ae84e..8c5126cf1b 100644 --- a/tools/veridex/precise_hidden_api_finder.h +++ b/tools/veridex/precise_hidden_api_finder.h @@ -48,7 +48,7 @@ class PreciseHiddenApiFinder { // Run over all methods of all dex files, and call `action` on each. void RunInternal( const std::vector<std::unique_ptr<VeridexResolver>>& resolvers, - const std::function<void(VeridexResolver*, const ClassDataItemIterator&)>& action); + const std::function<void(VeridexResolver*, const ClassAccessor::Method&)>& action); // Add uses found in method `ref`. void AddUsesAt(const std::vector<ReflectAccessInfo>& accesses, MethodReference ref); diff --git a/tools/veridex/resolver.cc b/tools/veridex/resolver.cc index 9113039b04..56729fffd0 100644 --- a/tools/veridex/resolver.cc +++ b/tools/veridex/resolver.cc @@ -16,6 +16,7 @@ #include "resolver.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file-inl.h" #include "dex/primitive.h" #include "hidden_api.h" @@ -24,34 +25,22 @@ namespace art { void VeridexResolver::Run() { - size_t class_def_count = dex_file_.NumClassDefs(); - for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) { - const DexFile::ClassDef& class_def = dex_file_.GetClassDef(class_def_index); - std::string name(dex_file_.StringByTypeIdx(class_def.class_idx_)); + for (ClassAccessor accessor : dex_file_.GetClasses()) { + std::string name(accessor.GetDescriptor()); auto existing = type_map_.find(name); + const uint32_t type_idx = accessor.GetClassIdx().index_; if (existing != type_map_.end()) { // Class already exists, cache it and move on. - type_infos_[class_def.class_idx_.index_] = *existing->second; + type_infos_[type_idx] = *existing->second; continue; } - type_infos_[class_def.class_idx_.index_] = VeriClass(Primitive::Type::kPrimNot, 0, &class_def); - type_map_[name] = &(type_infos_[class_def.class_idx_.index_]); - - const uint8_t* class_data = dex_file_.GetClassData(class_def); - if (class_data == nullptr) { - // Empty class. - continue; - } - - ClassDataItemIterator it(dex_file_, class_data); - for (; it.HasNextStaticField(); it.Next()) { - field_infos_[it.GetMemberIndex()] = it.DataPointer(); + type_infos_[type_idx] = VeriClass(Primitive::Type::kPrimNot, 0, &accessor.GetClassDef()); + type_map_[name] = &type_infos_[type_idx]; + for (const ClassAccessor::Field& field : accessor.GetFields()) { + field_infos_[field.GetIndex()] = field.GetDataPointer(); } - for (; it.HasNextInstanceField(); it.Next()) { - field_infos_[it.GetMemberIndex()] = it.DataPointer(); - } - for (; it.HasNextMethod(); it.Next()) { - method_infos_[it.GetMemberIndex()] = it.DataPointer(); + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + method_infos_[method.GetIndex()] = method.GetDataPointer(); } } } @@ -148,18 +137,14 @@ VeriMethod VeridexResolver::LookupMethodIn(const VeriClass& kls, // Look at methods declared in `kls`. const DexFile& other_dex_file = resolver->dex_file_; - const uint8_t* class_data = other_dex_file.GetClassData(*kls.GetClassDef()); - if (class_data != nullptr) { - ClassDataItemIterator it(other_dex_file, class_data); - it.SkipAllFields(); - for (; it.HasNextMethod(); it.Next()) { - const DexFile::MethodId& other_method_id = other_dex_file.GetMethodId(it.GetMemberIndex()); - if (HasSameNameAndSignature(other_dex_file, - other_method_id, - method_name, - method_signature)) { - return it.DataPointer(); - } + ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef()); + for (const ClassAccessor::Method& method : other_dex_accessor.GetMethods()) { + const DexFile::MethodId& other_method_id = other_dex_file.GetMethodId(method.GetIndex()); + if (HasSameNameAndSignature(other_dex_file, + other_method_id, + method_name, + method_signature)) { + return method.GetDataPointer(); } } @@ -207,17 +192,14 @@ VeriField VeridexResolver::LookupFieldIn(const VeriClass& kls, // Look at fields declared in `kls`. const DexFile& other_dex_file = resolver->dex_file_; - const uint8_t* class_data = other_dex_file.GetClassData(*kls.GetClassDef()); - if (class_data != nullptr) { - ClassDataItemIterator it(other_dex_file, class_data); - for (; it.HasNextStaticField() || it.HasNextInstanceField(); it.Next()) { - const DexFile::FieldId& other_field_id = other_dex_file.GetFieldId(it.GetMemberIndex()); - if (HasSameNameAndType(other_dex_file, - other_field_id, - field_name, - field_type)) { - return it.DataPointer(); - } + ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef()); + for (const ClassAccessor::Field& field : other_dex_accessor.GetFields()) { + const DexFile::FieldId& other_field_id = other_dex_file.GetFieldId(field.GetIndex()); + if (HasSameNameAndType(other_dex_file, + other_field_id, + field_name, + field_type)) { + return field.GetDataPointer(); } } @@ -260,18 +242,13 @@ VeriMethod VeridexResolver::LookupDeclaredMethodIn(const VeriClass& kls, } VeridexResolver* resolver = GetResolverOf(kls); const DexFile& other_dex_file = resolver->dex_file_; - const uint8_t* class_data = other_dex_file.GetClassData(*kls.GetClassDef()); - if (class_data != nullptr) { - ClassDataItemIterator it(other_dex_file, class_data); - it.SkipAllFields(); - for (; it.HasNextMethod(); it.Next()) { - const DexFile::MethodId& other_method_id = other_dex_file.GetMethodId(it.GetMemberIndex()); - if (HasSameNameAndSignature(other_dex_file, - other_method_id, - method_name, - type)) { - return it.DataPointer(); - } + ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef()); + for (const ClassAccessor::Method& method : other_dex_accessor.GetMethods()) { + if (HasSameNameAndSignature(other_dex_file, + other_dex_file.GetMethodId(method.GetIndex()), + method_name, + type)) { + return method.GetDataPointer(); } } return nullptr; |