/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "compact_dex_file.h" #include "dex_file_loader.h" #include "gtest/gtest.h" namespace art { TEST(CompactDexFileTest, MagicAndVersion) { // Test permutations of valid/invalid headers. for (size_t i = 0; i < 2; ++i) { for (size_t j = 0; j < 2; ++j) { static const size_t len = CompactDexFile::kDexVersionLen + CompactDexFile::kDexMagicSize; uint8_t header[len] = {}; std::fill_n(header, len, 0x99); const bool valid_magic = (i & 1) == 0; const bool valid_version = (j & 1) == 0; if (valid_magic) { CompactDexFile::WriteMagic(header); } if (valid_version) { CompactDexFile::WriteCurrentVersion(header); } EXPECT_EQ(valid_magic, CompactDexFile::IsMagicValid(header)); EXPECT_EQ(valid_version, CompactDexFile::IsVersionValid(header)); EXPECT_EQ(valid_magic, DexFileLoader::IsMagicValid(header)); EXPECT_EQ(valid_magic && valid_version, DexFileLoader::IsVersionAndMagicValid(header)); } } } TEST(CompactDexFileTest, CodeItemFields) { auto test_and_write = [&] (uint16_t registers_size, uint16_t ins_size, uint16_t outs_size, uint16_t tries_size, uint32_t insns_size_in_code_units) { ASSERT_GE(registers_size, ins_size); uint16_t buffer[sizeof(CompactDexFile::CodeItem) + CompactDexFile::CodeItem::kMaxPreHeaderSize] = {}; CompactDexFile::CodeItem* code_item = reinterpret_cast<CompactDexFile::CodeItem*>( &buffer[CompactDexFile::CodeItem::kMaxPreHeaderSize]); const uint16_t* preheader_ptr = code_item->Create(registers_size, ins_size, outs_size, tries_size, insns_size_in_code_units, code_item->GetPreHeader()); ASSERT_GT(preheader_ptr, buffer); uint16_t out_registers_size; uint16_t out_ins_size; uint16_t out_outs_size; uint16_t out_tries_size; uint32_t out_insns_size_in_code_units; code_item->DecodeFields</*kDecodeOnlyInstructionCount=*/false>(&out_insns_size_in_code_units, &out_registers_size, &out_ins_size, &out_outs_size, &out_tries_size); ASSERT_EQ(registers_size, out_registers_size); ASSERT_EQ(ins_size, out_ins_size); ASSERT_EQ(outs_size, out_outs_size); ASSERT_EQ(tries_size, out_tries_size); ASSERT_EQ(insns_size_in_code_units, out_insns_size_in_code_units); ++out_insns_size_in_code_units; // Force value to change. code_item->DecodeFields</*kDecodeOnlyInstructionCount=*/true>(&out_insns_size_in_code_units, /*registers_size=*/ nullptr, /*ins_size=*/ nullptr, /*outs_size=*/ nullptr, /*tries_size=*/ nullptr); ASSERT_EQ(insns_size_in_code_units, out_insns_size_in_code_units); }; static constexpr uint32_t kMax32 = std::numeric_limits<uint32_t>::max(); static constexpr uint16_t kMax16 = std::numeric_limits<uint16_t>::max(); test_and_write(0, 0, 0, 0, 0); test_and_write(kMax16, kMax16, kMax16, kMax16, kMax32); test_and_write(kMax16 - 1, kMax16 - 2, kMax16 - 3, kMax16 - 4, kMax32 - 5); test_and_write(kMax16 - 4, kMax16 - 5, kMax16 - 3, kMax16 - 2, kMax32 - 1); test_and_write(5, 4, 3, 2, 1); test_and_write(5, 0, 3, 2, 1); test_and_write(kMax16, 0, kMax16 / 2, 1234, kMax32 / 4); } } // namespace art