xref: /llvm-project/llvm/unittests/Object/DXContainerTest.cpp (revision 621ffbcbe4abe92fc085966f52fe95e2b8e19b8c)
1 //===- DXContainerTest.cpp - Tests for DXContainerFile --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Object/DXContainer.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/BinaryFormat/Magic.h"
12 #include "llvm/Support/MemoryBufferRef.h"
13 #include "llvm/Testing/Support/Error.h"
14 #include "gtest/gtest.h"
15 
16 using namespace llvm;
17 using namespace llvm::object;
18 
19 template <std::size_t X> MemoryBufferRef getMemoryBuffer(uint8_t Data[X]) {
20   StringRef Obj(reinterpret_cast<char *>(&Data[0]), X);
21   return MemoryBufferRef(Obj, "");
22 }
23 
24 TEST(DXCFile, IdentifyMagic) {
25   {
26     StringRef Buffer("DXBC");
27     EXPECT_EQ(identify_magic(Buffer), file_magic::dxcontainer_object);
28   }
29   {
30     StringRef Buffer("DXBCBlahBlahBlah");
31     EXPECT_EQ(identify_magic(Buffer), file_magic::dxcontainer_object);
32   }
33 }
34 
35 TEST(DXCFile, ParseHeaderErrors) {
36   uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43};
37   EXPECT_THAT_EXPECTED(
38       DXContainer::create(getMemoryBuffer<4>(Buffer)),
39       FailedWithMessage("Reading structure out of file bounds"));
40 }
41 
42 TEST(DXCFile, EmptyFile) {
43   EXPECT_THAT_EXPECTED(
44       DXContainer::create(MemoryBufferRef(StringRef("", 0), "")),
45       FailedWithMessage("Reading structure out of file bounds"));
46 }
47 
48 TEST(DXCFile, ParseHeader) {
49   uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
50                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51                       0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
52                       0x70, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
53   DXContainer C =
54       llvm::cantFail(DXContainer::create(getMemoryBuffer<32>(Buffer)));
55   EXPECT_TRUE(memcmp(C.getHeader().Magic, "DXBC", 4) == 0);
56   EXPECT_TRUE(memcmp(C.getHeader().FileHash.Digest,
57                      "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0);
58   EXPECT_EQ(C.getHeader().Version.Major, 1u);
59   EXPECT_EQ(C.getHeader().Version.Minor, 0u);
60 }
61 
62 TEST(DXCFile, ParsePartMissingOffsets) {
63   uint8_t Buffer[] = {
64       0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
66       0x00, 0x00, 0x70, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
67   };
68   EXPECT_THAT_EXPECTED(
69       DXContainer::create(getMemoryBuffer<32>(Buffer)),
70       FailedWithMessage("Reading structure out of file bounds"));
71 }
72 
73 TEST(DXCFile, ParsePartInvalidOffsets) {
74   // This test covers a case where the part offset is beyond the buffer size.
75   uint8_t Buffer[] = {
76       0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
78       0x70, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
79   };
80   EXPECT_THAT_EXPECTED(
81       DXContainer::create(getMemoryBuffer<36>(Buffer)),
82       FailedWithMessage("Part offset points beyond boundary of the file"));
83 }
84 
85 TEST(DXCFile, ParsePartTooSmallBuffer) {
86   // This test covers a case where there is insufficent space to read a full
87   // part name, but the offset for the part is inside the buffer.
88   uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
89                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90                       0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
91                       0x26, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
92                       0x24, 0x00, 0x00, 0x00, 0x46, 0x4B};
93   EXPECT_THAT_EXPECTED(
94       DXContainer::create(getMemoryBuffer<38>(Buffer)),
95       FailedWithMessage("File not large enough to read part name"));
96 }
97 
98 TEST(DXCFile, ParsePartNoSize) {
99   // This test covers a case where the part's header is readable, but the size
100   // the part extends beyond the boundaries of the file.
101   uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
102                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x0D, 0x00,
104                       0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
105                       0x46, 0x4B, 0x45, 0x30, 0x00, 0x00};
106   EXPECT_THAT_EXPECTED(
107       DXContainer::create(getMemoryBuffer<42>(Buffer)),
108       FailedWithMessage("Reading part size out of file bounds"));
109 }
110 
111 TEST(DXCFile, ParseOverlappingParts) {
112   // This test covers a case where a part's offset is inside the size range
113   // covered by the previous part.
114   uint8_t Buffer[] = {
115       0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
117       0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
118       0x2C, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x30, 0x08, 0x00, 0x00, 0x00,
119       0x46, 0x4B, 0x45, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120   };
121   EXPECT_THAT_EXPECTED(
122       DXContainer::create(getMemoryBuffer<60>(Buffer)),
123       FailedWithMessage(
124           "Part offset for part 1 begins before the previous part ends"));
125 }
126 
127 TEST(DXCFile, ParseEmptyParts) {
128   uint8_t Buffer[] = {
129       0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
131       0x70, 0x0D, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
132       0x44, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
133       0x5C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
134       0x46, 0x4B, 0x45, 0x30, 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x31,
135       0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x32, 0x00, 0x00, 0x00, 0x00,
136       0x46, 0x4B, 0x45, 0x33, 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x34,
137       0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x35, 0x00, 0x00, 0x00, 0x00,
138       0x46, 0x4B, 0x45, 0x36, 0x00, 0x00, 0x00, 0x00,
139   };
140   DXContainer C =
141       llvm::cantFail(DXContainer::create(getMemoryBuffer<116>(Buffer)));
142   EXPECT_EQ(C.getHeader().PartCount, 7u);
143 
144   // All the part sizes are 0, which makes a nice test of the range based for
145   int ElementsVisited = 0;
146   for (auto Part : C) {
147     EXPECT_EQ(Part.Part.Size, 0u);
148     EXPECT_EQ(Part.Data.size(), 0u);
149     ++ElementsVisited;
150   }
151   EXPECT_EQ(ElementsVisited, 7);
152 
153   {
154     // These are all intended to be fake part names so that the parser doesn't
155     // try to parse the part data.
156     auto It = C.begin();
157     EXPECT_TRUE(memcmp(It->Part.Name, "FKE0", 4) == 0);
158     ++It;
159     EXPECT_TRUE(memcmp(It->Part.Name, "FKE1", 4) == 0);
160     ++It;
161     EXPECT_TRUE(memcmp(It->Part.Name, "FKE2", 4) == 0);
162     ++It;
163     EXPECT_TRUE(memcmp(It->Part.Name, "FKE3", 4) == 0);
164     ++It;
165     EXPECT_TRUE(memcmp(It->Part.Name, "FKE4", 4) == 0);
166     ++It;
167     EXPECT_TRUE(memcmp(It->Part.Name, "FKE5", 4) == 0);
168     ++It;
169     EXPECT_TRUE(memcmp(It->Part.Name, "FKE6", 4) == 0);
170     ++It; // Don't increment past the end
171     EXPECT_TRUE(memcmp(It->Part.Name, "FKE6", 4) == 0);
172   }
173 }
174