diff options
author | Samuel Huang <huangs@chromium.org> | 2018-03-13 18:19:34 +0000 |
---|---|---|
committer | Edward Lesmes <ehmaldonado@google.com> | 2021-07-23 21:50:59 +0000 |
commit | 06f1ae9aaca969ee95ef840f22b6b461c304542d (patch) | |
tree | f1e5c6624e70628e81fbf38d6cd14b974abe5d93 /abs32_utils_unittest.cc | |
download | zucchini-06f1ae9aaca969ee95ef840f22b6b461c304542d.tar.gz |
[Zucchini] Move Zucchini from /chrome/installer/ to /components/.
(Use "git log --follow" to see older revisions of files).
/components/ is the most logical place to put Zucchini, which only
depends on /base and /testing/gtest. This move also enables Zucchini to
be used by the Component Updater. Details:
- Move all files; run the following to change deps and guards:
sed 's/chrome\/installer/components/' *.cc *.h -i
sed 's/CHROME_INSTALLER/COMPONENTS/' *.cc *.h -i
- Sorting works out pretty well!
- Change all 'chrome/installer/zucchini' to 'components/zucchini'
throughout other parts of the repo; sort if necessary.
- Fix 6 'git cl lint' errors.
- Change 1 Bind() usage to BindRepeated().
- Update OWNER.
Bug: 729154
Change-Id: I50c5a7d411ea85f707b5994ab319dfb2a1acccf7
Reviewed-on: https://chromium-review.googlesource.com/954923
Reviewed-by: Greg Thompson <grt@chromium.org>
Reviewed-by: Jochen Eisinger <jochen@chromium.org>
Reviewed-by: Samuel Huang <huangs@chromium.org>
Commit-Queue: Samuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542857}
NOKEYCHECK=True
GitOrigin-RevId: 577ef6c435e8d43be6e3e60ccbcbd1881780f4ec
Diffstat (limited to 'abs32_utils_unittest.cc')
-rw-r--r-- | abs32_utils_unittest.cc | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/abs32_utils_unittest.cc b/abs32_utils_unittest.cc new file mode 100644 index 0000000..480fea0 --- /dev/null +++ b/abs32_utils_unittest.cc @@ -0,0 +1,496 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/zucchini/abs32_utils.h" + +#include <stdint.h> + +#include <algorithm> +#include <string> +#include <utility> + +#include "base/numerics/safe_conversions.h" +#include "components/zucchini/image_utils.h" +#include "components/zucchini/test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace zucchini { + +namespace { + +// A trivial AddressTranslator that applies constant shift. +class TestAddressTranslator : public AddressTranslator { + public: + TestAddressTranslator(size_t image_size, rva_t rva_begin) { + DCHECK_GE(rva_begin, 0U); + CHECK_EQ(AddressTranslator::kSuccess, + Initialize({{0, base::checked_cast<offset_t>(image_size), + rva_begin, base::checked_cast<rva_t>(image_size)}})); + } +}; + +// Helper to translate address |value| to RVA. May return |kInvalidRva|. +rva_t AddrValueToRva(uint64_t value, AbsoluteAddress* addr) { + *addr->mutable_value() = value; + return addr->ToRva(); +} + +} // namespace + +TEST(Abs32UtilsTest, AbsoluteAddress32) { + std::vector<uint8_t> data32 = ParseHexString( + "00 00 32 00 21 43 65 4A 00 00 00 00 FF FF FF FF FF FF 31 00"); + ConstBufferView image32(data32.data(), data32.size()); + MutableBufferView mutable_image32(data32.data(), data32.size()); + + AbsoluteAddress addr32(kBit32, 0x00320000U); + EXPECT_TRUE(addr32.Read(0x0U, image32)); + EXPECT_EQ(0x00000000U, addr32.ToRva()); + EXPECT_TRUE(addr32.Read(0x4U, image32)); + EXPECT_EQ(0x4A334321U, addr32.ToRva()); + EXPECT_TRUE(addr32.Read(0x8U, image32)); + EXPECT_EQ(kInvalidRva, addr32.ToRva()); // Underflow. + EXPECT_TRUE(addr32.Read(0xCU, image32)); + EXPECT_EQ(kInvalidRva, addr32.ToRva()); // Translated RVA would be to large. + EXPECT_TRUE(addr32.Read(0x10U, image32)); + EXPECT_EQ(kInvalidRva, addr32.ToRva()); // Underflow (boundary case). + + EXPECT_FALSE(addr32.Read(0x11U, image32)); + EXPECT_FALSE(addr32.Read(0x14U, image32)); + EXPECT_FALSE(addr32.Read(0x100000U, image32)); + EXPECT_FALSE(addr32.Read(0x80000000U, image32)); + EXPECT_FALSE(addr32.Read(0xFFFFFFFFU, image32)); + + EXPECT_TRUE(addr32.FromRva(0x11223344U)); + EXPECT_TRUE(addr32.Write(0x2U, &mutable_image32)); + EXPECT_TRUE(addr32.Write(0x10U, &mutable_image32)); + std::vector<uint8_t> expected_data32 = ParseHexString( + "00 00 44 33 54 11 65 4A 00 00 00 00 FF FF FF FF 44 33 54 11"); + EXPECT_EQ(expected_data32, data32); + EXPECT_FALSE(addr32.Write(0x11U, &mutable_image32)); + EXPECT_FALSE(addr32.Write(0xFFFFFFFFU, &mutable_image32)); + EXPECT_EQ(expected_data32, data32); +} + +TEST(Abs32UtilsTest, AbsoluteAddress32Overflow) { + AbsoluteAddress addr32(kBit32, 0xC0000000U); + EXPECT_TRUE(addr32.FromRva(0x00000000U)); + EXPECT_TRUE(addr32.FromRva(0x11223344U)); + EXPECT_TRUE(addr32.FromRva(0x3FFFFFFFU)); + EXPECT_FALSE(addr32.FromRva(0x40000000U)); + EXPECT_FALSE(addr32.FromRva(0x40000001U)); + EXPECT_FALSE(addr32.FromRva(0x80000000U)); + EXPECT_FALSE(addr32.FromRva(0xFFFFFFFFU)); + + EXPECT_EQ(0x00000000U, AddrValueToRva(0xC0000000U, &addr32)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0xBFFFFFFFU, &addr32)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0x00000000U, &addr32)); + EXPECT_EQ(0x3FFFFFFFU, AddrValueToRva(0xFFFFFFFFU, &addr32)); +} + +TEST(Abs32UtilsTest, AbsoluteAddress64) { + std::vector<uint8_t> data64 = ParseHexString( + "00 00 00 00 64 00 00 00 21 43 65 4A 64 00 00 00 " + "00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF " + "00 00 00 00 64 00 00 80 FF FF FF FF 63 00 00 00"); + ConstBufferView image64(data64.data(), data64.size()); + MutableBufferView mutable_image64(data64.data(), data64.size()); + + AbsoluteAddress addr64(kBit64, 0x0000006400000000ULL); + EXPECT_TRUE(addr64.Read(0x0U, image64)); + EXPECT_EQ(0x00000000U, addr64.ToRva()); + EXPECT_TRUE(addr64.Read(0x8U, image64)); + EXPECT_EQ(0x4A654321U, addr64.ToRva()); + EXPECT_TRUE(addr64.Read(0x10U, image64)); // Succeeds, in spite of value. + EXPECT_EQ(kInvalidRva, addr64.ToRva()); // Underflow. + EXPECT_TRUE(addr64.Read(0x18U, image64)); + EXPECT_EQ(kInvalidRva, addr64.ToRva()); // Translated RVA too large. + EXPECT_TRUE(addr64.Read(0x20U, image64)); + EXPECT_EQ(kInvalidRva, addr64.ToRva()); // Translated RVA toolarge. + EXPECT_TRUE(addr64.Read(0x28U, image64)); + EXPECT_EQ(kInvalidRva, addr64.ToRva()); // Underflow. + + EXPECT_FALSE(addr64.Read(0x29U, image64)); // Extends outside. + EXPECT_FALSE(addr64.Read(0x30U, image64)); // Entirely outside (note: hex). + EXPECT_FALSE(addr64.Read(0x100000U, image64)); + EXPECT_FALSE(addr64.Read(0x80000000U, image64)); + EXPECT_FALSE(addr64.Read(0xFFFFFFFFU, image64)); + + EXPECT_TRUE(addr64.FromRva(0x11223344U)); + EXPECT_TRUE(addr64.Write(0x13U, &mutable_image64)); + EXPECT_TRUE(addr64.Write(0x20U, &mutable_image64)); + std::vector<uint8_t> expected_data64 = ParseHexString( + "00 00 00 00 64 00 00 00 21 43 65 4A 64 00 00 00 " + "00 00 00 44 33 22 11 64 00 00 00 FF FF FF FF FF " + "44 33 22 11 64 00 00 00 FF FF FF FF 63 00 00 00"); + EXPECT_EQ(expected_data64, data64); + EXPECT_FALSE(addr64.Write(0x29U, &mutable_image64)); + EXPECT_FALSE(addr64.Write(0x30U, &mutable_image64)); + EXPECT_FALSE(addr64.Write(0xFFFFFFFFU, &mutable_image64)); + EXPECT_EQ(expected_data64, data64); + + EXPECT_FALSE(addr64.FromRva(0xFFFFFFFFU)); +} + +TEST(Abs32UtilsTest, AbsoluteAddress64Overflow) { + { + // Counterpart to AbsoluteAddress632verflow test. + AbsoluteAddress addr64(kBit64, 0xFFFFFFFFC0000000ULL); + EXPECT_TRUE(addr64.FromRva(0x00000000U)); + EXPECT_TRUE(addr64.FromRva(0x11223344U)); + EXPECT_TRUE(addr64.FromRva(0x3FFFFFFFU)); + EXPECT_FALSE(addr64.FromRva(0x40000000U)); + EXPECT_FALSE(addr64.FromRva(0x40000001U)); + EXPECT_FALSE(addr64.FromRva(0x80000000U)); + EXPECT_FALSE(addr64.FromRva(0xFFFFFFFFU)); + + EXPECT_EQ(0x00000000U, AddrValueToRva(0xFFFFFFFFC0000000U, &addr64)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0xFFFFFFFFBFFFFFFFU, &addr64)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0x0000000000000000U, &addr64)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0xFFFFFFFF00000000U, &addr64)); + EXPECT_EQ(0x3FFFFFFFU, AddrValueToRva(0xFFFFFFFFFFFFFFFFU, &addr64)); + } + { + // Pseudo-counterpart to AbsoluteAddress632verflow test: Some now pass. + AbsoluteAddress addr64(kBit64, 0xC0000000U); + EXPECT_TRUE(addr64.FromRva(0x00000000U)); + EXPECT_TRUE(addr64.FromRva(0x11223344U)); + EXPECT_TRUE(addr64.FromRva(0x3FFFFFFFU)); + EXPECT_TRUE(addr64.FromRva(0x40000000U)); + EXPECT_TRUE(addr64.FromRva(0x40000001U)); + EXPECT_FALSE(addr64.FromRva(0x80000000U)); + EXPECT_FALSE(addr64.FromRva(0xFFFFFFFFU)); + + // ToRva() still fail though. + EXPECT_EQ(0x00000000U, AddrValueToRva(0xC0000000U, &addr64)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0xBFFFFFFFU, &addr64)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0x00000000U, &addr64)); + EXPECT_EQ(0x3FFFFFFFU, AddrValueToRva(0xFFFFFFFFU, &addr64)); + } + { + AbsoluteAddress addr64(kBit64, 0xC000000000000000ULL); + EXPECT_TRUE(addr64.FromRva(0x00000000ULL)); + EXPECT_TRUE(addr64.FromRva(0x11223344ULL)); + EXPECT_TRUE(addr64.FromRva(0x3FFFFFFFULL)); + EXPECT_TRUE(addr64.FromRva(0x40000000ULL)); + EXPECT_TRUE(addr64.FromRva(0x40000001ULL)); + EXPECT_FALSE(addr64.FromRva(0x80000000ULL)); + EXPECT_FALSE(addr64.FromRva(0xFFFFFFFFULL)); + + EXPECT_EQ(0x00000000U, AddrValueToRva(0xC000000000000000ULL, &addr64)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0xBFFFFFFFFFFFFFFFULL, &addr64)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0x0000000000000000ULL, &addr64)); + EXPECT_EQ(0x3FFFFFFFU, AddrValueToRva(0xC00000003FFFFFFFULL, &addr64)); + EXPECT_EQ(kInvalidRva, AddrValueToRva(0xFFFFFFFFFFFFFFFFULL, &addr64)); + } +} + +TEST(Abs32UtilsTest, Win32Read32) { + constexpr uint32_t kImageBase = 0xA0000000U; + constexpr uint32_t kRvaBegin = 0x00C00000U; + struct { + std::vector<uint8_t> data32; + std::vector<offset_t> abs32_locations; // Assumtion: Sorted. + offset_t lo; // Assumption: In range, does not straddle |abs32_location|. + offset_t hi; // Assumption: Also >= |lo|. + std::vector<Reference> expected_refs; + } test_cases[] = { + // Targets at beginning and end. + {ParseHexString("FF FF FF FF 0F 00 C0 A0 00 00 C0 A0 FF FF FF FF"), + {0x4U, 0x8U}, + 0x0U, + 0x10U, + {{0x4U, 0xFU}, {0x8U, 0x0U}}}, + // Targets at beginning and end are out of bound: Rejected. + {ParseHexString("FF FF FF FF 10 00 C0 A0 FF FF BF A0 FF FF FF FF"), + {0x4U, 0x8U}, + 0x0U, + 0x10U, + std::vector<Reference>()}, + // Same with more extreme target values: Rejected. + {ParseHexString("FF FF FF FF FF FF FF FF 00 00 00 00 FF FF FF FF"), + {0x4U, 0x8U}, + 0x0U, + 0x10U, + std::vector<Reference>()}, + // Locations at beginning and end, plus invalid locations. + {ParseHexString("08 00 C0 A0 FF FF FF FF FF FF FF FF 04 00 C0 A0"), + {0x0U, 0xCU, 0x10U, 0x1000U, 0x80000000U, 0xFFFFFFFFU}, + 0x0U, + 0x10U, + {{0x0U, 0x8U}, {0xCU, 0x4U}}}, + // Odd size, location, target. + {ParseHexString("FF FF FF 09 00 C0 A0 FF FF FF FF FF FF FF FF FF " + "FF FF FF"), + {0x3U}, + 0x0U, + 0x13U, + {{0x3U, 0x9U}}}, + // No location given. + {ParseHexString("FF FF FF FF 0C 00 C0 A0 00 00 C0 A0 FF FF FF FF"), + std::vector<offset_t>(), 0x0U, 0x10U, std::vector<Reference>()}, + // Simple alternation. + {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " + "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), + {0x0U, 0x8U, 0x10U, 0x18U}, + 0x0U, + 0x20U, + {{0x0U, 0x4U}, {0x8U, 0xCU}, {0x10U, 0x14U}, {0x18U, 0x1CU}}}, + // Same, with locations limited by |lo| and |hi|. By assumption these must + // not cut accross Reference body. + {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " + "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), + {0x0U, 0x8U, 0x10U, 0x18U}, + 0x04U, + 0x17U, + {{0x8U, 0xCU}, {0x10U, 0x14U}}}, + // Same, with very limiting |lo| and |hi|. + {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " + "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), + {0x0U, 0x8U, 0x10U, 0x18U}, + 0x0CU, + 0x10U, + std::vector<Reference>()}, + // Same, |lo| == |hi|. + {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " + "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), + {0x0U, 0x8U, 0x10U, 0x18U}, + 0x14U, + 0x14U, + std::vector<Reference>()}, + // Same, |lo| and |hi| at end. + {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " + "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), + {0x0U, 0x8U, 0x10U, 0x18U}, + 0x20U, + 0x20U, + std::vector<Reference>()}, + // Mix. Note that targets can overlap. + {ParseHexString("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF " + "06 00 C0 A0 2C 00 C0 A0 FF FF C0 A0 2B 00 C0 A0 " + "FF 06 00 C0 A0 00 00 C0 A0 FF FF FF FF FF FF FF"), + {0x10U, 0x14U, 0x18U, 0x1CU, 0x21U, 0x25U, 0xAAAAU}, + 0x07U, + 0x25U, + {{0x10U, 0x6U}, {0x14U, 0x2CU}, {0x1CU, 0x2BU}, {0x21, 0x6U}}}, + }; + + for (const auto& test_case : test_cases) { + ConstBufferView image32(test_case.data32.data(), test_case.data32.size()); + Abs32RvaExtractorWin32 extractor(image32, {kBit32, kImageBase}, + test_case.abs32_locations, test_case.lo, + test_case.hi); + + TestAddressTranslator translator(test_case.data32.size(), kRvaBegin); + Abs32ReaderWin32 reader(std::move(extractor), translator); + + // Loop over |expected_ref| to check element-by-element. + base::Optional<Reference> ref; + for (const auto& expected_ref : test_case.expected_refs) { + ref = reader.GetNext(); + EXPECT_TRUE(ref.has_value()); + EXPECT_EQ(expected_ref, ref.value()); + } + // Check that nothing is left. + ref = reader.GetNext(); + EXPECT_FALSE(ref.has_value()); + } +} + +TEST(Abs32UtilsTest, Win32Read64) { + constexpr uint64_t kImageBase = 0x31415926A0000000U; + constexpr uint32_t kRvaBegin = 0x00C00000U; + // For simplicity, just test mixed case. + std::vector<uint8_t> data64 = ParseHexString( + "FF FF FF FF FF FF FF FF 00 00 C0 A0 26 59 41 31 " + "06 00 C0 A0 26 59 41 31 02 00 C0 A0 26 59 41 31 " + "FF FF FF BF 26 59 41 31 FF FF FF FF FF FF FF FF " + "02 00 C0 A0 26 59 41 31 07 00 C0 A0 26 59 41 31"); + std::vector<offset_t> abs32_locations = {0x8U, 0x10U, 0x18U, 0x20U, + 0x28U, 0x30U, 0x38U, 0x40U}; + offset_t lo = 0x10U; + offset_t hi = 0x38U; + std::vector<Reference> expected_refs = { + {0x10U, 0x06U}, {0x18U, 0x02U}, {0x30U, 0x02U}}; + + ConstBufferView image64(data64.data(), data64.size()); + Abs32RvaExtractorWin32 extractor(image64, {kBit64, kImageBase}, + abs32_locations, lo, hi); + TestAddressTranslator translator(data64.size(), kRvaBegin); + Abs32ReaderWin32 reader(std::move(extractor), translator); + + std::vector<Reference> refs; + base::Optional<Reference> ref; + for (ref = reader.GetNext(); ref.has_value(); ref = reader.GetNext()) + refs.push_back(ref.value()); + EXPECT_EQ(expected_refs, refs); +} + +TEST(Abs32UtilsTest, Win32ReadFail) { + // Make |bitness| a state to reduce repetition. + Bitness bitness = kBit32; + + constexpr uint32_t kImageBase = 0xA0000000U; // Shared for 32-bit and 64-bit. + std::vector<uint8_t> data(32U, 0xFFU); + ConstBufferView image(data.data(), data.size()); + + auto try_make = [&](std::vector<offset_t>&& abs32_locations, offset_t lo, + offset_t hi) { + Abs32RvaExtractorWin32 extractor(image, {bitness, kImageBase}, + abs32_locations, lo, hi); + extractor.GetNext(); // Dummy call so |extractor| gets used. + }; + + // 32-bit tests. + bitness = kBit32; + try_make({8U, 24U}, 0U, 32U); + EXPECT_DEATH(try_make({4U, 24U}, 32U, 0U), ""); // |lo| > |hi|. + try_make({8U, 24U}, 0U, 12U); + try_make({8U, 24U}, 0U, 28U); + try_make({8U, 24U}, 8U, 32U); + try_make({8U, 24U}, 24U, 32U); + EXPECT_DEATH(try_make({8U, 24U}, 0U, 11U), ""); // |hi| straddles. + EXPECT_DEATH(try_make({8U, 24U}, 26U, 32U), ""); // |lo| straddles. + try_make({8U, 24U}, 12U, 24U); + + // 64-bit tests. + bitness = kBit64; + try_make({6U, 22U}, 0U, 32U); + // |lo| > |hi|. + EXPECT_DEATH(try_make(std::vector<offset_t>(), 32U, 31U), ""); + try_make({6U, 22U}, 0U, 14U); + try_make({6U, 22U}, 0U, 30U); + try_make({6U, 22U}, 6U, 32U); + try_make({6U, 22U}, 22U, 32U); + EXPECT_DEATH(try_make({6U, 22U}, 0U, 29U), ""); // |hi| straddles. + EXPECT_DEATH(try_make({6U, 22U}, 7U, 32U), ""); // |lo| straddles. + try_make({6U, 22U}, 14U, 20U); + try_make({16U}, 16U, 24U); + EXPECT_DEATH(try_make({16U}, 18U, 18U), ""); // |lo|, |hi| straddle. +} + +TEST(Abs32UtilsTest, Win32Write32) { + constexpr uint32_t kImageBase = 0xA0000000U; + constexpr uint32_t kRvaBegin = 0x00C00000U; + std::vector<uint8_t> data32(0x30, 0xFFU); + MutableBufferView image32(data32.data(), data32.size()); + AbsoluteAddress addr(kBit32, kImageBase); + TestAddressTranslator translator(data32.size(), kRvaBegin); + Abs32WriterWin32 writer(image32, std::move(addr), translator); + + // Successful writes. + writer.PutNext({0x02U, 0x10U}); + writer.PutNext({0x0BU, 0x21U}); + writer.PutNext({0x16U, 0x10U}); + writer.PutNext({0x2CU, 0x00U}); + + // Invalid data: For simplicity, Abs32WriterWin32 simply ignores bad writes. + // Invalid location. + writer.PutNext({0x2DU, 0x20U}); + writer.PutNext({0x80000000U, 0x20U}); + writer.PutNext({0xFFFFFFFFU, 0x20U}); + // Invalid target. + writer.PutNext({0x1CU, 0x00001111U}); + writer.PutNext({0x10U, 0xFFFFFF00U}); + + std::vector<uint8_t> expected_data32 = ParseHexString( + "FF FF 10 00 C0 A0 FF FF FF FF FF 21 00 C0 A0 FF " + "FF FF FF FF FF FF 10 00 C0 A0 FF FF FF FF FF FF " + "FF FF FF FF FF FF FF FF FF FF FF FF 00 00 C0 A0"); + EXPECT_EQ(expected_data32, data32); +} + +TEST(Abs32UtilsTest, Win32Write64) { + constexpr uint64_t kImageBase = 0x31415926A0000000U; + constexpr uint32_t kRvaBegin = 0x00C00000U; + std::vector<uint8_t> data64(0x30, 0xFFU); + MutableBufferView image32(data64.data(), data64.size()); + AbsoluteAddress addr(kBit64, kImageBase); + TestAddressTranslator translator(data64.size(), kRvaBegin); + Abs32WriterWin32 writer(image32, std::move(addr), translator); + + // Successful writes. + writer.PutNext({0x02U, 0x10U}); + writer.PutNext({0x0BU, 0x21U}); + writer.PutNext({0x16U, 0x10U}); + writer.PutNext({0x28U, 0x00U}); + + // Invalid data: For simplicity, Abs32WriterWin32 simply ignores bad writes. + // Invalid location. + writer.PutNext({0x29U, 0x20U}); + writer.PutNext({0x80000000U, 0x20U}); + writer.PutNext({0xFFFFFFFFU, 0x20U}); + // Invalid target. + writer.PutNext({0x1CU, 0x00001111U}); + writer.PutNext({0x10U, 0xFFFFFF00U}); + + std::vector<uint8_t> expected_data64 = ParseHexString( + "FF FF 10 00 C0 A0 26 59 41 31 FF 21 00 C0 A0 26 " + "59 41 31 FF FF FF 10 00 C0 A0 26 59 41 31 FF FF " + "FF FF FF FF FF FF FF FF 00 00 C0 A0 26 59 41 31"); + EXPECT_EQ(expected_data64, data64); +} + +TEST(Abs32UtilsTest, RemoveOverlappingAbs32Locations) { + // Make |bitness| a state to reduce repetition. + Bitness bitness = kBit32; + + auto run_test = [&bitness](const std::vector<offset_t>& expected_locations, + std::vector<offset_t>&& locations) { + ASSERT_TRUE(std::is_sorted(locations.begin(), locations.end())); + size_t expected_removals = locations.size() - expected_locations.size(); + size_t removals = RemoveOverlappingAbs32Locations(bitness, &locations); + EXPECT_EQ(expected_removals, removals); + EXPECT_EQ(expected_locations, locations); + }; + + // 32-bit tests. + bitness = kBit32; + run_test(std::vector<offset_t>(), std::vector<offset_t>()); + run_test({4U}, {4U}); + run_test({4U, 10U}, {4U, 10U}); + run_test({4U, 8U}, {4U, 8U}); + run_test({4U}, {4U, 7U}); + run_test({4U}, {4U, 4U}); + run_test({4U, 8U}, {4U, 7U, 8U}); + run_test({4U, 10U}, {4U, 7U, 10U}); + run_test({4U, 9U}, {4U, 9U, 10U}); + run_test({3U}, {3U, 5U, 6U}); + run_test({3U, 7U}, {3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U}); + run_test({3U, 7U, 11U}, {3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 11U, 12U}); + run_test({4U, 8U, 12U}, {4U, 6U, 8U, 10U, 12U}); + run_test({4U, 8U, 12U, 16U}, {4U, 8U, 12U, 16U}); + run_test({4U, 8U, 12U}, {4U, 8U, 9U, 12U}); + run_test({4U}, {4U, 4U, 4U, 4U, 4U, 4U}); + run_test({3U}, {3U, 4U, 4U, 4U, 5U, 5U}); + run_test({3U, 7U}, {3U, 4U, 4U, 4U, 7U, 7U, 8U}); + run_test({10U, 20U, 30U, 40U}, {10U, 20U, 22U, 22U, 30U, 40U}); + run_test({1000000U, 1000004U}, {1000000U, 1000004U}); + run_test({1000000U}, {1000000U, 1000002U}); + + // 64-bit tests. + bitness = kBit64; + run_test(std::vector<offset_t>(), std::vector<offset_t>()); + run_test({4U}, {4U}); + run_test({4U, 20U}, {4U, 20U}); + run_test({4U, 12U}, {4U, 12U}); + run_test({4U}, {4U, 11U}); + run_test({4U}, {4U, 5U}); + run_test({4U}, {4U, 4U}); + run_test({4U, 12U, 20U}, {4U, 12U, 20U}); + run_test({1U, 9U, 17U}, {1U, 9U, 17U}); + run_test({1U, 17U}, {1U, 8U, 17U}); + run_test({1U, 10U}, {1U, 10U, 17U}); + run_test({3U, 11U}, {3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 11U, 12U}); + run_test({4U, 12U}, {4U, 6U, 8U, 10U, 12U}); + run_test({4U, 12U}, {4U, 12U, 16U}); + run_test({4U, 12U, 20U, 28U}, {4U, 12U, 20U, 28U}); + run_test({4U}, {4U, 4U, 4U, 4U, 5U, 5U}); + run_test({3U, 11U}, {3U, 4U, 4U, 4U, 11U, 11U, 12U}); + run_test({10U, 20U, 30U, 40U}, {10U, 20U, 22U, 22U, 30U, 40U}); + run_test({1000000U, 1000008U}, {1000000U, 1000008U}); + run_test({1000000U}, {1000000U, 1000004U}); +} + +} // namespace zucchini |