Add flock(2)ing on dex-cache files to prevent races

Bug: 9071417
Change-Id: I1ee9ff281867f90fba7a8ed8bbf06b33ac29d511
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index e48806e..ffe1f72 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -62,7 +62,7 @@
 
   ASSERT_EQ(0, dlclose(dl_oat_so));
 
-  UniquePtr<File> file(OS::OpenFile(elf_filename.c_str(), false));
+  UniquePtr<File> file(OS::OpenFileForReading(elf_filename.c_str()));
   ASSERT_TRUE(file.get() != NULL);
   {
     UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false));
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index a40e3fc..4e9ae54 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -79,7 +79,7 @@
     dex_caches_.insert(dex_cache);
   }
 
-  UniquePtr<File> oat_file(OS::OpenFile(oat_filename.c_str(), true, false));
+  UniquePtr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
   if (oat_file.get() == NULL) {
     LOG(ERROR) << "Failed to open oat file " << oat_filename << " for " << oat_location;
     return false;
@@ -145,7 +145,7 @@
   PatchOatCodeAndMethods();
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
 
-  UniquePtr<File> image_file(OS::OpenFile(image_filename.c_str(), true));
+  UniquePtr<File> image_file(OS::CreateEmptyFile(image_filename.c_str()));
   if (image_file.get() == NULL) {
     LOG(ERROR) << "Failed to open image file " << image_filename;
     return false;
diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc
index 7542b84..139100b 100644
--- a/compiler/llvm/llvm_compilation_unit.cc
+++ b/compiler/llvm/llvm_compilation_unit.cc
@@ -155,7 +155,7 @@
   std::string bitcode;
   DumpBitcodeToString(bitcode);
   std::string filename(StringPrintf("%s/Art%u.bc", DumpDirectory().c_str(), cunit_id_));
-  UniquePtr<File> output(OS::OpenFile(filename.c_str(), true));
+  UniquePtr<File> output(OS::CreateEmptyFile(filename.c_str()));
   output->WriteFully(bitcode.data(), bitcode.size());
   LOG(INFO) << ".bc file written successfully: " << filename;
 }
@@ -182,7 +182,7 @@
   if (kDumpELF) {
     // Dump the ELF image for debugging
     std::string filename(StringPrintf("%s/Art%u.o", DumpDirectory().c_str(), cunit_id_));
-    UniquePtr<File> output(OS::OpenFile(filename.c_str(), true));
+    UniquePtr<File> output(OS::CreateEmptyFile(filename.c_str()));
     output->WriteFully(elf_object_.data(), elf_object_.size());
     LOG(INFO) << ".o file written successfully: " << filename;
   }
diff --git a/compiler/sea_ir/debug/dot_gen.h b/compiler/sea_ir/debug/dot_gen.h
index 675d83d..5270582 100644
--- a/compiler/sea_ir/debug/dot_gen.h
+++ b/compiler/sea_ir/debug/dot_gen.h
@@ -103,7 +103,7 @@
     LOG(INFO) << "Starting to write SEA string to file.";
     DotGenerationVisitor dgv = DotGenerationVisitor(&options_, types);
     graph->Accept(&dgv);
-    art::File* file = art::OS::OpenFile(filename.c_str(), true, true);
+    art::File* file = art::OS::OpenFile(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC);
     art::FileOutputStream fos(file);
     std::string graph_as_string = dgv.GetResult();
     graph_as_string += "}";
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 25cfda6..ceb6bf6 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -313,7 +313,7 @@
       oat_data_begin = image_writer.GetOatDataBegin();
     }
 
