diff options
| -rw-r--r-- | adbconnection/adbconnection.cc | 18 | ||||
| -rw-r--r-- | compiler/optimizing/nodes_vector.h | 5 | ||||
| -rw-r--r-- | dex2oat/dex2oat.cc | 41 | ||||
| -rw-r--r-- | dex2oat/dex2oat_options.cc | 3 | ||||
| -rw-r--r-- | dex2oat/dex2oat_options.def | 1 | ||||
| -rw-r--r-- | dex2oat/dex2oat_test.cc | 45 | ||||
| -rw-r--r-- | runtime/class_loader_context.cc | 58 | ||||
| -rw-r--r-- | runtime/class_loader_context.h | 17 | ||||
| -rw-r--r-- | runtime/debug_print.cc | 39 | ||||
| -rw-r--r-- | test/682-double-catch-phi/expected.txt | 1 | ||||
| -rw-r--r-- | test/682-double-catch-phi/info.txt | 1 | ||||
| -rw-r--r-- | test/682-double-catch-phi/smali/DoubleCatchPhi.smali | 47 | ||||
| -rw-r--r-- | test/682-double-catch-phi/src/Main.java | 26 | ||||
| -rw-r--r-- | tools/veridex/flow_analysis.cc | 10 | ||||
| -rw-r--r-- | tools/veridex/flow_analysis.h | 16 | ||||
| -rw-r--r-- | tools/veridex/hidden_api.h | 6 | ||||
| -rw-r--r-- | tools/veridex/hidden_api_finder.cc | 4 | ||||
| -rw-r--r-- | tools/veridex/veridex.cc | 5 | ||||
| -rw-r--r-- | tools/veridex/veridex.h | 2 |
19 files changed, 298 insertions, 47 deletions
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc index 06ded26a2d..ee89717043 100644 --- a/adbconnection/adbconnection.cc +++ b/adbconnection/adbconnection.cc @@ -824,11 +824,21 @@ void AdbConnectionState::PerformHandshake() { } void AdbConnectionState::AttachJdwpAgent(art::Thread* self) { + art::Runtime* runtime = art::Runtime::Current(); + if (runtime->GetJit() == nullptr && !runtime->GetInstrumentation()->IsForcedInterpretOnly()) { + // If we don't have a JIT we should try to start the jit for performance reasons. + runtime->CreateJit(); + if (runtime->GetJit() == nullptr) { + LOG(WARNING) << "Could not start jit for debugging. This process might be quite slow as it " + << "is running entirely in the interpreter. Try running 'setenforce 0' and " + << "starting the debugging session over."; + } + } self->AssertNoPendingException(); - art::Runtime::Current()->AttachAgent(/* JNIEnv */ nullptr, - MakeAgentArg(), - /* classloader */ nullptr, - /*allow_non_debuggable_tooling*/ true); + runtime->AttachAgent(/* JNIEnv */ nullptr, + MakeAgentArg(), + /* classloader */ nullptr, + /*allow_non_debuggable_tooling*/ true); if (self->IsExceptionPending()) { LOG(ERROR) << "Failed to load agent " << agent_name_; art::ScopedObjectAccess soa(self); diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h index 0d38d57375..d1eaf5c366 100644 --- a/compiler/optimizing/nodes_vector.h +++ b/compiler/optimizing/nodes_vector.h @@ -171,9 +171,12 @@ class HVecOperation : public HVariableInputSizeInstruction { if (instruction->IsVecOperation()) { return !instruction->IsVecExtractScalar(); // only scalar returning vec op } else if (instruction->IsPhi()) { + // Vectorizer only uses Phis in reductions, so checking for a 2-way phi + // with a direct vector operand as second argument suffices. return instruction->GetType() == kSIMDType && - instruction->InputAt(1)->IsVecOperation(); // vectorizer does not go deeper + instruction->InputCount() == 2 && + instruction->InputAt(1)->IsVecOperation(); } return false; } diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 1e4ed58c8c..fe927bbc1c 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -428,6 +428,10 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(" --class-loader-context=<string spec>: a string specifying the intended"); UsageError(" runtime loading context for the compiled dex files."); UsageError(""); + UsageError(" --stored-class-loader-context=<string spec>: a string specifying the intended"); + UsageError(" runtime loading context that is stored in the oat file. Overrides"); + UsageError(" --class-loader-context. Note that this ignores the classpath_dir arg."); + UsageError(""); UsageError(" It describes how the class loader chain should be built in order to ensure"); UsageError(" classes are resolved during dex2aot as they would be resolved at runtime."); UsageError(" This spec will be encoded in the oat file. If at runtime the dex file is"); @@ -1260,11 +1264,31 @@ class Dex2Oat FINAL { ParseInstructionSetFeatures(*args.Get(M::TargetInstructionSetFeatures), parser_options.get()); } if (args.Exists(M::ClassLoaderContext)) { - class_loader_context_ = ClassLoaderContext::Create(*args.Get(M::ClassLoaderContext)); + std::string class_loader_context_arg = *args.Get(M::ClassLoaderContext); + class_loader_context_ = ClassLoaderContext::Create(class_loader_context_arg); if (class_loader_context_ == nullptr) { Usage("Option --class-loader-context has an incorrect format: %s", - args.Get(M::ClassLoaderContext)->c_str()); + class_loader_context_arg.c_str()); + } + if (args.Exists(M::StoredClassLoaderContext)) { + const std::string stored_context_arg = *args.Get(M::StoredClassLoaderContext); + stored_class_loader_context_ = ClassLoaderContext::Create(stored_context_arg); + if (stored_class_loader_context_ == nullptr) { + Usage("Option --stored-class-loader-context has an incorrect format: %s", + stored_context_arg.c_str()); + } else if (!class_loader_context_->VerifyClassLoaderContextMatch( + stored_context_arg, + /*verify_names*/ false, + /*verify_checksums*/ false)) { + Usage( + "Option --stored-class-loader-context '%s' mismatches --class-loader-context '%s'", + stored_context_arg.c_str(), + class_loader_context_arg.c_str()); + } } + } else if (args.Exists(M::StoredClassLoaderContext)) { + Usage("Option --stored-class-loader-context should only be used if " + "--class-loader-context is also specified"); } if (!ReadCompilerOptions(args, compiler_options_.get(), &error_msg)) { @@ -1579,7 +1603,7 @@ class Dex2Oat FINAL { if (class_loader_context_ == nullptr) { // If no context was specified use the default one (which is an empty PathClassLoader). - class_loader_context_ = std::unique_ptr<ClassLoaderContext>(ClassLoaderContext::Default()); + class_loader_context_ = ClassLoaderContext::Default(); } DCHECK_EQ(oat_writers_.size(), 1u); @@ -1605,8 +1629,12 @@ class Dex2Oat FINAL { } // Store the class loader context in the oat header. - key_value_store_->Put(OatHeader::kClassPathKey, - class_loader_context_->EncodeContextForOatFile(classpath_dir_)); + // TODO: deprecate this since store_class_loader_context should be enough to cover the users + // of classpath_dir as well. + std::string class_path_key = + class_loader_context_->EncodeContextForOatFile(classpath_dir_, + stored_class_loader_context_.get()); + key_value_store_->Put(OatHeader::kClassPathKey, class_path_key); } // Now that we have finalized key_value_store_, start writing the oat file. @@ -2845,6 +2873,9 @@ class Dex2Oat FINAL { // The spec describing how the class loader should be setup for compilation. std::unique_ptr<ClassLoaderContext> class_loader_context_; + // The class loader context stored in the oat file. May be equal to class_loader_context_. + std::unique_ptr<ClassLoaderContext> stored_class_loader_context_; + size_t thread_count_; uint64_t start_ns_; uint64_t start_cputime_ns_; diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc index 0d68f4fab6..5843691a24 100644 --- a/dex2oat/dex2oat_options.cc +++ b/dex2oat/dex2oat_options.cc @@ -245,6 +245,9 @@ static Parser CreateArgumentParser() { .Define("--class-loader-context=_") .WithType<std::string>() .IntoKey(M::ClassLoaderContext) + .Define("--stored-class-loader-context=_") + .WithType<std::string>() + .IntoKey(M::StoredClassLoaderContext) .Define("--compact-dex-level=_") .WithType<CompactDexLevel>() .WithValueMap({{"none", CompactDexLevel::kCompactDexLevelNone}, diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def index 01f9d9425f..1a913a9bbf 100644 --- a/dex2oat/dex2oat_options.def +++ b/dex2oat/dex2oat_options.def @@ -88,6 +88,7 @@ DEX2OAT_OPTIONS_KEY (std::string, NoInlineFrom) DEX2OAT_OPTIONS_KEY (Unit, ForceDeterminism) DEX2OAT_OPTIONS_KEY (std::string, ClasspathDir) DEX2OAT_OPTIONS_KEY (std::string, ClassLoaderContext) +DEX2OAT_OPTIONS_KEY (std::string, StoredClassLoaderContext) DEX2OAT_OPTIONS_KEY (std::string, DirtyImageObjects) DEX2OAT_OPTIONS_KEY (std::vector<std::string>, RuntimeOptions) DEX2OAT_OPTIONS_KEY (std::string, CompilationReason) diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index c890f8bef0..bc8468e12f 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -2125,4 +2125,49 @@ TEST_F(Dex2oatTest, AppImageNoProfile) { EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtFields).Size(), 0u); } +TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) { + std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex"); + const std::string out_dir = GetScratchDir(); + const std::string odex_location = out_dir + "/base.odex"; + const std::string valid_context = "PCL[" + dex_files[0]->GetLocation() + "]"; + const std::string stored_context = "PCL[/system/not_real_lib.jar]"; + std::string expected_stored_context = "PCL["; + size_t index = 1; + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + const bool is_first = index == 1u; + if (!is_first) { + expected_stored_context += ":"; + } + expected_stored_context += "/system/not_real_lib.jar"; + if (!is_first) { + expected_stored_context += "!classes" + std::to_string(index) + ".dex"; + } + expected_stored_context += "*" + std::to_string(dex_file->GetLocationChecksum()); + ++index; + } + expected_stored_context += + "]"; + // The class path should not be valid and should fail being stored. + GenerateOdexForTest(GetTestDexFileName("ManyMethods"), + odex_location, + CompilerFilter::Filter::kQuicken, + { "--class-loader-context=" + stored_context }, + true, // expect_success + false, // use_fd + [&](const OatFile& oat_file) { + EXPECT_NE(oat_file.GetClassLoaderContext(), stored_context) << output_; + EXPECT_NE(oat_file.GetClassLoaderContext(), valid_context) << output_; + }); + // The stored context should match what we expect even though it's invalid. + GenerateOdexForTest(GetTestDexFileName("ManyMethods"), + odex_location, + CompilerFilter::Filter::kQuicken, + { "--class-loader-context=" + valid_context, + "--stored-class-loader-context=" + stored_context }, + true, // expect_success + false, // use_fd + [&](const OatFile& oat_file) { + EXPECT_EQ(oat_file.GetClassLoaderContext(), expected_stored_context) << output_; + }); +} + } // namespace art diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc index e646520f3d..4afc44cb91 100644 --- a/runtime/class_loader_context.cc +++ b/runtime/class_loader_context.cc @@ -254,6 +254,7 @@ bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& cla // This will allow the context to VerifyClassLoaderContextMatch which expects or multidex // location in the class paths. // Note that this will also remove the paths that could not be opened. + info.original_classpath = std::move(info.classpath); info.classpath.clear(); info.checksums.clear(); for (size_t k = opened_dex_files_index; k < info.opened_dex_files.size(); k++) { @@ -294,20 +295,26 @@ bool ClassLoaderContext::RemoveLocationsFromClassPaths( } std::string ClassLoaderContext::EncodeContextForDex2oat(const std::string& base_dir) const { - return EncodeContext(base_dir, /*for_dex2oat*/ true); + return EncodeContext(base_dir, /*for_dex2oat*/ true, /*stored_context*/ nullptr); } -std::string ClassLoaderContext::EncodeContextForOatFile(const std::string& base_dir) const { - return EncodeContext(base_dir, /*for_dex2oat*/ false); +std::string ClassLoaderContext::EncodeContextForOatFile(const std::string& base_dir, + ClassLoaderContext* stored_context) const { + return EncodeContext(base_dir, /*for_dex2oat*/ false, stored_context); } std::string ClassLoaderContext::EncodeContext(const std::string& base_dir, - bool for_dex2oat) const { + bool for_dex2oat, + ClassLoaderContext* stored_context) const { CheckDexFilesOpened("EncodeContextForOatFile"); if (special_shared_library_) { return OatFile::kSpecialSharedLibrary; } + if (stored_context != nullptr) { + DCHECK_EQ(class_loader_chain_.size(), stored_context->class_loader_chain_.size()); + } + std::ostringstream out; if (class_loader_chain_.empty()) { // We can get in this situation if the context was created with a class path containing the @@ -326,6 +333,15 @@ std::string ClassLoaderContext::EncodeContext(const std::string& base_dir, out << GetClassLoaderTypeName(info.type); out << kClassLoaderOpeningMark; std::set<std::string> seen_locations; + SafeMap<std::string, std::string> remap; + if (stored_context != nullptr) { + DCHECK_EQ(info.original_classpath.size(), + stored_context->class_loader_chain_[i].classpath.size()); + for (size_t k = 0; k < info.original_classpath.size(); ++k) { + // Note that we don't care if the same name appears twice. + remap.Put(info.original_classpath[k], stored_context->class_loader_chain_[i].classpath[k]); + } + } for (size_t k = 0; k < info.opened_dex_files.size(); k++) { const std::unique_ptr<const DexFile>& dex_file = info.opened_dex_files[k]; if (for_dex2oat) { @@ -337,7 +353,14 @@ std::string ClassLoaderContext::EncodeContext(const std::string& base_dir, continue; } } - const std::string& location = dex_file->GetLocation(); + std::string location = dex_file->GetLocation(); + // If there is a stored class loader remap, fix up the multidex strings. + if (!remap.empty()) { + std::string base_dex_location = DexFileLoader::GetBaseLocation(location); + auto it = remap.find(base_dex_location); + CHECK(it != remap.end()) << base_dex_location; + location = it->second + DexFileLoader::GetMultiDexSuffix(location); + } if (k > 0) { out << kClasspathSeparator; } @@ -345,7 +368,7 @@ std::string ClassLoaderContext::EncodeContext(const std::string& base_dir, if (!base_dir.empty() && location.substr(0, base_dir.length()) == base_dir) { out << location.substr(base_dir.length() + 1).c_str(); } else { - out << dex_file->GetLocation().c_str(); + out << location.c_str(); } // dex2oat does not need the checksums. if (!for_dex2oat) { @@ -649,12 +672,16 @@ static bool IsAbsoluteLocation(const std::string& location) { return !location.empty() && location[0] == '/'; } -bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec) const { - DCHECK(dex_files_open_attempted_); - DCHECK(dex_files_open_result_); +bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec, + bool verify_names, + bool verify_checksums) const { + if (verify_names || verify_checksums) { + DCHECK(dex_files_open_attempted_); + DCHECK(dex_files_open_result_); + } ClassLoaderContext expected_context; - if (!expected_context.Parse(context_spec, /*parse_checksums*/ true)) { + if (!expected_context.Parse(context_spec, verify_checksums)) { LOG(WARNING) << "Invalid class loader context: " << context_spec; return false; } @@ -693,8 +720,14 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex return false; } - DCHECK_EQ(info.classpath.size(), info.checksums.size()); - DCHECK_EQ(expected_info.classpath.size(), expected_info.checksums.size()); + if (verify_checksums) { + DCHECK_EQ(info.classpath.size(), info.checksums.size()); + DCHECK_EQ(expected_info.classpath.size(), expected_info.checksums.size()); + } + + if (!verify_names) { + continue; + } for (size_t k = 0; k < info.classpath.size(); k++) { // Compute the dex location that must be compared. @@ -766,4 +799,3 @@ jclass ClassLoaderContext::GetClassLoaderClass(ClassLoaderType type) { } } // namespace art - diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h index 692a6cda5b..1c83007f41 100644 --- a/runtime/class_loader_context.h +++ b/runtime/class_loader_context.h @@ -84,9 +84,12 @@ class ClassLoaderContext { // (so that it can be read and verified at runtime against the actual class // loader hierarchy). // Should only be called if OpenDexFiles() returned true. + // If stored context is non-null, the stored names are overwritten by the class path from the + // stored context. // E.g. if the context is PCL[a.dex:b.dex] this will return // "PCL[a.dex*a_checksum*b.dex*a_checksum]". - std::string EncodeContextForOatFile(const std::string& base_dir) const; + std::string EncodeContextForOatFile(const std::string& base_dir, + ClassLoaderContext* stored_context = nullptr) const; // Encodes the context as a string suitable to be passed to dex2oat. // This is the same as EncodeContextForOatFile but without adding the checksums @@ -104,7 +107,11 @@ class ClassLoaderContext { // - the class loader from the same position have the same classpath // (the order and checksum of the dex files matches) // This should be called after OpenDexFiles(). - bool VerifyClassLoaderContextMatch(const std::string& context_spec) const; + // Names are only verified if verify_names is true. + // Checksums are only verified if verify_checksums is true. + bool VerifyClassLoaderContextMatch(const std::string& context_spec, + bool verify_names = true, + bool verify_checksums = true) const; // Creates the class loader context from the given string. // The format: ClassLoaderType1[ClasspathElem1:ClasspathElem2...];ClassLoaderType2[...]... @@ -146,6 +153,8 @@ class ClassLoaderContext { // The list of class path elements that this loader loads. // Note that this list may contain relative paths. std::vector<std::string> classpath; + // Original opened class path (ignoring multidex). + std::vector<std::string> original_classpath; // The list of class path elements checksums. // May be empty if the checksums are not given when the context is created. std::vector<uint32_t> checksums; @@ -198,7 +207,9 @@ class ClassLoaderContext { // location). Otherwise, for oat files, the encoding adds all the dex files (including multidex) // together with their checksums. // Should only be called if OpenDexFiles() returned true. - std::string EncodeContext(const std::string& base_dir, bool for_dex2oat) const; + std::string EncodeContext(const std::string& base_dir, + bool for_dex2oat, + ClassLoaderContext* stored_context) const; // Extracts the class loader type from the given spec. // Return ClassLoaderContext::kInvalidClassLoader if the class loader type is not diff --git a/runtime/debug_print.cc b/runtime/debug_print.cc index 60487670ac..7e075ce352 100644 --- a/runtime/debug_print.cc +++ b/runtime/debug_print.cc @@ -97,14 +97,27 @@ std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* clas StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> handle(hs.NewHandle(loader)); const char* path_separator = ""; - VisitClassLoaderDexFiles(soa, - handle, - [&](const DexFile* dex_file) { - oss << path_separator << dex_file->GetLocation() - << "/" << static_cast<const void*>(dex_file); - path_separator = ":"; - return true; // Continue with the next DexFile. - }); + const DexFile* base_dex_file = nullptr; + VisitClassLoaderDexFiles( + soa, + handle, + [&](const DexFile* dex_file) { + oss << path_separator; + path_separator = ":"; + if (base_dex_file != nullptr && + dex_file->GetLocation().length() > base_dex_file->GetLocation().length() && + dex_file->GetLocation().compare(0u, + base_dex_file->GetLocation().length(), + base_dex_file->GetLocation()) == 0) { + // Replace the base location with "+" to shorten the output. + oss << "+" << dex_file->GetLocation().substr(base_dex_file->GetLocation().length()); + } else { + oss << dex_file->GetLocation(); + base_dex_file = dex_file; + } + oss << "/" << static_cast<const void*>(dex_file); + return true; // Continue with the next DexFile. + }); oss << ")"; } } @@ -132,13 +145,13 @@ void DumpB77342775DebugData(ObjPtr<mirror::Class> target_class, ObjPtr<mirror::C std::string source_descriptor_storage; const char* source_descriptor = src_class->GetDescriptor(&source_descriptor_storage); + LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor + << " with loader " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor); if (target_class->IsInterface()) { ObjPtr<mirror::IfTable> iftable = src_class->GetIfTable(); CHECK(iftable != nullptr); size_t ifcount = iftable->Count(); - LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor - << " with loader " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor) - << " in interface table for " << source_descriptor << " ifcount=" << ifcount + LOG(ERROR) << " in interface table for " << source_descriptor << " ifcount=" << ifcount << " with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor); for (size_t i = 0; i != ifcount; ++i) { ObjPtr<mirror::Class> iface = iftable->GetInterface(i); @@ -147,9 +160,7 @@ void DumpB77342775DebugData(ObjPtr<mirror::Class> target_class, ObjPtr<mirror::C matcher(iface); } } else { - LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor - << " with loader " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor) - << " in superclass chain for " << source_descriptor + LOG(ERROR) << " in superclass chain for " << source_descriptor << " with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor); for (ObjPtr<mirror::Class> klass = src_class; klass != nullptr; diff --git a/test/682-double-catch-phi/expected.txt b/test/682-double-catch-phi/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/682-double-catch-phi/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/682-double-catch-phi/info.txt b/test/682-double-catch-phi/info.txt new file mode 100644 index 0000000000..0ef2e59e9b --- /dev/null +++ b/test/682-double-catch-phi/info.txt @@ -0,0 +1 @@ +Regression test on double-typed catch phi diff --git a/test/682-double-catch-phi/smali/DoubleCatchPhi.smali b/test/682-double-catch-phi/smali/DoubleCatchPhi.smali new file mode 100644 index 0000000000..1d3f927bb2 --- /dev/null +++ b/test/682-double-catch-phi/smali/DoubleCatchPhi.smali @@ -0,0 +1,47 @@ +# 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. + +.class public LDoubleCatchPhi; + +.super Ljava/lang/Object; + +.field public mValue:D + +.method public constructor <init>()V +.registers 1 + invoke-direct {v0}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public strangeMethod(F)V +.registers 6 + move-object v2, v4 + monitor-enter v4 +:try_start1 + float-to-double v0, v5 + iput-wide v0, v4, LDoubleCatchPhi;->mValue:D + monitor-exit v2 +:try_end1 + goto :end_catch +:catch +:try_start2 + move-exception v3 + monitor-exit v2 +:try_end2 + throw v3 +:end_catch + return-void +.catchall {:try_start1 .. :try_end1} :catch +.catchall {:try_start2 .. :try_end2} :catch +.end method diff --git a/test/682-double-catch-phi/src/Main.java b/test/682-double-catch-phi/src/Main.java new file mode 100644 index 0000000000..e65bf0d4d4 --- /dev/null +++ b/test/682-double-catch-phi/src/Main.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +import java.lang.reflect.Method; + +public class Main { + public static void main(String[] args) throws Exception { + if (System.getProperty("java.vm.name").equals("Dalvik")) { + Class<?> c = Class.forName("DoubleCatchPhi"); + } + System.out.println("passed"); + } +} diff --git a/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc index abd0b9b28c..a4553f9613 100644 --- a/tools/veridex/flow_analysis.cc +++ b/tools/veridex/flow_analysis.cc @@ -41,7 +41,11 @@ bool VeriFlowAnalysis::IsBranchTarget(uint32_t dex_pc) { 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 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) { 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 c065fb8c24..80ae5fc9df 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 @@ class RegisterValue { 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 4c67768a00..b1c8559374 100644 --- a/tools/veridex/hidden_api.h +++ b/tools/veridex/hidden_api.h @@ -63,6 +63,12 @@ class HiddenApi { 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 b9be618ed7..b1ae7dd804 100644 --- a/tools/veridex/hidden_api_finder.cc +++ b/tools/veridex/hidden_api_finder.cc @@ -95,9 +95,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { // 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 6e72faaf57..dc7ea94032 100644 --- a/tools/veridex/veridex.cc +++ b/tools/veridex/veridex.cc @@ -52,6 +52,7 @@ VeriClass* VeriClass::void_ = &v_; // 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::getDeclaredField_ = nullptr; 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 @@ class Veridex { // 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 @@ class Veridex { "(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 75e4845293..9c0a158174 100644 --- a/tools/veridex/veridex.h +++ b/tools/veridex/veridex.h @@ -65,6 +65,7 @@ class VeriClass { static VeriClass* object_; static VeriClass* class_; + static VeriClass* class_loader_; static VeriClass* string_; static VeriClass* throwable_; static VeriClass* boolean_; @@ -83,6 +84,7 @@ class VeriClass { static VeriMethod getMethod_; static VeriMethod getDeclaredMethod_; static VeriMethod getClass_; + static VeriMethod loadClass_; private: Primitive::Type kind_; |