ART: More ELF and oat file safety measures

In an ELF file, look for a shstrtab section when loading in
program-header-only mode. If the section is outside the file size,
it strongly indicates a broken compile.

When compiling oat files in the class linker, explicitly unlink
on failure. This should catch cases when dex2oat is killed or
crashes and doesn't have a chance to delete its (partial) output.

Bug: 15567083
Change-Id: Ia0c75f151d91c6f26a71696967255d6d409ca882
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index cb2831c..cd1a93a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -19,6 +19,7 @@
 #include <fcntl.h>
 #include <sys/file.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include <deque>
 #include <memory>
 #include <string>
@@ -662,7 +663,14 @@
     argv.push_back(compiler_options[i].c_str());
   }
 
-  return Exec(argv, error_msg);
+  if (!Exec(argv, error_msg)) {
+    // Manually delete the file. Ensures there is no garbage left over if the process unexpectedly
+    // died. Ignore unlink failure, propagate the original error.
+    TEMP_FAILURE_RETRY(unlink(oat_cache_filename));
+    return false;
+  }
+
+  return true;
 }
 
 const OatFile* ClassLinker::RegisterOatFile(const OatFile* oat_file) {
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 6ec0712..29628f1 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -432,6 +432,20 @@
     return false;
   }
 
+  // We'd also like to confirm a shstrtab in program_header_only_ mode (else Open() does this for
+  // us). This is usually the last in an oat file, and a good indicator of whether writing was
+  // successful (or the process crashed and left garbage).
+  if (program_header_only_) {
+    // It might not be mapped, but we can compare against the file size.
+    int64_t offset = static_cast<int64_t>(GetHeader().e_shoff +
+                                          (GetHeader().e_shstrndx * GetHeader().e_shentsize));
+    if (offset >= file_->GetLength()) {
+      *error_msg = StringPrintf("Shstrtab is not in the mapped ELF file: '%s'",
+                                file_->GetPath().c_str());
+      return false;
+    }
+  }
+
   return true;
 }