-    UniquePtr<File> oat_file(OS::OpenFile(oat_filename.c_str(), true, false));
+    UniquePtr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
     if (oat_file.get() == NULL) {
       PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
       return false;
@@ -808,7 +808,7 @@
   UniquePtr<File> oat_file;
   bool create_file = !oat_unstripped.empty();  // as opposed to using open file descriptor
   if (create_file) {
-    oat_file.reset(OS::OpenFile(oat_unstripped.c_str(), true));
+    oat_file.reset(OS::CreateEmptyFile(oat_unstripped.c_str()));
     if (oat_location.empty()) {
       oat_location = oat_filename;
     }
@@ -1023,8 +1023,8 @@
   if (oat_unstripped != oat_stripped) {
     timings.NewSplit("dex2oat OatFile copy");
     oat_file.reset();
-    UniquePtr<File> in(OS::OpenFile(oat_unstripped.c_str(), false));
-    UniquePtr<File> out(OS::OpenFile(oat_stripped.c_str(), true));
+     UniquePtr<File> in(OS::OpenFileForReading(oat_unstripped.c_str()));
+    UniquePtr<File> out(OS::CreateEmptyFile(oat_stripped.c_str()));
     size_t buffer_size = 8192;
     UniquePtr<uint8_t> buffer(new uint8_t[buffer_size]);
     while (true) {
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 67398af..fbfdfd9 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -777,7 +777,7 @@
       os_ = saved_os;
     }
     os << "STATS:\n" << std::flush;
-    UniquePtr<File> file(OS::OpenFile(image_filename_.c_str(), false));
+    UniquePtr<File> file(OS::OpenFileForReading(image_filename_.c_str()));
     stats_.file_bytes = file->GetLength();
     size_t header_bytes = sizeof(ImageHeader);
     stats_.header_bytes = header_bytes;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index bd36a6c..039e7bc 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -659,6 +659,7 @@
       CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation();
     }
   }
+  VLOG(class_linker) << "Registering " << oat_file.GetLocation();
   oat_files_.push_back(&oat_file);
 }
 
@@ -694,22 +695,39 @@
   UniquePtr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL,
                                             !Runtime::Current()->IsCompiler()));
   if (oat_file.get() == NULL) {
+    VLOG(class_linker) << "Failed to find existing oat file at " << oat_location;
     return NULL;
   }
   Runtime* runtime = Runtime::Current();
   const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
