Fix handling for invalid or missing app images
Avoid crashing when there is an invalid app image path passed to
oatdump. Added regression test.
Bug: 137724009
Test: test-art-host-gtest-oatdump_app_test
Change-Id: I27470d0c1d844de5b9f3f3bf960e925cd8977d50
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 090e271..ea64708 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -2782,12 +2782,14 @@
if (space == nullptr) {
LOG(ERROR) << "Failed to open app image " << options->app_image_ << " with error "
<< error_msg;
+ return EXIT_FAILURE;
}
// Open dex files for the image.
std::vector<std::unique_ptr<const DexFile>> dex_files;
if (!runtime->GetClassLinker()->OpenImageDexFiles(space.get(), &dex_files, &error_msg)) {
LOG(ERROR) << "Failed to open app image dex files " << options->app_image_ << " with error "
<< error_msg;
+ return EXIT_FAILURE;
}
// Dump the actual image.
int result = DumpImage(space.get(), options, os);
diff --git a/oatdump/oatdump_app_test.cc b/oatdump/oatdump_app_test.cc
index 4490647..b4997ba 100644
--- a/oatdump/oatdump_app_test.cc
+++ b/oatdump/oatdump_app_test.cc
@@ -42,4 +42,13 @@
ASSERT_TRUE(Exec(kStatic, kModeAppImage, {}, kListAndCode));
}
+TEST_F(OatDumpTest, TestAppImageInvalidPath) {
+ TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS(); // GC bug, b/126305867
+ TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
+ const std::string app_image_arg = "--app-image-file=" + GetAppImageName();
+ ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M", app_image_arg}));
+ SetAppImageName("missing_app_image.art");
+ ASSERT_TRUE(Exec(kStatic, kModeAppImage, {}, kListAndCode, /*expect_failure=*/true));
+}
+
} // namespace art
diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h
index 359b060..7c5149d 100644
--- a/oatdump/oatdump_test.h
+++ b/oatdump/oatdump_test.h
@@ -107,8 +107,15 @@
return "ProfileTestMultiDex";
}
+ void SetAppImageName(const std::string& name) {
+ app_image_name_ = name;
+ }
+
std::string GetAppImageName() {
- return tmp_dir_ + "/" + GetAppBaseName() + ".art";
+ if (app_image_name_.empty()) {
+ app_image_name_ = tmp_dir_ + "/" + GetAppBaseName() + ".art";
+ }
+ return app_image_name_;
}
std::string GetAppOdexName() {
@@ -158,7 +165,8 @@
::testing::AssertionResult Exec(Flavor flavor,
Mode mode,
const std::vector<std::string>& args,
- Display display) {
+ Display display,
+ bool expect_failure = false) {
std::string file_path = GetExecutableFilePath(flavor, "oatdump");
if (!OS::FileExists(file_path.c_str())) {
@@ -322,8 +330,17 @@
if (res.stage != ForkAndExecResult::kFinished) {
return ::testing::AssertionFailure() << strerror(errno);
}
+ error_buf.push_back(0); // Make data a C string.
+
if (!res.StandardSuccess()) {
- return ::testing::AssertionFailure() << "Did not terminate successfully: " << res.status_code;
+ if (expect_failure && WIFEXITED(res.status_code)) {
+ // Avoid crash as valid exit.
+ return ::testing::AssertionSuccess();
+ }
+ return ::testing::AssertionFailure() << "Did not terminate successfully: " << res.status_code
+ << " " << error_buf.data();
+ } else if (expect_failure) {
+ return ::testing::AssertionFailure() << "Expected failure";
}
if (mode == kModeSymbolize) {
@@ -342,7 +359,6 @@
}
if (!result) {
oss << "Processed bytes " << total << ":" << std::endl;
- error_buf.push_back(0); // Make data a C string.
}
return result ? ::testing::AssertionSuccess()
@@ -350,6 +366,7 @@
}
std::string tmp_dir_;
+ std::string app_image_name_;
private:
std::string core_art_location_;