| // Copyright 2019 The Fuchsia 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 <lib/fuzzing/cpp/traits.h> |
| #include <lib/zx/handle.h> |
| #include <zircon/types.h> |
| |
| #include <array> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <gtest/gtest.h> |
| |
| namespace fuzzing { |
| namespace { |
| |
| constexpr size_t size0 = 0; |
| constexpr size_t size1 = 1; |
| constexpr size_t size2 = 2; |
| constexpr size_t size8 = 8; |
| |
| template <typename T1> |
| std::pair<T1, size_t> DoSizedAlloc(size_t size) { |
| std::vector<uint8_t> data(size, 0); |
| ::fuzzing::FuzzInput src(data.data(), size); |
| T1 ret = Allocate<T1>{}(&src, &size); |
| return std::pair<T1, size_t>(std::move(ret), size); |
| } |
| |
| template <typename T1, typename T2 = T1> |
| std::pair<T1, size_t> DoAlloc() { |
| return DoSizedAlloc<T1>(sizeof(T2)); |
| } |
| |
| TEST(TraitsTest, StaticMinSizesMatch) { |
| EXPECT_EQ(MinSize<bool>(), sizeof(bool)); |
| EXPECT_EQ(MinSize<uint8_t>(), sizeof(uint8_t)); |
| EXPECT_EQ(MinSize<uint16_t>(), sizeof(uint16_t)); |
| EXPECT_EQ(MinSize<uint32_t>(), sizeof(uint32_t)); |
| EXPECT_EQ(MinSize<uint64_t>(), sizeof(uint64_t)); |
| EXPECT_EQ(MinSize<int8_t>(), sizeof(int8_t)); |
| EXPECT_EQ(MinSize<int16_t>(), sizeof(int16_t)); |
| EXPECT_EQ(MinSize<int32_t>(), sizeof(int32_t)); |
| EXPECT_EQ(MinSize<int64_t>(), sizeof(int64_t)); |
| EXPECT_EQ(MinSize<float>(), sizeof(float)); |
| EXPECT_EQ(MinSize<double>(), sizeof(double)); |
| EXPECT_EQ(MinSize<::zx::handle>(), sizeof(zx_handle_t)); |
| // TODO(markdittmer): Test handles to objects; e.g., ::zx::channel. |
| } |
| |
| TEST(TraitsTest, EmptyMinSizesMatch) { |
| EXPECT_EQ(MinSize<std::string>(), size0); |
| EXPECT_EQ((MinSize<std::array<bool, 2>>()), size0); |
| EXPECT_EQ(MinSize<std::vector<bool>>(), size0); |
| EXPECT_EQ(MinSize<std::unique_ptr<bool>>(), size0); |
| } |
| |
| TEST(TraitsTest, CantAllocateSizeTooSmall) { |
| uint8_t data[] = {0x00, 0x01, 0x02, 0x03}; |
| ::fuzzing::FuzzInput src(static_cast<uint8_t*>(data), 4); |
| |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(bool) - 1; |
| Allocate<bool>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(uint8_t) - 1; |
| Allocate<uint8_t>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(uint16_t) - 1; |
| Allocate<uint16_t>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(uint32_t) - 1; |
| Allocate<uint32_t>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(uint64_t) - 1; |
| Allocate<uint64_t>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(int8_t) - 1; |
| Allocate<int8_t>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(int16_t) - 1; |
| Allocate<int16_t>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(int32_t) - 1; |
| Allocate<int32_t>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(int64_t) - 1; |
| Allocate<int64_t>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(float) - 1; |
| Allocate<float>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(double) - 1; |
| Allocate<double>{}(&src, &size); |
| }, |
| ""); |
| EXPECT_DEATH( |
| { |
| size_t size = sizeof(zx_handle_t) - 1; |
| Allocate<::zx::handle>{}(&src, &size); |
| }, |
| ""); |
| // TODO(markdittmer): Test handles to objects; e.g., ::zx::channel. |
| } |
| |
| TEST(TraitsTest, CanAllocateJustEnough) { |
| EXPECT_EQ(DoAlloc<bool>().second, sizeof(bool)); |
| EXPECT_EQ(DoAlloc<uint8_t>().second, sizeof(uint8_t)); |
| EXPECT_EQ(DoAlloc<uint16_t>().second, sizeof(uint16_t)); |
| EXPECT_EQ(DoAlloc<uint32_t>().second, sizeof(uint32_t)); |
| EXPECT_EQ(DoAlloc<uint64_t>().second, sizeof(uint64_t)); |
| EXPECT_EQ(DoAlloc<int8_t>().second, sizeof(int8_t)); |
| EXPECT_EQ(DoAlloc<int16_t>().second, sizeof(int16_t)); |
| EXPECT_EQ(DoAlloc<int32_t>().second, sizeof(int32_t)); |
| EXPECT_EQ(DoAlloc<int64_t>().second, sizeof(int64_t)); |
| EXPECT_EQ(DoAlloc<float>().second, sizeof(float)); |
| EXPECT_EQ(DoAlloc<double>().second, sizeof(double)); |
| EXPECT_EQ(DoAlloc<::zx::handle>().second, sizeof(zx_handle_t)); |
| // TODO(markdittmer): Test handles to objects; e.g., ::zx::channel. |
| } |
| |
| TEST(TestTraits, CanAllocateInnerMinSizeZero) { |
| EXPECT_EQ((DoSizedAlloc<std::array<std::array<uint8_t, 2>, 0>>(0).second), size0); |
| EXPECT_EQ((DoSizedAlloc<std::array<std::array<uint8_t, 0>, 2>>(0).second), size0); |
| EXPECT_EQ((DoSizedAlloc<std::array<std::array<uint8_t, 0>, 0>>(0).second), size0); |
| |
| EXPECT_EQ((DoSizedAlloc<std::array<std::array<uint8_t, 2>, 0>>(sizeof(uint8_t) * 2).second), |
| size0); |
| EXPECT_EQ((DoSizedAlloc<std::array<std::array<uint8_t, 0>, 2>>(sizeof(uint8_t) * 2).second), |
| size0); |
| EXPECT_EQ((DoSizedAlloc<std::array<std::array<uint8_t, 0>, 0>>(sizeof(uint8_t) * 2).second), |
| size0); |
| |
| std::pair<std::array<std::array<uint8_t, 2>, 2>, size_t> aa_and_size = |
| DoSizedAlloc<std::array<std::array<uint8_t, 2>, 2>>(sizeof(uint8_t) * 4); |
| EXPECT_EQ(aa_and_size.second, sizeof(uint8_t) * 4); |
| ASSERT_EQ(aa_and_size.first.size(), size2); |
| EXPECT_EQ(aa_and_size.first[0].size(), size2); |
| EXPECT_EQ(aa_and_size.first[1].size(), size2); |
| |
| // Undersized allocation: Vector assumes MinSize<T>()=0 items take up at |
| // at least 8 bytes each. Here, even though 4 bytes is enough for non-zero |
| // vectors, the outer vector using the 8-byte heuristic assumes 4 bytes won't |
| // be enough to allocate any items. |
| { |
| const size_t four_uint8_ts = sizeof(uint8_t) * 4; |
| EXPECT_LT(four_uint8_ts, size8); |
| std::pair<std::vector<std::vector<uint8_t>>, size_t> vv_and_size = |
| DoSizedAlloc<std::vector<std::vector<uint8_t>>>(four_uint8_ts); |
| EXPECT_EQ(vv_and_size.second, size0); |
| EXPECT_EQ(vv_and_size.first.size(), size0); |
| } |
| |
| // Single outer allocation: For heuristic reasons explained above, outer |
| // vector will allocate 8 bytes for inner vector, yielding: |
| // vector(vector(u8, u8, u8, u8, u8, u8, u8, u8)). |
| { |
| const size_t eight_uint8_ts = sizeof(uint8_t) * 8; |
| EXPECT_EQ(eight_uint8_ts, size8); |
| std::pair<std::vector<std::vector<uint8_t>>, size_t> vv_and_size = |
| DoSizedAlloc<std::vector<std::vector<uint8_t>>>(eight_uint8_ts); |
| EXPECT_EQ(vv_and_size.second, size8); |
| ASSERT_EQ(vv_and_size.first.size(), size1); |
| EXPECT_EQ(vv_and_size.first[0].size(), size8); |
| } |
| } |
| |
| } // namespace |
| } // namespace fuzzing |