-  if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() != image_header.GetOatChecksum()) {
+  uint32_t expected_image_oat_checksum = image_header.GetOatChecksum();
+  uint32_t actual_image_oat_checksum = oat_file->GetOatHeader().GetImageFileLocationOatChecksum();
+  if (expected_image_oat_checksum != actual_image_oat_checksum) {
+    VLOG(class_linker) << "Failed to find oat file at " << oat_location
+                       << " with expected image oat checksum of " << expected_image_oat_checksum
+                       << ", found " << actual_image_oat_checksum;
     return NULL;
   }
-  if (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin()
-      != reinterpret_cast<uint32_t>(image_header.GetOatDataBegin())) {
+
+  uint32_t expected_image_oat_offset = reinterpret_cast<uint32_t>(image_header.GetOatDataBegin());
+  uint32_t actual_image_oat_offset = oat_file->GetOatHeader().GetImageFileLocationOatDataBegin();
+  if (expected_image_oat_offset != actual_image_oat_offset) {
+    VLOG(class_linker) << "Failed to find oat file at " << oat_location
+                       << " with expected image oat offset " << expected_image_oat_offset
+                       << ", found " << actual_image_oat_offset;
     return NULL;
   }
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
   if (oat_dex_file == NULL) {
+    VLOG(class_linker) << "Failed to find oat file at " << oat_location << " containing " << dex_location;
     return NULL;
   }
-  if (oat_dex_file->GetDexFileLocationChecksum() != dex_location_checksum) {
+  uint32_t expected_dex_checksum = dex_location_checksum;
+  uint32_t actual_dex_checksum = oat_dex_file->GetDexFileLocationChecksum();
+  if (expected_dex_checksum != actual_dex_checksum) {
+    VLOG(class_linker) << "Failed to find oat file at " << oat_location
+                       << " with expected dex checksum of " << expected_dex_checksum
+                       << ", found " << actual_dex_checksum;
     return NULL;
   }
   RegisterOatFileLocked(*oat_file.release());
@@ -722,6 +740,58 @@
   return FindOrCreateOatFileForDexLocationLocked(dex_location, oat_location);
 }
 
+class ScopedFlock {
+ public:
+  ScopedFlock() {}
+
+  bool Init(const std::string& filename) {
+    while (true) {
+      file_.reset(OS::OpenFileWithFlags(filename.c_str(), O_CREAT | O_RDWR));
+      if (file_.get() == NULL) {
+        LOG(ERROR) << "Failed to open file: " << filename;
+        return false;
+      }
+      int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_EX));
+      if (flock_result != 0) {
+        PLOG(ERROR) << "Failed to lock file: " << filename;
+        return false;
+      }
+      struct stat fstat_stat;
+      int fstat_result = TEMP_FAILURE_RETRY(fstat(file_->Fd(), &fstat_stat));
+      if (fstat_result != 0) {
+        PLOG(ERROR) << "Failed to fstat: " << filename;
+        return false;
+      }
+      struct stat stat_stat;
+      int stat_result = TEMP_FAILURE_RETRY(stat(filename.c_str(), &stat_stat));
+      if (stat_result != 0) {
+        PLOG(WARNING) << "Failed to stat, will retry: " << filename;
+        // ENOENT can happen if someone racing with us unlinks the file we created so just retry.
+        continue;
+      }
+      if (fstat_stat.st_dev != stat_stat.st_dev || fstat_stat.st_ino != stat_stat.st_ino) {
+        LOG(WARNING) << "File changed while locking, will retry: " << filename;
+        continue;
+      }
+      return true;
+    }
+  }
+
+  File& GetFile() {
+    return *file_;
+  }
+
+  ~ScopedFlock() {
+    int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_UN));
+    CHECK_EQ(0, flock_result);
+  }
+
+ private:
+  UniquePtr<File> file_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedFlock);
+};
+
 const DexFile* ClassLinker::FindOrCreateOatFileForDexLocationLocked(const std::string& dex_location,
                                                                     const std::string& oat_location) {
   uint32_t dex_location_checksum;
@@ -730,6 +800,17 @@
     return NULL;
   }
 
+  // We play a locking game here so that if two different processes
+  // race to generate (or worse, one tries to open a partial generated
+  // file) we will be okay. This is actually common with apps that use
+  // DexClassLoader to work around the dex method reference limit and
+  // that have a background service running in a separate process.
+  ScopedFlock scoped_flock;
+  if (!scoped_flock.Init(oat_location)) {
+    LOG(ERROR) << "Failed to open locked oat file: " << oat_location;
+    return NULL;
+  }
+
   // Check if we already have an up-to-date output file
   const DexFile* dex_file = FindDexFileInOatLocation(dex_location,
                                                      dex_location_checksum,
@@ -739,12 +820,8 @@
   }
 
   // Generate the output oat file for the dex file
