summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.gtest.mk19
-rw-r--r--compiler/optimizing/inliner.cc1
-rw-r--r--compiler/optimizing/load_store_elimination.cc9
-rw-r--r--dex2oat/dex2oat_test.cc16
-rw-r--r--runtime/dex/dex_file_loader.cc6
-rw-r--r--runtime/gc/space/image_space.cc37
-rw-r--r--runtime/runtime.cc7
-rw-r--r--runtime/well_known_classes.cc9
-rw-r--r--test/530-checker-lse/expected.txt1
-rw-r--r--test/530-checker-lse/src/Main.java23
10 files changed, 122 insertions, 6 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index c8f661561f..894b33b00a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -78,6 +78,11 @@ ART_TEST_TARGET_GTEST_MainStripped_DEX := $(basename $(ART_TEST_TARGET_GTEST_Mai
ART_TEST_HOST_GTEST_MainUncompressed_DEX := $(basename $(ART_TEST_HOST_GTEST_Main_DEX))Uncompressed$(suffix $(ART_TEST_HOST_GTEST_Main_DEX))
ART_TEST_TARGET_GTEST_MainUncompressed_DEX := $(basename $(ART_TEST_TARGET_GTEST_Main_DEX))Uncompressed$(suffix $(ART_TEST_TARGET_GTEST_Main_DEX))
+# Create rules for UncompressedEmpty, a classes.dex that is empty and uncompressed
+# for the dex2oat tests.
+ART_TEST_HOST_GTEST_EmptyUncompressed_DEX := $(basename $(ART_TEST_HOST_GTEST_Main_DEX))EmptyUncompressed$(suffix $(ART_TEST_HOST_GTEST_Main_DEX))
+ART_TEST_TARGET_GTEST_EmptyUncompressed_DEX := $(basename $(ART_TEST_TARGET_GTEST_Main_DEX))EmptyUncompressed$(suffix $(ART_TEST_TARGET_GTEST_Main_DEX))
+
$(ART_TEST_HOST_GTEST_MainStripped_DEX): $(ART_TEST_HOST_GTEST_Main_DEX)
cp $< $@
$(call dexpreopt-remove-classes.dex,$@)
@@ -96,6 +101,16 @@ $(ART_TEST_TARGET_GTEST_MainUncompressed_DEX): $(ART_TEST_TARGET_GTEST_Main_DEX)
$(call uncompress-dexs, $@)
$(call align-package, $@)
+$(ART_TEST_HOST_GTEST_EmptyUncompressed_DEX): $(ZIPALIGN)
+ touch $(dir $@)classes.dex
+ zip -j -qD -X -0 $@ $(dir $@)classes.dex
+ rm $(dir $@)classes.dex
+
+$(ART_TEST_TARGET_GTEST_EmptyUncompressed_DEX): $(ZIPALIGN)
+ touch $(dir $@)classes.dex
+ zip -j -qD -X -0 $@ $(dir $@)classes.dex
+ rm $(dir $@)classes.dex
+
ART_TEST_GTEST_VerifierDeps_SRC := $(abspath $(wildcard $(LOCAL_PATH)/VerifierDeps/*.smali))
ART_TEST_GTEST_VerifierDepsMulti_SRC := $(abspath $(wildcard $(LOCAL_PATH)/VerifierDepsMulti/*.smali))
ART_TEST_HOST_GTEST_VerifierDeps_DEX := $(dir $(ART_TEST_HOST_GTEST_Main_DEX))$(subst Main,VerifierDeps,$(basename $(notdir $(ART_TEST_HOST_GTEST_Main_DEX))))$(suffix $(ART_TEST_HOST_GTEST_Main_DEX))
@@ -126,7 +141,7 @@ ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods Prof
ART_GTEST_dex_cache_test_DEX_DEPS := Main Packages MethodTypes
ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested MultiDex
ART_GTEST_dexlayout_test_DEX_DEPS := ManyMethods
-ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ManyMethods Statics VerifierDeps MainUncompressed
+ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ManyMethods Statics VerifierDeps MainUncompressed EmptyUncompressed
ART_GTEST_dex2oat_image_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics VerifierDeps
ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
ART_GTEST_hiddenapi_test_DEX_DEPS := HiddenApi
@@ -750,6 +765,8 @@ ART_TEST_HOST_GTEST_MainStripped_DEX :=
ART_TEST_TARGET_GTEST_MainStripped_DEX :=
ART_TEST_HOST_GTEST_MainUncompressed_DEX :=
ART_TEST_TARGET_GTEST_MainUncompressed_DEX :=
+ART_TEST_HOST_GTEST_EmptyUncompressed_DEX :=
+ART_TEST_TARGET_GTEST_EmptyUncompressed_DEX :=
ART_TEST_GTEST_VerifierDeps_SRC :=
ART_TEST_HOST_GTEST_VerifierDeps_DEX :=
ART_TEST_TARGET_GTEST_VerifierDeps_DEX :=
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index b9ae0ffb12..4fc7262265 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1471,6 +1471,7 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction,
LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified)
<< "Method " << method->PrettyMethod()
<< " has soft failures un-handled by the compiler, so it cannot be inlined";
+ return false;
}
if (IsMethodUnverified(compiler_driver_, method)) {
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 8b4eae1780..237ecd3c10 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -882,6 +882,7 @@ class LSEVisitor : public HGraphDelegateVisitor {
}
if (ref_info->IsSingletonAndRemovable() && !new_instance->NeedsChecks()) {
DCHECK(!new_instance->IsFinalizable());
+ // new_instance can potentially be eliminated.
singleton_new_instances_.push_back(new_instance);
}
ScopedArenaVector<HInstruction*>& heap_values =
@@ -904,7 +905,13 @@ class LSEVisitor : public HGraphDelegateVisitor {
return;
}
if (ref_info->IsSingletonAndRemovable()) {
- singleton_new_instances_.push_back(new_array);
+ if (new_array->GetLength()->IsIntConstant() &&
+ new_array->GetLength()->AsIntConstant()->GetValue() >= 0) {
+ // new_array can potentially be eliminated.
+ singleton_new_instances_.push_back(new_array);
+ } else {
+ // new_array may throw NegativeArraySizeException. Keep it.
+ }
}
ScopedArenaVector<HInstruction*>& heap_values =
heap_values_for_[new_array->GetBlock()->GetBlockId()];
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 5614ac6458..17a27f8567 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1543,4 +1543,20 @@ TEST_F(Dex2oatTest, UncompressedTest) {
});
}
+TEST_F(Dex2oatTest, EmptyUncompressedDexTest) {
+ std::string out_dir = GetScratchDir();
+ const std::string base_oat_name = out_dir + "/base.oat";
+ std::string error_msg;
+ int status = GenerateOdexForTestWithStatus(
+ { GetTestDexFileName("MainEmptyUncompressed") },
+ base_oat_name,
+ CompilerFilter::Filter::kQuicken,
+ &error_msg,
+ { },
+ /*use_fd*/ false);
+ // Expect to fail with code 1 and not SIGSEGV or SIGABRT.
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(WEXITSTATUS(status), 1) << error_msg;
+}
+
} // namespace art
diff --git a/runtime/dex/dex_file_loader.cc b/runtime/dex/dex_file_loader.cc
index 0f2758e372..2c75c5b5d9 100644
--- a/runtime/dex/dex_file_loader.cc
+++ b/runtime/dex/dex_file_loader.cc
@@ -319,7 +319,7 @@ std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
*verify_result = VerifyResult::kVerifyNotAttempted;
}
std::unique_ptr<DexFile> dex_file;
- if (StandardDexFile::IsMagicValid(base)) {
+ if (size >= sizeof(StandardDexFile::Header) && StandardDexFile::IsMagicValid(base)) {
if (data_size != 0) {
CHECK_EQ(base, data_base) << "Unsupported for standard dex";
}
@@ -329,7 +329,7 @@ std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
location_checksum,
oat_dex_file,
container));
- } else if (CompactDexFile::IsMagicValid(base)) {
+ } else if (size >= sizeof(CompactDexFile::Header) && CompactDexFile::IsMagicValid(base)) {
if (data_base == nullptr) {
// TODO: Is there a clean way to support both an explicit data section and reading the one
// from the header.
@@ -346,6 +346,8 @@ std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
location_checksum,
oat_dex_file,
container));
+ } else {
+ *error_msg = "Invalid or truncated dex file";
}
if (dex_file == nullptr) {
*error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index ca5a3eeb17..2b06e838ce 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -277,6 +277,36 @@ static bool RelocateImage(const char* image_location,
return Exec(argv, error_msg);
}
+static bool VerifyImage(const char* image_location,
+ const char* dest_filename,
+ InstructionSet isa,
+ std::string* error_msg) {
+ std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
+
+ std::string input_image_location_arg("--input-image-location=");
+ input_image_location_arg += image_location;
+
+ std::string output_image_filename_arg("--output-image-file=");
+ output_image_filename_arg += dest_filename;
+
+ std::string instruction_set_arg("--instruction-set=");
+ instruction_set_arg += GetInstructionSetString(isa);
+
+ std::vector<std::string> argv;
+ argv.push_back(patchoat);
+
+ argv.push_back(input_image_location_arg);
+ argv.push_back(output_image_filename_arg);
+
+ argv.push_back(instruction_set_arg);
+
+ argv.push_back("--verify");
+
+ std::string command_line(android::base::Join(argv, ' '));
+ LOG(INFO) << "VerifyImage: " << command_line;
+ return Exec(argv, error_msg);
+}
+
static ImageHeader* ReadSpecificImageHeader(const char* filename, std::string* error_msg) {
std::unique_ptr<ImageHeader> hdr(new ImageHeader);
if (!ReadSpecificImageHeader(filename, hdr.get())) {
@@ -1504,7 +1534,12 @@ std::unique_ptr<ImageSpace> ImageSpace::CreateBootImage(const char* image_locati
if (is_zygote && dalvik_cache_exists) {
DCHECK(!dalvik_cache.empty());
std::string local_error_msg;
- if (!CheckSpace(dalvik_cache, &local_error_msg)) {
+ // All secondary images are verified when the primary image is verified.
+ bool verified = secondary_image || VerifyImage(image_location,
+ cache_filename.c_str(),
+ image_isa,
+ &local_error_msg);
+ if (!(verified && CheckSpace(dalvik_cache, &local_error_msg))) {
LOG(WARNING) << local_error_msg << " Preemptively pruning the dalvik cache.";
PruneDalvikCache(image_isa);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 3afd320f05..b26b09c156 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1178,7 +1178,12 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
// (b) Zygote forked a new process that is not exempt (see ZygoteHooks).
// TODO(dbrazdil): Turn the NoHiddenApiChecks negative flag into a positive one
// to clean up this logic.
- do_hidden_api_checks_ = IsAotCompiler() && !runtime_options.Exists(Opt::NoHiddenApiChecks);
+ if (kIsTargetBuild && IsAotCompiler() && !runtime_options.Exists(Opt::NoHiddenApiChecks)) {
+ // dex2oat on target without -Xno-hidden-api-checks.
+ do_hidden_api_checks_ = !IsCompilingBootImage();
+ } else {
+ do_hidden_api_checks_ = false;
+ }
DCHECK(!is_zygote_ || !do_hidden_api_checks_)
<< "Zygote should not be started with hidden API checks";
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 5fe10f5c12..f4f5420190 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -278,6 +278,12 @@ uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) {
#undef STRING_INIT_LIST
void WellKnownClasses::Init(JNIEnv* env) {
+ // The following initializers use JNI to get handles on hidden methods/fields.
+ // Temporarily disable hidden API checks as they would see these calls coming
+ // from an unattached thread and assume the caller is not in boot class path.
+ const bool hidden_api_checks_enabled = Runtime::Current()->AreHiddenApiChecksEnabled();
+ Runtime::Current()->SetHiddenApiChecksEnabled(false);
+
dalvik_annotation_optimization_CriticalNative =
CacheClass(env, "dalvik/annotation/optimization/CriticalNative");
dalvik_annotation_optimization_FastNative = CacheClass(env, "dalvik/annotation/optimization/FastNative");
@@ -401,6 +407,9 @@ void WellKnownClasses::Init(JNIEnv* env) {
InitStringInit(env);
Thread::Current()->InitStringEntryPoints();
+
+ // Reenable hidden API checks if necessary.
+ Runtime::Current()->SetHiddenApiChecksEnabled(hidden_api_checks_enabled);
}
void WellKnownClasses::LateInit(JNIEnv* env) {
diff --git a/test/530-checker-lse/expected.txt b/test/530-checker-lse/expected.txt
index ddae16aff4..fb67e22d0b 100644
--- a/test/530-checker-lse/expected.txt
+++ b/test/530-checker-lse/expected.txt
@@ -1 +1,2 @@
java.lang.ArrayIndexOutOfBoundsException: length=3; index=3
+Got NegativeArraySizeException.
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index 98838c5089..ebde3bf845 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -1052,6 +1052,23 @@ public class Main {
return array[1] + array[i];
}
+ /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (before)
+ /// CHECK: NewArray
+ /// CHECK: ArraySet
+ /// CHECK: ArrayGet
+
+ /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (after)
+ /// CHECK: NewArray
+ /// CHECK-NOT: ArraySet
+ /// CHECK-NOT: ArrayGet
+ private static int testAllocationEliminationOfArray5(int i) {
+ // Cannot eliminate array allocation due to unknown i that may
+ // cause NegativeArraySizeException.
+ int[] array = new int[i];
+ array[1] = 12;
+ return array[1];
+ }
+
/// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (before)
/// CHECK: NewInstance
/// CHECK: InstanceFieldSet
@@ -1205,6 +1222,12 @@ public class Main {
assertIntEquals(testAllocationEliminationOfArray2(), 11);
assertIntEquals(testAllocationEliminationOfArray3(2), 4);
assertIntEquals(testAllocationEliminationOfArray4(2), 6);
+ assertIntEquals(testAllocationEliminationOfArray5(2), 12);
+ try {
+ testAllocationEliminationOfArray5(-2);
+ } catch (NegativeArraySizeException e) {
+ System.out.println("Got NegativeArraySizeException.");
+ }
assertIntEquals(testStoreStore().i, 41);
assertIntEquals(testStoreStore().j, 43);