Home | History | Annotate | Download | only in patchoat
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <openssl/sha.h>
     18 #include <dirent.h>
     19 #include <sys/types.h>
     20 
     21 #include <string>
     22 #include <vector>
     23 
     24 #include "android-base/stringprintf.h"
     25 #include "android-base/strings.h"
     26 
     27 #include "base/leb128.h"
     28 #include "dexopt_test.h"
     29 #include "runtime.h"
     30 
     31 #include <gtest/gtest.h>
     32 
     33 namespace art {
     34 
     35 using android::base::StringPrintf;
     36 
     37 class PatchoatTest : public DexoptTest {
     38  public:
     39   static bool ListDirFilesEndingWith(
     40       const std::string& dir,
     41       const std::string& suffix,
     42       std::vector<std::string>* filenames,
     43       std::string* error_msg) {
     44     DIR* d = opendir(dir.c_str());
     45     if (d == nullptr) {
     46       *error_msg = "Failed to open directory";
     47       return false;
     48     }
     49     dirent* e;
     50     struct stat s;
     51     size_t suffix_len = suffix.size();
     52     while ((e = readdir(d)) != nullptr) {
     53       if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) {
     54         continue;
     55       }
     56       size_t name_len = strlen(e->d_name);
     57       if ((name_len < suffix_len) || (strcmp(&e->d_name[name_len - suffix_len], suffix.c_str()))) {
     58         continue;
     59       }
     60       std::string basename(e->d_name);
     61       std::string filename = dir + "/" + basename;
     62       int stat_result = lstat(filename.c_str(), &s);
     63       if (stat_result != 0) {
     64         *error_msg =
     65             StringPrintf("Failed to stat %s: stat returned %d", filename.c_str(), stat_result);
     66         return false;
     67       }
     68       if (S_ISDIR(s.st_mode)) {
     69         continue;
     70       }
     71       filenames->push_back(basename);
     72     }
     73     closedir(d);
     74     return true;
     75   }
     76 
     77   static void AddRuntimeArg(std::vector<std::string>& args, const std::string& arg) {
     78     args.push_back("--runtime-arg");
     79     args.push_back(arg);
     80   }
     81 
     82   bool CompileBootImage(const std::vector<std::string>& extra_args,
     83                         const std::string& image_file_name_prefix,
     84                         uint32_t base_addr,
     85                         std::string* error_msg) {
     86     Runtime* const runtime = Runtime::Current();
     87     std::vector<std::string> argv;
     88     argv.push_back(runtime->GetCompilerExecutable());
     89     AddRuntimeArg(argv, "-Xms64m");
     90     AddRuntimeArg(argv, "-Xmx64m");
     91     std::vector<std::string> dex_files = GetLibCoreDexFileNames();
     92     for (const std::string& dex_file : dex_files) {
     93       argv.push_back("--dex-file=" + dex_file);
     94       argv.push_back("--dex-location=" + dex_file);
     95     }
     96     if (runtime->IsJavaDebuggable()) {
     97       argv.push_back("--debuggable");
     98     }
     99     runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
    100 
    101     AddRuntimeArg(argv, "-Xverify:softfail");
    102 
    103     if (!kIsTargetBuild) {
    104       argv.push_back("--host");
    105     }
    106 
    107     argv.push_back("--image=" + image_file_name_prefix + ".art");
    108     argv.push_back("--oat-file=" + image_file_name_prefix + ".oat");
    109     argv.push_back("--oat-location=" + image_file_name_prefix + ".oat");
    110     argv.push_back(StringPrintf("--base=0x%" PRIx32, base_addr));
    111     argv.push_back("--compile-pic");
    112     argv.push_back("--multi-image");
    113     argv.push_back("--no-generate-debug-info");
    114 
    115     std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
    116     argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
    117 
    118     // We must set --android-root.
    119     const char* android_root = getenv("ANDROID_ROOT");
    120     CHECK(android_root != nullptr);
    121     argv.push_back("--android-root=" + std::string(android_root));
    122     argv.insert(argv.end(), extra_args.begin(), extra_args.end());
    123 
    124     return RunDex2OatOrPatchoat(argv, error_msg);
    125   }
    126 
    127   static std::vector<std::string> BasePatchoatCommand(const std::string& input_image_location,
    128                                                       off_t base_offset_delta) {
    129     Runtime* const runtime = Runtime::Current();
    130     std::vector<std::string> argv;
    131     argv.push_back(runtime->GetPatchoatExecutable());
    132     argv.push_back("--input-image-location=" + input_image_location);
    133     argv.push_back(StringPrintf("--base-offset-delta=0x%jx", (intmax_t) base_offset_delta));
    134     argv.push_back(StringPrintf("--instruction-set=%s", GetInstructionSetString(kRuntimeISA)));
    135 
    136     return argv;
    137   }
    138 
    139   bool RelocateBootImage(const std::string& input_image_location,
    140                          const std::string& output_image_directory,
    141                          off_t base_offset_delta,
    142                          std::string* error_msg) {
    143     std::vector<std::string> argv = BasePatchoatCommand(input_image_location, base_offset_delta);
    144     argv.push_back("--output-image-directory=" + output_image_directory);
    145 
    146     return RunDex2OatOrPatchoat(argv, error_msg);
    147   }
    148 
    149   bool VerifyBootImage(const std::string& input_image_location,
    150                        const std::string& output_image_directory,
    151                        off_t base_offset_delta,
    152                        std::string* error_msg) {
    153     std::vector<std::string> argv = BasePatchoatCommand(input_image_location, base_offset_delta);
    154     argv.push_back("--output-image-directory=" + output_image_directory);
    155     argv.push_back("--verify");
    156 
    157     return RunDex2OatOrPatchoat(argv, error_msg);
    158   }
    159 
    160   bool GenerateBootImageRelFile(const std::string& input_image_location,
    161                                 const std::string& output_rel_directory,
    162                                 off_t base_offset_delta,
    163                                 std::string* error_msg) {
    164     std::vector<std::string> argv = BasePatchoatCommand(input_image_location, base_offset_delta);
    165     argv.push_back("--output-image-relocation-directory=" + output_rel_directory);
    166 
    167     return RunDex2OatOrPatchoat(argv, error_msg);
    168   }
    169 
    170   bool RunDex2OatOrPatchoat(const std::vector<std::string>& args, std::string* error_msg) {
    171     int link[2];
    172 
    173     if (pipe(link) == -1) {
    174       return false;
    175     }
    176 
    177     pid_t pid = fork();
    178     if (pid == -1) {
    179       return false;
    180     }
    181 
    182     if (pid == 0) {
    183       // We need dex2oat to actually log things.
    184       setenv("ANDROID_LOG_TAGS", "*:e", 1);
    185       dup2(link[1], STDERR_FILENO);
    186       close(link[0]);
    187       close(link[1]);
    188       std::vector<const char*> c_args;
    189       for (const std::string& str : args) {
    190         c_args.push_back(str.c_str());
    191       }
    192       c_args.push_back(nullptr);
    193       execv(c_args[0], const_cast<char* const*>(c_args.data()));
    194       exit(1);
    195       UNREACHABLE();
    196     } else {
    197       close(link[1]);
    198       char buffer[128];
    199       memset(buffer, 0, 128);
    200       ssize_t bytes_read = 0;
    201 
    202       while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) {
    203         *error_msg += std::string(buffer, bytes_read);
    204       }
    205       close(link[0]);
    206       int status = -1;
    207       if (waitpid(pid, &status, 0) != -1) {
    208         return (status == 0);
    209       }
    210       return false;
    211     }
    212   }
    213 
    214   bool CompileBootImageToDir(
    215       const std::string& output_dir,
    216       const std::vector<std::string>& dex2oat_extra_args,
    217       uint32_t base_addr,
    218       std::string* error_msg) {
    219     return CompileBootImage(dex2oat_extra_args, output_dir + "/boot", base_addr, error_msg);
    220   }
    221 
    222   bool CopyImageChecksumAndSetPatchDelta(
    223       const std::string& src_image_filename,
    224       const std::string& dest_image_filename,
    225       off_t dest_patch_delta,
    226       std::string* error_msg) {
    227     std::unique_ptr<File> src_file(OS::OpenFileForReading(src_image_filename.c_str()));
    228     if (src_file.get() == nullptr) {
    229       *error_msg = StringPrintf("Failed to open source image file %s", src_image_filename.c_str());
    230       return false;
    231     }
    232     ImageHeader src_header;
    233     if (!src_file->ReadFully(&src_header, sizeof(src_header))) {
    234       *error_msg = StringPrintf("Failed to read source image file %s", src_image_filename.c_str());
    235       return false;
    236     }
    237 
    238     std::unique_ptr<File> dest_file(OS::OpenFileReadWrite(dest_image_filename.c_str()));
    239     if (dest_file.get() == nullptr) {
    240       *error_msg =
    241           StringPrintf("Failed to open destination image file %s", dest_image_filename.c_str());
    242       return false;
    243     }
    244     ImageHeader dest_header;
    245     if (!dest_file->ReadFully(&dest_header, sizeof(dest_header))) {
    246       *error_msg =
    247           StringPrintf("Failed to read destination image file %s", dest_image_filename.c_str());
    248       return false;
    249     }
    250     dest_header.SetOatChecksum(src_header.GetOatChecksum());
    251     dest_header.SetPatchDelta(dest_patch_delta);
    252     if (!dest_file->ResetOffset()) {
    253       *error_msg =
    254           StringPrintf(
    255               "Failed to seek to start of destination image file %s", dest_image_filename.c_str());
    256       return false;
    257     }
    258     if (!dest_file->WriteFully(&dest_header, sizeof(dest_header))) {
    259       *error_msg =
    260           StringPrintf("Failed to write to destination image file %s", dest_image_filename.c_str());
    261       dest_file->Erase();
    262       return false;
    263     }
    264     if (dest_file->FlushCloseOrErase() != 0) {
    265       *error_msg =
    266           StringPrintf(
    267               "Failed to flush/close destination image file %s", dest_image_filename.c_str());
    268       return false;
    269     }
    270 
    271     return true;
    272   }
    273 
    274   bool ReadFully(
    275       const std::string& filename, std::vector<uint8_t>* contents, std::string* error_msg) {
    276     std::unique_ptr<File> file(OS::OpenFileForReading(filename.c_str()));
    277     if (file.get() == nullptr) {
    278       *error_msg = "Failed to open";
    279       return false;
    280     }
    281     int64_t size = file->GetLength();
    282     if (size < 0) {
    283       *error_msg = "Failed to get size";
    284       return false;
    285     }
    286     contents->resize(size);
    287     if (!file->ReadFully(&(*contents)[0], size)) {
    288       *error_msg = "Failed to read";
    289       contents->clear();
    290       return false;
    291     }
    292     return true;
    293   }
    294 
    295   bool BinaryDiff(
    296       const std::string& filename1, const std::string& filename2, std::string* error_msg) {
    297     std::string read_error_msg;
    298     std::vector<uint8_t> image1;
    299     if (!ReadFully(filename1, &image1, &read_error_msg)) {
    300       *error_msg = StringPrintf("Failed to read %s: %s", filename1.c_str(), read_error_msg.c_str());
    301       return true;
    302     }
    303     std::vector<uint8_t> image2;
    304     if (!ReadFully(filename2, &image2, &read_error_msg)) {
    305       *error_msg = StringPrintf("Failed to read %s: %s", filename2.c_str(), read_error_msg.c_str());
    306       return true;
    307     }
    308     if (image1.size() != image1.size()) {
    309       *error_msg =
    310           StringPrintf(
    311               "%s and %s are of different size: %zu vs %zu",
    312               filename1.c_str(),
    313               filename2.c_str(),
    314               image1.size(),
    315               image2.size());
    316       return true;
    317     }
    318     size_t size = image1.size();
    319     for (size_t i = 0; i < size; i++) {
    320       if (image1[i] != image2[i]) {
    321         *error_msg =
    322             StringPrintf("%s and %s differ at offset %zu", filename1.c_str(), filename2.c_str(), i);
    323         return true;
    324       }
    325     }
    326 
    327     return false;
    328   }
    329 };
    330 
    331 TEST_F(PatchoatTest, PatchoatRelocationSameAsDex2oatRelocation) {
    332 #if defined(ART_USE_READ_BARRIER)
    333   // This test checks that relocating a boot image using patchoat produces the same result as
    334   // producing the boot image for that relocated base address using dex2oat. To be precise, these
    335   // two files will have two small differences: the OAT checksum and base address. However, this
    336   // test takes this into account.
    337 
    338   // Compile boot image into a random directory using dex2oat
    339   ScratchFile dex2oat_orig_scratch;
    340   dex2oat_orig_scratch.Unlink();
    341   std::string dex2oat_orig_dir = dex2oat_orig_scratch.GetFilename();
    342   ASSERT_EQ(0, mkdir(dex2oat_orig_dir.c_str(), 0700));
    343   const uint32_t orig_base_addr = 0x60000000;
    344   // Force deterministic output. We want the boot images created by this dex2oat run and the run
    345   // below to differ only in their base address.
    346   std::vector<std::string> dex2oat_extra_args;
    347   dex2oat_extra_args.push_back("--force-determinism");
    348   dex2oat_extra_args.push_back("-j1");  // Might not be needed. Causes a 3-5x slowdown.
    349   std::string error_msg;
    350   if (!CompileBootImageToDir(dex2oat_orig_dir, dex2oat_extra_args, orig_base_addr, &error_msg)) {
    351     FAIL() << "CompileBootImage1 failed: " << error_msg;
    352   }
    353 
    354   // Compile a "relocated" boot image into a random directory using dex2oat. This image is relocated
    355   // in the sense that it uses a different base address.
    356   ScratchFile dex2oat_reloc_scratch;
    357   dex2oat_reloc_scratch.Unlink();
    358   std::string dex2oat_reloc_dir = dex2oat_reloc_scratch.GetFilename();
    359   ASSERT_EQ(0, mkdir(dex2oat_reloc_dir.c_str(), 0700));
    360   const uint32_t reloc_base_addr = 0x70000000;
    361   if (!CompileBootImageToDir(dex2oat_reloc_dir, dex2oat_extra_args, reloc_base_addr, &error_msg)) {
    362     FAIL() << "CompileBootImage2 failed: " << error_msg;
    363   }
    364   const off_t base_addr_delta = reloc_base_addr - orig_base_addr;
    365 
    366   // Relocate the original boot image using patchoat. The image is relocated by the same amount
    367   // as the second/relocated image produced by dex2oat.
    368   ScratchFile patchoat_scratch;
    369   patchoat_scratch.Unlink();
    370   std::string patchoat_dir = patchoat_scratch.GetFilename();
    371   ASSERT_EQ(0, mkdir(patchoat_dir.c_str(), 0700));
    372   std::string dex2oat_orig_with_arch_dir =
    373       dex2oat_orig_dir + "/" + GetInstructionSetString(kRuntimeISA);
    374   // The arch-including symlink is needed by patchoat
    375   ASSERT_EQ(0, symlink(dex2oat_orig_dir.c_str(), dex2oat_orig_with_arch_dir.c_str()));
    376   if (!RelocateBootImage(
    377       dex2oat_orig_dir + "/boot.art",
    378       patchoat_dir,
    379       base_addr_delta,
    380       &error_msg)) {
    381     FAIL() << "RelocateBootImage failed: " << error_msg;
    382   }
    383 
    384   // Assert that patchoat created the same set of .art files as dex2oat
    385   std::vector<std::string> dex2oat_image_basenames;
    386   std::vector<std::string> patchoat_image_basenames;
    387   if (!ListDirFilesEndingWith(dex2oat_reloc_dir, ".art", &dex2oat_image_basenames, &error_msg)) {
    388     FAIL() << "Failed to list *.art files in " << dex2oat_reloc_dir << ": " << error_msg;
    389   }
    390   if (!ListDirFilesEndingWith(patchoat_dir, ".art", &patchoat_image_basenames, &error_msg)) {
    391     FAIL() << "Failed to list *.art files in " << patchoat_dir << ": " << error_msg;
    392   }
    393   std::sort(dex2oat_image_basenames.begin(), dex2oat_image_basenames.end());
    394   std::sort(patchoat_image_basenames.begin(), patchoat_image_basenames.end());
    395   // .art file names output by patchoat look like tmp@art-data-<random>-<random>@boot*.art. To
    396   // compare these with .art file names output by dex2oat we retain only the part of the file name
    397   // after the last @.
    398   std::vector<std::string> patchoat_image_shortened_basenames(patchoat_image_basenames.size());
    399   for (size_t i = 0; i < patchoat_image_basenames.size(); i++) {
    400     patchoat_image_shortened_basenames[i] =
    401         patchoat_image_basenames[i].substr(patchoat_image_basenames[i].find_last_of("@") + 1);
    402   }
    403   ASSERT_EQ(dex2oat_image_basenames, patchoat_image_shortened_basenames);
    404 
    405   // Patch up the dex2oat-relocated image files so that it looks as though they were relocated by
    406   // patchoat. patchoat preserves the OAT checksum header field and sets patch delta header field.
    407   for (const std::string& image_basename : dex2oat_image_basenames) {
    408     if (!CopyImageChecksumAndSetPatchDelta(
    409         dex2oat_orig_dir + "/" + image_basename,
    410         dex2oat_reloc_dir + "/" + image_basename,
    411         base_addr_delta,
    412         &error_msg)) {
    413       FAIL() << "Unable to patch up " << image_basename << ": " << error_msg;
    414     }
    415   }
    416 
    417   // Assert that the patchoat-relocated images are identical to the dex2oat-relocated images
    418   for (size_t i = 0; i < dex2oat_image_basenames.size(); i++) {
    419     const std::string& dex2oat_image_basename = dex2oat_image_basenames[i];
    420     const std::string& dex2oat_image_filename = dex2oat_reloc_dir + "/" + dex2oat_image_basename;
    421     const std::string& patchoat_image_filename = patchoat_dir + "/" + patchoat_image_basenames[i];
    422     if (BinaryDiff(dex2oat_image_filename, patchoat_image_filename, &error_msg)) {
    423       FAIL() << "patchoat- and dex2oat-relocated variants of " << dex2oat_image_basename
    424           << " differ: " << error_msg;
    425     }
    426   }
    427 
    428   ClearDirectory(dex2oat_orig_dir.c_str(), /*recursive*/ true);
    429   ClearDirectory(dex2oat_reloc_dir.c_str(), /*recursive*/ true);
    430   ClearDirectory(patchoat_dir.c_str(), /*recursive*/ true);
    431   rmdir(dex2oat_orig_dir.c_str());
    432   rmdir(dex2oat_reloc_dir.c_str());
    433   rmdir(patchoat_dir.c_str());
    434 #else
    435   LOG(INFO) << "Skipping PatchoatRelocationSameAsDex2oatRelocation";
    436   // Force-print to std::cout so it's also outside the logcat.
    437   std::cout << "Skipping PatchoatRelocationSameAsDex2oatRelocation" << std::endl;
    438 #endif
    439 }
    440 
    441 // These tests check that a boot image relocated using patchoat can be unrelocated
    442 // using the .rel file created by patchoat.
    443 //
    444 // The tests don't work when heap poisoning is enabled because some of the
    445 // references are negated. b/72117833 is tracking the effort to have patchoat
    446 // and its tests support heap poisoning.
    447 class PatchoatVerificationTest : public PatchoatTest {
    448  protected:
    449   void CreateRelocatedBootImage() {
    450     // Compile boot image into a random directory using dex2oat
    451     ScratchFile dex2oat_orig_scratch;
    452     dex2oat_orig_scratch.Unlink();
    453     dex2oat_orig_dir_ = dex2oat_orig_scratch.GetFilename();
    454     ASSERT_EQ(0, mkdir(dex2oat_orig_dir_.c_str(), 0700));
    455     const uint32_t orig_base_addr = 0x60000000;
    456     std::vector<std::string> dex2oat_extra_args;
    457     std::string error_msg;
    458     if (!CompileBootImageToDir(dex2oat_orig_dir_, dex2oat_extra_args, orig_base_addr, &error_msg)) {
    459       FAIL() << "CompileBootImage1 failed: " << error_msg;
    460     }
    461 
    462     // Generate image relocation file for the original boot image
    463     std::string dex2oat_orig_with_arch_dir =
    464         dex2oat_orig_dir_ + "/" + GetInstructionSetString(kRuntimeISA);
    465     // The arch-including symlink is needed by patchoat
    466     ASSERT_EQ(0, symlink(dex2oat_orig_dir_.c_str(), dex2oat_orig_with_arch_dir.c_str()));
    467     base_addr_delta_ = 0x100000;
    468     if (!GenerateBootImageRelFile(
    469         dex2oat_orig_dir_ + "/boot.art",
    470         dex2oat_orig_dir_,
    471         base_addr_delta_,
    472         &error_msg)) {
    473       FAIL() << "RelocateBootImage failed: " << error_msg;
    474     }
    475 
    476     // Relocate the original boot image using patchoat
    477     ScratchFile relocated_scratch;
    478     relocated_scratch.Unlink();
    479     relocated_dir_ = relocated_scratch.GetFilename();
    480     ASSERT_EQ(0, mkdir(relocated_dir_.c_str(), 0700));
    481     // Use a different relocation delta from the one used when generating .rel files above. This is
    482     // to make sure .rel files are not specific to a particular relocation delta.
    483     base_addr_delta_ -= 0x10000;
    484     if (!RelocateBootImage(
    485         dex2oat_orig_dir_ + "/boot.art",
    486         relocated_dir_,
    487         base_addr_delta_,
    488         &error_msg)) {
    489       FAIL() << "RelocateBootImage failed: " << error_msg;
    490     }
    491 
    492     // Assert that patchoat created the same set of .art and .art.rel files
    493     std::vector<std::string> rel_basenames;
    494     std::vector<std::string> relocated_image_basenames;
    495     if (!ListDirFilesEndingWith(dex2oat_orig_dir_, ".rel", &rel_basenames, &error_msg)) {
    496       FAIL() << "Failed to list *.art.rel files in " << dex2oat_orig_dir_ << ": " << error_msg;
    497     }
    498     if (!ListDirFilesEndingWith(relocated_dir_, ".art", &relocated_image_basenames, &error_msg)) {
    499       FAIL() << "Failed to list *.art files in " << relocated_dir_ << ": " << error_msg;
    500     }
    501     std::sort(rel_basenames.begin(), rel_basenames.end());
    502     std::sort(relocated_image_basenames.begin(), relocated_image_basenames.end());
    503 
    504     // .art and .art.rel file names output by patchoat look like
    505     // tmp@art-data-<random>-<random>@boot*.art, encoding the name of the directory in their name.
    506     // To compare these with each other, we retain only the part of the file name after the last @,
    507     // and we also drop the extension.
    508     std::vector<std::string> rel_shortened_basenames(rel_basenames.size());
    509     std::vector<std::string> relocated_image_shortened_basenames(relocated_image_basenames.size());
    510     for (size_t i = 0; i < rel_basenames.size(); i++) {
    511       rel_shortened_basenames[i] = rel_basenames[i].substr(rel_basenames[i].find_last_of("@") + 1);
    512       rel_shortened_basenames[i] =
    513           rel_shortened_basenames[i].substr(0, rel_shortened_basenames[i].find("."));
    514     }
    515     for (size_t i = 0; i < relocated_image_basenames.size(); i++) {
    516       relocated_image_shortened_basenames[i] =
    517           relocated_image_basenames[i].substr(relocated_image_basenames[i].find_last_of("@") + 1);
    518       relocated_image_shortened_basenames[i] =
    519           relocated_image_shortened_basenames[i].substr(
    520               0, relocated_image_shortened_basenames[i].find("."));
    521     }
    522     ASSERT_EQ(rel_shortened_basenames, relocated_image_shortened_basenames);
    523   }
    524 
    525   virtual void TearDown() {
    526     if (!dex2oat_orig_dir_.empty()) {
    527       ClearDirectory(dex2oat_orig_dir_.c_str(), /*recursive*/ true);
    528       rmdir(dex2oat_orig_dir_.c_str());
    529     }
    530     if (!relocated_dir_.empty()) {
    531       ClearDirectory(relocated_dir_.c_str(), /*recursive*/ true);
    532       rmdir(relocated_dir_.c_str());
    533     }
    534     PatchoatTest::TearDown();
    535   }
    536 
    537   std::string dex2oat_orig_dir_;
    538   std::string relocated_dir_;
    539   off_t base_addr_delta_;
    540 };
    541 
    542 // Assert that verification works with the .rel files.
    543 TEST_F(PatchoatVerificationTest, Sucessful) {
    544   TEST_DISABLED_FOR_HEAP_POISONING();
    545   CreateRelocatedBootImage();
    546 
    547   std::string error_msg;
    548   if (!VerifyBootImage(
    549       dex2oat_orig_dir_ + "/boot.art",
    550       relocated_dir_,
    551       base_addr_delta_,
    552       &error_msg)) {
    553     FAIL() << "VerifyBootImage failed: " << error_msg;
    554   }
    555 }
    556 
    557 // Corrupt the image file and check that the verification fails gracefully.
    558 TEST_F(PatchoatVerificationTest, CorruptedImage) {
    559   TEST_DISABLED_FOR_HEAP_POISONING();
    560   CreateRelocatedBootImage();
    561 
    562   std::string error_msg;
    563   std::string relocated_image_filename;
    564   if (!GetDalvikCacheFilename((dex2oat_orig_dir_ + "/boot.art").c_str(),
    565                                relocated_dir_.c_str(),
    566                                &relocated_image_filename,
    567                                &error_msg)) {
    568     FAIL() << "Failed to find relocated image file name: " << error_msg;
    569   }
    570   ASSERT_EQ(truncate(relocated_image_filename.c_str(), sizeof(ImageHeader)), 0)
    571     << relocated_image_filename;
    572 
    573   if (VerifyBootImage(
    574       dex2oat_orig_dir_ + "/boot.art",
    575       relocated_dir_,
    576       base_addr_delta_,
    577       &error_msg)) {
    578     FAIL() << "VerifyBootImage should have failed since the image was intentionally corrupted";
    579   }
    580 }
    581 
    582 // Corrupt the relocation file and check that the verification fails gracefully.
    583 TEST_F(PatchoatVerificationTest, CorruptedRelFile) {
    584   TEST_DISABLED_FOR_HEAP_POISONING();
    585   CreateRelocatedBootImage();
    586 
    587   std::string error_msg;
    588   std::string art_filename = dex2oat_orig_dir_ + "/boot.art";
    589   std::string rel_filename = dex2oat_orig_dir_ + "/boot.art.rel";
    590   std::unique_ptr<File> art_file(OS::OpenFileForReading(art_filename.c_str()));
    591   std::unique_ptr<File> rel_file(OS::OpenFileReadWrite(rel_filename.c_str()));
    592   rel_file->ClearContent();
    593   uint8_t buffer[64] = {};
    594   ASSERT_TRUE(rel_file->WriteFully(&buffer, SHA256_DIGEST_LENGTH));
    595   // Encode single relocation which is just past the end of the image file.
    596   size_t leb_size = EncodeUnsignedLeb128(buffer, art_file->GetLength()) - buffer;
    597   ASSERT_TRUE(rel_file->WriteFully(&buffer, leb_size));
    598   ASSERT_EQ(rel_file->FlushClose(), 0);
    599   ASSERT_EQ(art_file->Close(), 0);
    600 
    601   if (VerifyBootImage(
    602       dex2oat_orig_dir_ + "/boot.art",
    603       relocated_dir_,
    604       base_addr_delta_,
    605       &error_msg)) {
    606     FAIL() << "VerifyBootImage should have failed since the rel file was intentionally corrupted";
    607   }
    608 }
    609 
    610 }  // namespace art
    611