-  UniquePtr<File> file(OS::OpenFile(oat_location.c_str(), true));
-  if (file.get() == NULL) {
-    LOG(ERROR) << "Failed to create oat file: " << oat_location;
-    return NULL;
-  }
-  if (!GenerateOatFile(dex_location, file->Fd(), oat_location)) {
+  VLOG(class_linker) << "Generating oat file " << oat_location << " for " << dex_location;
+  if (!GenerateOatFile(dex_location, scoped_flock.GetFile().Fd(), oat_location)) {
     LOG(ERROR) << "Failed to generate oat file: " << oat_location;
     return NULL;
   }
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index e7899ec..6449493 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -64,7 +64,7 @@
   CHECK(dex_bytes.get() != NULL);
 
   // write to provided file
-  UniquePtr<File> file(OS::OpenFile(location.c_str(), true));
+  UniquePtr<File> file(OS::CreateEmptyFile(location.c_str()));
   CHECK(file.get() != NULL);
   if (!file->WriteFully(dex_bytes.get(), length)) {
     PLOG(FATAL) << "Failed to write base64 as dex file";
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 6b8c41e..bf0fffa 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -269,7 +269,10 @@
 }
 
 void ThrowStackOverflowError(Thread* self) {
-  CHECK(!self->IsHandlingStackOverflow()) << "Recursive stack overflow.";
+  if (self->IsHandlingStackOverflow()) {
+      LOG(ERROR) << "Recursive stack overflow.";
+      // We don't fail here because SetStackEndForStackOverflow will print better diagnostics.
+  }
 
   if (Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()) {
     // Remove extra entry pushed onto second stack during method tracing.
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 22562df..f959cff 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -160,7 +160,7 @@
     LOG(INFO) << "ImageSpace::Init entering image_file_name=" << image_file_name;
   }
 
-  UniquePtr<File> file(OS::OpenFile(image_file_name.c_str(), false));
+  UniquePtr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
   if (file.get() == NULL) {
     LOG(ERROR) << "Failed to open " << image_file_name;
     return NULL;
diff --git a/runtime/image_test.cc b/runtime/image_test.cc
index 334f7ab..dcafc19 100644
--- a/runtime/image_test.cc
+++ b/runtime/image_test.cc
@@ -65,7 +65,7 @@
     }
   }
   // Workound bug that mcld::Linker::emit closes tmp_elf by reopening as tmp_oat.
-  UniquePtr<File> tmp_oat(OS::OpenFile(tmp_elf.GetFilename().c_str(), true, false));
+  UniquePtr<File> tmp_oat(OS::OpenFileReadWrite(tmp_elf.GetFilename().c_str()));
   ASSERT_TRUE(tmp_oat.get() != NULL);
 
   ScratchFile tmp_image;
@@ -80,7 +80,7 @@
   }
 
   {
-    UniquePtr<File> file(OS::OpenFile(tmp_image.GetFilename().c_str(), false));
+    UniquePtr<File> file(OS::OpenFileForReading(tmp_image.GetFilename().c_str()));
     ASSERT_TRUE(file.get() != NULL);
     ImageHeader image_header;
     file->ReadFully(&image_header, sizeof(image_header));
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index dc3573d..061dfb8 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -84,7 +84,7 @@
   void operator=(const NullableScopedUtfChars&);
 };
 
