Revert "Remove old unquickening of vdex logic."
This reverts commit 537f477453823db37130f9c1562f328ad3360b6a.
Bug: 170086509
Reason for revert: Fails some tests.
Change-Id: I965884b5039f4bce42450091fce04d2c87129c02
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 1486fad..81db30d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1237,6 +1237,7 @@
input_vdex_file_ = VdexFile::Open(input_vdex_,
/* writable */ false,
/* low_4gb */ false,
+ DoEagerUnquickeningOfVdex(),
&error_msg);
}
@@ -1245,8 +1246,8 @@
? ReplaceFileExtension(oat_filename, "vdex")
: output_vdex_;
if (vdex_filename == input_vdex_ && output_vdex_.empty()) {
- use_existing_vdex_ = true;
- std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_filename.c_str()));
+ update_input_vdex_ = true;
+ std::unique_ptr<File> vdex_file(OS::OpenFileReadWrite(vdex_filename.c_str()));
vdex_files_.push_back(std::move(vdex_file));
} else {
std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_filename.c_str()));
@@ -1288,6 +1289,7 @@
"vdex",
/* writable */ false,
/* low_4gb */ false,
+ DoEagerUnquickeningOfVdex(),
&error_msg);
// If there's any problem with the passed vdex, just warn and proceed
// without it.
@@ -1299,20 +1301,15 @@
DCHECK_NE(output_vdex_fd_, -1);
std::string vdex_location = ReplaceFileExtension(oat_location_, "vdex");
- if (input_vdex_file_ != nullptr && output_vdex_fd_ == input_vdex_fd_) {
- use_existing_vdex_ = true;
- }
-
- std::unique_ptr<File> vdex_file(new File(DupCloexec(output_vdex_fd_),
- vdex_location,
- /* check_usage= */ true,
- /* read_only_mode= */ use_existing_vdex_));
+ std::unique_ptr<File> vdex_file(new File(
+ DupCloexec(output_vdex_fd_), vdex_location, /* check_usage */ true));
if (!vdex_file->IsOpened()) {
PLOG(ERROR) << "Failed to create vdex file: " << vdex_location;
return false;
}
-
- if (!use_existing_vdex_) {
+ if (input_vdex_file_ != nullptr && output_vdex_fd_ == input_vdex_fd_) {
+ update_input_vdex_ = true;
+ } else {
if (vdex_file->SetLength(0) != 0) {
PLOG(ERROR) << "Truncating vdex file " << vdex_location << " failed.";
vdex_file->Erase();
@@ -1324,6 +1321,26 @@
oat_filenames_.push_back(oat_location_);
}
+ // If we're updating in place a vdex file, be defensive and put an invalid vdex magic in case
+ // dex2oat gets killed.
+ // Note: we're only invalidating the magic data in the file, as dex2oat needs the rest of
+ // the information to remain valid.
+ if (update_input_vdex_) {
+ File* vdex_file = vdex_files_.back().get();
+ if (!vdex_file->PwriteFully(&VdexFile::VdexFileHeader::kVdexInvalidMagic,
+ arraysize(VdexFile::VdexFileHeader::kVdexInvalidMagic),
+ /*offset=*/ 0u)) {
+ PLOG(ERROR) << "Failed to invalidate vdex header. File: " << vdex_file->GetPath();
+ return false;
+ }
+
+ if (vdex_file->Flush() != 0) {
+ PLOG(ERROR) << "Failed to flush stream after invalidating header of vdex file."
+ << " File: " << vdex_file->GetPath();
+ return false;
+ }
+ }
+
if (dm_fd_ != -1 || !dm_file_location_.empty()) {
std::string error_msg;
if (dm_fd_ != -1) {
@@ -1372,12 +1389,9 @@
void EraseOutputFiles() {
for (auto& files : { &vdex_files_, &oat_files_ }) {
for (size_t i = 0; i < files->size(); ++i) {
- auto& file = (*files)[i];
- if (file != nullptr) {
- if (!file->ReadOnlyMode()) {
- file->Erase();
- }
- file.reset();
+ if ((*files)[i].get() != nullptr) {
+ (*files)[i]->Erase();
+ (*files)[i].reset();
}
}
}
@@ -1441,7 +1455,7 @@
if (!oat_writers_[i]->WriteAndOpenDexFiles(
vdex_files_[i].get(),
verify,
- use_existing_vdex_,
+ update_input_vdex_,
copy_dex_files_,
&opened_dex_files_map,
&opened_dex_files)) {
@@ -1690,15 +1704,12 @@
}
// Setup VerifierDeps for compilation and report if we fail to parse the data.
- // When we do profile guided optimizations, the compiler currently needs to run
- // full verification.
- if (!DoProfileGuidedOptimizations() && input_vdex_file_ != nullptr) {
+ if (!DoEagerUnquickeningOfVdex() && input_vdex_file_ != nullptr) {
std::unique_ptr<verifier::VerifierDeps> verifier_deps(
new verifier::VerifierDeps(dex_files, /*output_only=*/ false));
if (!verifier_deps->ParseStoredData(dex_files, input_vdex_file_->GetVerifierDepsData())) {
return dex2oat::ReturnCode::kOther;
}
- // We can do fast verification.
callbacks_->SetVerifierDeps(verifier_deps.release());
} else {
// Create the main VerifierDeps, here instead of in the compiler since we want to aggregate
@@ -1781,7 +1792,7 @@
// This means extract, no-vdex verify, and quicken, will use the individual compilation
// mode (to reduce RAM used by the compiler).
return compile_individually_ &&
- (!IsImage() && !use_existing_vdex_ &&
+ (!IsImage() && !update_input_vdex_ &&
compiler_options_->dex_files_for_oat_file_.size() > 1 &&
!CompilerFilter::IsAotCompilationEnabled(compiler_options_->GetCompilerFilter()));
}
@@ -2058,7 +2069,7 @@
oat_writer->Initialize(driver_.get(), image_writer_.get(), dex_files);
}
- if (!use_existing_vdex_) {
+ {
TimingLogger::ScopedTiming t2("dex2oat Write VDEX", timings_);
DCHECK(IsBootImage() || IsBootImageExtension() || oat_files_.size() == 1u);
verifier::VerifierDeps* verifier_deps = callbacks_->GetVerifierDeps();
@@ -2314,6 +2325,16 @@
return DoProfileGuidedOptimizations();
}
+ bool MayInvalidateVdexMetadata() const {
+ // DexLayout can invalidate the vdex metadata if changing the class def order is enabled, so
+ // we need to unquicken the vdex file eagerly, before passing it to dexlayout.
+ return DoDexLayoutOptimizations();
+ }
+
+ bool DoEagerUnquickeningOfVdex() const {
+ return MayInvalidateVdexMetadata() && dm_file_ == nullptr;
+ }
+
bool LoadProfile() {
DCHECK(HasProfileInput());
profile_load_attempted_ = true;
@@ -2908,7 +2929,7 @@
std::string classpath_dir_;
// Whether the given input vdex is also the output.
- bool use_existing_vdex_ = false;
+ bool update_input_vdex_ = false;
// By default, copy the dex to the vdex file only if dex files are
// compressed in APK.
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 3cab12d..083e1c9 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1762,6 +1762,7 @@
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
/*writable=*/ false,
/*low_4gb=*/ false,
+ /*unquicken=*/ false,
&error_msg));
ASSERT_TRUE(vdex != nullptr);
EXPECT_FALSE(vdex->HasDexSection()) << output_;
diff --git a/dex2oat/dex2oat_vdex_test.cc b/dex2oat/dex2oat_vdex_test.cc
index 895e9c2..1f486e6 100644
--- a/dex2oat/dex2oat_vdex_test.cc
+++ b/dex2oat/dex2oat_vdex_test.cc
@@ -73,6 +73,7 @@
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
/*writable=*/ false,
/*low_4gb=*/ false,
+ /*unquicken=*/ false,
&error_msg_));
// Check the vdex doesn't have dex.
if (vdex->HasDexSection()) {
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 7e7bca5..5ac2bbf 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -683,7 +683,7 @@
bool OatWriter::WriteAndOpenDexFiles(
File* vdex_file,
bool verify,
- bool use_existing_vdex,
+ bool update_input_vdex,
CopyOption copy_dex_files,
/*out*/ std::vector<MemMap>* opened_dex_files_map,
/*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
@@ -697,7 +697,7 @@
// Write DEX files into VDEX, mmap and open them.
std::vector<MemMap> dex_files_map;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!WriteDexFiles(vdex_file, use_existing_vdex, copy_dex_files, &dex_files_map) ||
+ if (!WriteDexFiles(vdex_file, update_input_vdex, copy_dex_files, &dex_files_map) ||
!OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
return false;
}
@@ -3103,7 +3103,7 @@
}
bool OatWriter::WriteDexFiles(File* file,
- bool use_existing_vdex,
+ bool update_input_vdex,
CopyOption copy_dex_files,
/*out*/ std::vector<MemMap>* opened_dex_files_map) {
TimingLogger::ScopedTiming split("Write Dex files", timings_);
@@ -3136,8 +3136,8 @@
if (profile_compilation_info_ != nullptr ||
compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
for (OatDexFile& oat_dex_file : oat_dex_files_) {
- // use_existing_vdex should not be used with compact dex and layout.
- CHECK(!use_existing_vdex)
+ // update_input_vdex disables compact dex and layout.
+ CHECK(!update_input_vdex)
<< "We should never update the input vdex when doing dexlayout or compact dex";
if (!LayoutDexFile(&oat_dex_file)) {
return false;
@@ -3202,7 +3202,7 @@
// Extend the file and include the full page at the end as we need to write
// additional data there and do not want to mmap that page twice.
size_t page_aligned_size = RoundUp(vdex_size_with_dex_files, kPageSize);
- if (!use_existing_vdex) {
+ if (!update_input_vdex) {
if (file->SetLength(page_aligned_size) != 0) {
PLOG(ERROR) << "Failed to resize vdex file " << file->GetPath();
return false;
@@ -3233,7 +3233,7 @@
vdex_size_ = RoundUp(vdex_size_, 4u);
size_dex_file_alignment_ += vdex_size_ - old_vdex_size;
// Write the actual dex file.
- if (!WriteDexFile(file, &oat_dex_file, use_existing_vdex)) {
+ if (!WriteDexFile(file, &oat_dex_file, update_input_vdex)) {
return false;
}
}
@@ -3241,27 +3241,27 @@
// Write shared dex file data section and fix up the dex file headers.
if (shared_data_size != 0u) {
DCHECK_EQ(RoundUp(vdex_size_, 4u), vdex_dex_shared_data_offset_);
- if (!use_existing_vdex) {
+ if (!update_input_vdex) {
memset(vdex_begin_ + vdex_size_, 0, vdex_dex_shared_data_offset_ - vdex_size_);
}
size_dex_file_alignment_ += vdex_dex_shared_data_offset_ - vdex_size_;
vdex_size_ = vdex_dex_shared_data_offset_;
if (dex_container_ != nullptr) {
- CHECK(!use_existing_vdex) << "Use existing vdex should have empty dex container";
+ CHECK(!update_input_vdex) << "Update input vdex should have empty dex container";
CHECK(compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone);
DexContainer::Section* const section = dex_container_->GetDataSection();
DCHECK_EQ(shared_data_size, section->Size());
memcpy(vdex_begin_ + vdex_size_, section->Begin(), shared_data_size);
section->Clear();
dex_container_.reset();
- } else if (!use_existing_vdex) {
+ } else if (!update_input_vdex) {
// If we are not updating the input vdex, write out the shared data section.
memcpy(vdex_begin_ + vdex_size_, raw_dex_file_shared_data_begin, shared_data_size);
}
vdex_size_ += shared_data_size;
size_dex_file_ += shared_data_size;
- if (!use_existing_vdex) {
+ if (!update_input_vdex) {
// Fix up the dex headers to have correct offsets to the data section.
for (OatDexFile& oat_dex_file : oat_dex_files_) {
DexFile::Header* header =
@@ -3297,22 +3297,22 @@
bool OatWriter::WriteDexFile(File* file,
OatDexFile* oat_dex_file,
- bool use_existing_vdex) {
+ bool update_input_vdex) {
DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
if (oat_dex_file->source_.IsZipEntry()) {
- DCHECK(!use_existing_vdex);
+ DCHECK(!update_input_vdex);
if (!WriteDexFile(file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
return false;
}
} else if (oat_dex_file->source_.IsRawFile()) {
- DCHECK(!use_existing_vdex);
+ DCHECK(!update_input_vdex);
if (!WriteDexFile(file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
return false;
}
} else {
DCHECK(oat_dex_file->source_.IsRawData());
const uint8_t* raw_data = oat_dex_file->source_.GetRawData();
- if (!WriteDexFile(oat_dex_file, raw_data, use_existing_vdex)) {
+ if (!WriteDexFile(oat_dex_file, raw_data, update_input_vdex)) {
return false;
}
}
@@ -3447,14 +3447,14 @@
bool OatWriter::WriteDexFile(OatDexFile* oat_dex_file,
const uint8_t* dex_file,
- bool use_existing_vdex) {
+ bool update_input_vdex) {
// Note: The raw data has already been checked to contain the header
// and all the data that the header specifies as the file size.
DCHECK(dex_file != nullptr);
DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
DCHECK_EQ(oat_dex_file->dex_file_size_, AsUnalignedDexFileHeader(dex_file)->file_size_);
- if (use_existing_vdex) {
+ if (update_input_vdex) {
// The vdex already contains the dex code, no need to write it again.
} else {
uint8_t* raw_output = vdex_begin_ + oat_dex_file->dex_file_offset_;
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index ad14d60..87174eb 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -157,11 +157,11 @@
// Write raw dex files to the vdex file, mmap the file and open the dex files from it.
// The `verify` setting dictates whether the dex file verifier should check the dex files.
// This is generally the case, and should only be false for tests.
- // If `use_existing_vdex` is true, then this method won't actually write the dex files,
+ // If `update_input_vdex` is true, then this method won't actually write the dex files,
// and the compiler will just re-use the existing vdex file.
bool WriteAndOpenDexFiles(File* vdex_file,
bool verify,
- bool use_existing_vdex,
+ bool update_input_vdex,
CopyOption copy_dex_files,
/*out*/ std::vector<MemMap>* opened_dex_files_map,
/*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
@@ -276,12 +276,12 @@
// If `update_input_vdex` is true, then this method won't actually write the dex files,
// and the compiler will just re-use the existing vdex file.
bool WriteDexFiles(File* file,
- bool use_existing_vdex,
+ bool update_input_vdex,
CopyOption copy_dex_files,
/*out*/ std::vector<MemMap>* opened_dex_files_map);
bool WriteDexFile(File* file,
OatDexFile* oat_dex_file,
- bool use_existing_vdex);
+ bool update_input_vdex);
bool LayoutDexFile(OatDexFile* oat_dex_file);
bool WriteDexFile(File* file,
OatDexFile* oat_dex_file,
@@ -291,7 +291,7 @@
File* dex_file);
bool WriteDexFile(OatDexFile* oat_dex_file,
const uint8_t* dex_file,
- bool use_existing_vdex);
+ bool update_input_vdex);
bool OpenDexFiles(File* file,
bool verify,
/*inout*/ std::vector<MemMap>* opened_dex_files_map,
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 9aa0353..a9ea27d 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -330,6 +330,7 @@
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
/*writable=*/ false,
/*low_4gb=*/ false,
+ /*unquicken= */ false,
&error_msg /*out*/));
if (vdex == nullptr) {
std::cerr << "Could not open vdex file "
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index bdc7863..9bb7b8b 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -99,10 +99,7 @@
// Setting this to false disables class def layout entirely, which is stronger than strictly
// necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550).
- // This should never be set for a device build, as changing class defs ids
- // conflict with profiles and verification passed by Play.
static constexpr bool kChangeClassDefOrder = false;
- static_assert(!(kIsTargetBuild && kChangeClassDefOrder), "Never set class reordering on target");
DexLayout(Options& options,
ProfileCompilationInfo* info,
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index c80feaf..54e3712 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -190,6 +190,10 @@
}
private:
+ // Returns true if we want to remove quickened opcodes before loading the VDEX file, false
+ // otherwise.
+ bool ShouldUnquickenVDex() const;
+
DISALLOW_COPY_AND_ASSIGN(OatFileBase);
};
@@ -276,6 +280,23 @@
return ret.release();
}
+bool OatFileBase::ShouldUnquickenVDex() const {
+ // We sometimes load oat files without a runtime (eg oatdump) and don't want to do anything in
+ // that case. If we are debuggable there are no -quick opcodes to unquicken. If the runtime is not
+ // debuggable we don't care whether there are -quick opcodes or not so no need to do anything.
+ Runtime* runtime = Runtime::Current();
+ return (runtime != nullptr && runtime->IsJavaDebuggable()) &&
+ // Note: This is called before `OatFileBase::Setup()` where we validate the
+ // oat file contents. Check that we have at least a valid header, including
+ // oat file version, to avoid parsing the key-value store for a different
+ // version (out-of-date oat file) which can lead to crashes. b/179221298.
+ // TODO: While this is a poor workaround and the correct solution would be
+ // to postpone the unquickening check until after `OatFileBase::Setup()`,
+ // we prefer to avoid larger rewrites because quickening is deprecated and
+ // should be removed completely anyway. b/170086509
+ (GetOatHeader().IsValid() && !IsDebuggable());
+}
+
bool OatFileBase::LoadVdex(const std::string& vdex_filename,
bool writable,
bool low_4gb,
@@ -286,6 +307,7 @@
vdex_filename,
writable,
low_4gb,
+ ShouldUnquickenVDex(),
error_msg);
if (vdex_.get() == nullptr) {
*error_msg = StringPrintf("Failed to load vdex file '%s' %s",
@@ -316,6 +338,7 @@
vdex_filename,
writable,
low_4gb,
+ ShouldUnquickenVDex(),
error_msg);
if (vdex_.get() == nullptr) {
*error_msg = "Failed opening vdex file.";
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index c303a7b..414b24e 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -877,6 +877,7 @@
filename_,
/*writable=*/ false,
/*low_4gb=*/ false,
+ /*unquicken=*/ false,
&error_msg);
}
}
@@ -884,6 +885,7 @@
vdex = VdexFile::Open(filename_,
/*writable=*/ false,
/*low_4gb=*/ false,
+ /*unquicken=*/ false,
&error_msg);
}
if (vdex == nullptr) {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index aaa6600..f172ee0 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -497,6 +497,7 @@
vdex_file = VdexFile::Open(vdex_path,
/* writable= */ false,
/* low_4gb= */ false,
+ /* unquicken= */ false,
&error_msg);
if (vdex_file == nullptr) {
LOG(WARNING) << "Failed to open vdex " << vdex_path << ": " << error_msg;
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index ba80886..0afa131 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -72,6 +72,7 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg) {
ScopedTrace trace(("VdexFile::OpenAtAddress " + vdex_filename).c_str());
if (!OS::FileExists(vdex_filename.c_str())) {
@@ -105,6 +106,7 @@
vdex_filename,
writable,
low_4gb,
+ unquicken,
error_msg);
}
@@ -116,6 +118,7 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg) {
if (mmap_addr != nullptr && mmap_size < vdex_length) {
LOG(WARNING) << "Insufficient pre-allocated space to mmap vdex.";
@@ -123,6 +126,7 @@
mmap_reuse = false;
}
CHECK(!mmap_reuse || mmap_addr != nullptr);
+ CHECK(!(writable && unquicken)) << "We don't want to be writing unquickened files out to disk!";
// Start as PROT_WRITE so we can mprotect back to it if we want to.
MemMap mmap = MemMap::MapFileAtAddress(
mmap_addr,
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 3ccbfa5..35be4fb 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -194,6 +194,7 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg);
// Returns nullptr if the vdex file cannot be opened or is not valid.
@@ -206,12 +207,14 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg);
// Returns nullptr if the vdex file cannot be opened or is not valid.
static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg) {
return OpenAtAddress(nullptr,
0,
@@ -219,6 +222,7 @@
vdex_filename,
writable,
low_4gb,
+ unquicken,
error_msg);
}
@@ -228,6 +232,7 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg) {
return OpenAtAddress(nullptr,
0,
@@ -237,6 +242,7 @@
vdex_filename,
writable,
low_4gb,
+ unquicken,
error_msg);
}
diff --git a/runtime/vdex_file_test.cc b/runtime/vdex_file_test.cc
index 565487e..9d92b42 100644
--- a/runtime/vdex_file_test.cc
+++ b/runtime/vdex_file_test.cc
@@ -36,11 +36,12 @@
tmp.GetFilename(),
/*writable=*/false,
/*low_4gb=*/false,
+ /*unquicken=*/false,
&error_msg);
EXPECT_TRUE(vdex == nullptr);
vdex = VdexFile::Open(
- tmp.GetFilename(), /*writable=*/false, /*low_4gb=*/false, &error_msg);
+ tmp.GetFilename(), /*writable=*/false, /*low_4gb=*/false, /*unquicken=*/ false, &error_msg);
EXPECT_TRUE(vdex == nullptr);
}