-static jint DexFile_openDexFile(JNIEnv* env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
+static jint DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
   ScopedUtfChars sourceName(env, javaSourceName);
   if (sourceName.c_str() == NULL) {
     return 0;
@@ -141,21 +141,25 @@
   ScopedObjectAccess soa(env);
   const DexFile* dex_file = toDexFile(cookie);
   if (dex_file == NULL) {
+    VLOG(class_linker) << "Failed to find dex_file";
     return NULL;
   }
   ScopedUtfChars class_name(env, javaName);
   if (class_name.c_str() == NULL) {
+    VLOG(class_linker) << "Failed to find class_name";
     return NULL;
   }
   const std::string descriptor(DotToDescriptor(class_name.c_str()));
   const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
   if (dex_class_def == NULL) {
+    VLOG(class_linker) << "Failed to find dex_class_def";
     return NULL;
   }
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   class_linker->RegisterDexFile(*dex_file);
   mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
   mirror::Class* result = class_linker->DefineClass(descriptor, class_loader, *dex_file, *dex_class_def);
+  VLOG(class_linker) << "DexFile_defineClassNative returning " << result;
   return soa.AddLocalReference<jclass>(result);
 }
 
@@ -300,7 +304,7 @@
   NATIVE_METHOD(DexFile, defineClassNative, "(Ljava/lang/String;Ljava/lang/ClassLoader;I)Ljava/lang/Class;"),
   NATIVE_METHOD(DexFile, getClassNameList, "(I)[Ljava/lang/String;"),
   NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"),
-  NATIVE_METHOD(DexFile, openDexFile, "(Ljava/lang/String;Ljava/lang/String;I)I"),
+  NATIVE_METHOD(DexFile, openDexFileNative, "(Ljava/lang/String;Ljava/lang/String;I)I"),
 };
 
 void register_dalvik_system_DexFile(JNIEnv* env) {
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 1f34317..afa823d 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -74,7 +74,7 @@
   //
   // On host, dlopen is expected to fail when cross compiling, so fall back to OpenElfFile.
   // This won't work for portable runtime execution because it doesn't process relocations.
-  UniquePtr<File> file(OS::OpenFile(filename.c_str(), false, false));
+  UniquePtr<File> file(OS::OpenFileForReading(filename.c_str()));
   if (file.get() == NULL) {
     return NULL;
   }
@@ -125,11 +125,13 @@
 bool OatFile::Dlopen(const std::string& elf_filename, byte* requested_base) {
   char* absolute_path = realpath(elf_filename.c_str(), NULL);
   if (absolute_path == NULL) {
+    VLOG(class_linker) << "Failed to find absolute path for " << elf_filename;
     return false;
   }
   dlopen_handle_ = dlopen(absolute_path, RTLD_NOW);
   free(absolute_path);
   if (dlopen_handle_ == NULL) {
+    VLOG(class_linker) << "Failed to dlopen " << elf_filename << ": " << dlerror();
     return false;
   }
   begin_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatdata"));
@@ -319,7 +321,14 @@
   Table::const_iterator it = oat_dex_files_.find(dex_file_location);
   if (it == oat_dex_files_.end()) {
     if (warn_if_not_found) {
-      LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_file_location;
+      LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_file_location
+                   << " in OatFile " << GetLocation();
+      if (kIsDebugBuild) {
+        for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it) {
+          LOG(WARNING) << "OatFile " << GetLocation()
+                       << " contains OatDexFile " << it->second->GetDexFileLocation();
+        }
+      }
     }
     return NULL;
   }
@@ -360,11 +369,11 @@
   uint32_t oat_class_offset = oat_class_offsets_pointer_[class_def_index];
 
   const byte* oat_class_pointer = oat_file_->Begin() + oat_class_offset;
-  CHECK_LT(oat_class_pointer, oat_file_->End());
+  CHECK_LT(oat_class_pointer, oat_file_->End()) << oat_file_->GetLocation();
   mirror::Class::Status status = *reinterpret_cast<const mirror::Class::Status*>(oat_class_pointer);
 
   const byte* methods_pointer = oat_class_pointer + sizeof(status);
-  CHECK_LT(methods_pointer, oat_file_->End());
+  CHECK_LT(methods_pointer, oat_file_->End()) << oat_file_->GetLocation();
 
   return new OatClass(oat_file_,
                       status,
diff --git a/runtime/os.h b/runtime/os.h
index 6767566..6248d5f 100644
--- a/runtime/os.h
+++ b/runtime/os.h
@@ -29,8 +29,17 @@
 
 class OS {
  public:
-  // Open a file. The returned pointer must be deleted by the caller.
-  static File* OpenFile(const char* name, bool writable, bool create = true);
+  // Open an existing file with read only access.
+  static File* OpenFileForReading(const char* name);
+
+  // Open an existing file with read/write access.
+  static File* OpenFileReadWrite(const char* name);
+
+  // Create an empty file with read/write access.
+  static File* CreateEmptyFile(const char* name);
+
+  // Open a file with the specified open(2) flags.
+  static File* OpenFileWithFlags(const char* name, int flags);
 
   // Check if a file exists.
   static bool FileExists(const char* name);
diff --git a/runtime/os_linux.cc b/runtime/os_linux.cc
index d3a1ccb..7ce17e0 100644
--- a/runtime/os_linux.cc
+++ b/runtime/os_linux.cc
@@ -27,17 +27,20 @@
 
 namespace art {
 
-File* OS::OpenFile(const char* name, bool writable, bool create) {
+File* OS::OpenFileForReading(const char* name) {
+  return OpenFileWithFlags(name, O_RDONLY);
+}
+
+File* OS::OpenFileReadWrite(const char* name) {
+  return OpenFileWithFlags(name, O_RDWR);
+}
+
+File* OS::CreateEmptyFile(const char* name) {
+  return OpenFileWithFlags(name, O_RDWR | O_CREAT | O_TRUNC);
+}
+
+File* OS::OpenFileWithFlags(const char* name, int flags) {
   CHECK(name != NULL);
-  int flags = 0;
-  if (writable) {
-    flags |= O_RDWR;
-    if (create) {
-      flags |= (O_CREAT | O_TRUNC);
-    }
-  } else {
-    flags |= O_RDONLY;
-  }
   UniquePtr<File> file(new File);
   if (!file->Open(name, flags, 0666)) {
     return NULL;
diff --git a/runtime/output_stream_test.cc b/runtime/output_stream_test.cc
index c9e0ede..8da2ac9 100644
--- a/runtime/output_stream_test.cc
+++ b/runtime/output_stream_test.cc
@@ -62,7 +62,7 @@
   FileOutputStream output_stream(tmp.GetFile());
   SetOutputStream(output_stream);
   GenerateTestOutput();
-  UniquePtr<File> in(OS::OpenFile(tmp.GetFilename().c_str(), false));
+  UniquePtr<File> in(OS::OpenFileForReading(tmp.GetFilename().c_str()));
   EXPECT_TRUE(in.get() != NULL);
   std::vector<uint8_t> actual(in->GetLength());
   bool readSuccess = in->ReadFully(&actual[0], actual.size());
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 7e3afb5..48e595f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2218,11 +2218,13 @@
 
 // Set the stack end to that to be used during a stack overflow
 void Thread::SetStackEndForStackOverflow() {
-  // During stack overflow we allow use of the full stack
+  // During stack overflow we allow use of the full stack.
   if (stack_end_ == stack_begin_) {
-    DumpStack(std::cerr);
-    LOG(FATAL) << "Need to increase kStackOverflowReservedBytes (currently "
-               << kStackOverflowReservedBytes << ")";
+    // However, we seem to have already extended to use the full stack.
+    LOG(ERROR) << "Need to increase kStackOverflowReservedBytes (currently "
+               << kStackOverflowReservedBytes << ")?";
+    DumpStack(LOG(ERROR));
+    LOG(FATAL) << "Recursive stack overflow.";
   }
 
   stack_end_ = stack_begin_;
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 29765c9..13e2bf6 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -318,7 +318,7 @@
   UniquePtr<File> trace_file;
   if (!direct_to_ddms) {
     if (trace_fd < 0) {
-      trace_file.reset(OS::OpenFile(trace_filename, true));
+      trace_file.reset(OS::CreateEmptyFile(trace_filename));
     } else {
       trace_file.reset(new File(trace_fd, "tracefile"));
       trace_file->DisableAutoClose();
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 87cd21c..6856bb7 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1229,6 +1229,7 @@
 
 bool IsValidOatFilename(const std::string& filename) {
   return (EndsWith(filename, ".odex") ||
+          EndsWith(filename, ".dex") ||
           EndsWith(filename, ".oat") ||
           EndsWith(filename, DexFile::kClassesDex));
 }
diff --git a/test/Android.mk b/test/Android.mk
index 87e15a8..596c411 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -111,7 +111,7 @@
 	$(hide) rm /tmp/test-art-target-oat-$(1)
 
 $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).odex: $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar $(HOST_CORE_IMG_OUT) | $(DEX2OAT)
-	$(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$$< --oat-file=$$@ --instruction-set=$(HOST_ARCH) --host --host-prefix="" --android-root=$(HOST_OUT)
+	$(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$(PWD)/$$< --oat-file=$(PWD)/$$@ --instruction-set=$(HOST_ARCH) --host --host-prefix="" --android-root=$(HOST_OUT)
 
 .PHONY: test-art-host-oat-default-$(1)
 test-art-host-oat-default-$(1): $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).odex test-art-host-dependencies