Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / unittests / Object / DXContainerTest.cpp
blob9da6543c520c7444de3a2a7d3000b7ff59c7bc5c
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 //===----------------------------------------------------------------------===//
9 #include "llvm/Object/DXContainer.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/BinaryFormat/Magic.h"
12 #include "llvm/ObjectYAML/DXContainerYAML.h"
13 #include "llvm/ObjectYAML/yaml2obj.h"
14 #include "llvm/Support/MemoryBufferRef.h"
15 #include "llvm/Testing/Support/Error.h"
16 #include "gtest/gtest.h"
18 using namespace llvm;
19 using namespace llvm::object;
21 template <std::size_t X> MemoryBufferRef getMemoryBuffer(uint8_t Data[X]) {
22 StringRef Obj(reinterpret_cast<char *>(&Data[0]), X);
23 return MemoryBufferRef(Obj, "");
26 TEST(DXCFile, IdentifyMagic) {
28 StringRef Buffer("DXBC");
29 EXPECT_EQ(identify_magic(Buffer), file_magic::dxcontainer_object);
32 StringRef Buffer("DXBCBlahBlahBlah");
33 EXPECT_EQ(identify_magic(Buffer), file_magic::dxcontainer_object);
37 TEST(DXCFile, ParseHeaderErrors) {
38 uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43};
39 EXPECT_THAT_EXPECTED(
40 DXContainer::create(getMemoryBuffer<4>(Buffer)),
41 FailedWithMessage("Reading structure out of file bounds"));
44 TEST(DXCFile, EmptyFile) {
45 EXPECT_THAT_EXPECTED(
46 DXContainer::create(MemoryBufferRef(StringRef("", 0), "")),
47 FailedWithMessage("Reading structure out of file bounds"));
50 TEST(DXCFile, ParseHeader) {
51 uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
54 0x70, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
55 DXContainer C =
56 llvm::cantFail(DXContainer::create(getMemoryBuffer<32>(Buffer)));
57 EXPECT_TRUE(memcmp(C.getHeader().Magic, "DXBC", 4) == 0);
58 EXPECT_TRUE(memcmp(C.getHeader().FileHash.Digest,
59 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0);
60 EXPECT_EQ(C.getHeader().Version.Major, 1u);
61 EXPECT_EQ(C.getHeader().Version.Minor, 0u);
64 TEST(DXCFile, ParsePartMissingOffsets) {
65 uint8_t Buffer[] = {
66 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
68 0x00, 0x00, 0x70, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
70 EXPECT_THAT_EXPECTED(
71 DXContainer::create(getMemoryBuffer<32>(Buffer)),
72 FailedWithMessage("Reading structure out of file bounds"));
75 TEST(DXCFile, ParsePartInvalidOffsets) {
76 // This test covers a case where the part offset is beyond the buffer size.
77 uint8_t Buffer[] = {
78 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
80 0x70, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
82 EXPECT_THAT_EXPECTED(
83 DXContainer::create(getMemoryBuffer<36>(Buffer)),
84 FailedWithMessage("Part offset points beyond boundary of the file"));
87 TEST(DXCFile, ParsePartTooSmallBuffer) {
88 // This test covers a case where there is insufficent space to read a full
89 // part name, but the offset for the part is inside the buffer.
90 uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
93 0x26, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
94 0x24, 0x00, 0x00, 0x00, 0x46, 0x4B};
95 EXPECT_THAT_EXPECTED(
96 DXContainer::create(getMemoryBuffer<38>(Buffer)),
97 FailedWithMessage("File not large enough to read part name"));
100 TEST(DXCFile, ParsePartNoSize) {
101 // This test covers a case where the part's header is readable, but the size
102 // the part extends beyond the boundaries of the file.
103 uint8_t Buffer[] = {0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x0D, 0x00,
106 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
107 0x46, 0x4B, 0x45, 0x30, 0x00, 0x00};
108 EXPECT_THAT_EXPECTED(
109 DXContainer::create(getMemoryBuffer<42>(Buffer)),
110 FailedWithMessage("Reading part size out of file bounds"));
113 TEST(DXCFile, ParseOverlappingParts) {
114 // This test covers a case where a part's offset is inside the size range
115 // covered by the previous part.
116 uint8_t Buffer[] = {
117 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
119 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
120 0x2C, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x30, 0x08, 0x00, 0x00, 0x00,
121 0x46, 0x4B, 0x45, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 EXPECT_THAT_EXPECTED(
124 DXContainer::create(getMemoryBuffer<60>(Buffer)),
125 FailedWithMessage(
126 "Part offset for part 1 begins before the previous part ends"));
129 TEST(DXCFile, ParseEmptyParts) {
130 uint8_t Buffer[] = {
131 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
133 0x70, 0x0D, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
134 0x44, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
135 0x5C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
136 0x46, 0x4B, 0x45, 0x30, 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x31,
137 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x32, 0x00, 0x00, 0x00, 0x00,
138 0x46, 0x4B, 0x45, 0x33, 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x34,
139 0x00, 0x00, 0x00, 0x00, 0x46, 0x4B, 0x45, 0x35, 0x00, 0x00, 0x00, 0x00,
140 0x46, 0x4B, 0x45, 0x36, 0x00, 0x00, 0x00, 0x00,
142 DXContainer C =
143 llvm::cantFail(DXContainer::create(getMemoryBuffer<116>(Buffer)));
144 EXPECT_EQ(C.getHeader().PartCount, 7u);
146 // All the part sizes are 0, which makes a nice test of the range based for
147 int ElementsVisited = 0;
148 for (auto Part : C) {
149 EXPECT_EQ(Part.Part.Size, 0u);
150 EXPECT_EQ(Part.Data.size(), 0u);
151 ++ElementsVisited;
153 EXPECT_EQ(ElementsVisited, 7);
156 // These are all intended to be fake part names so that the parser doesn't
157 // try to parse the part data.
158 auto It = C.begin();
159 EXPECT_TRUE(memcmp(It->Part.Name, "FKE0", 4) == 0);
160 ++It;
161 EXPECT_TRUE(memcmp(It->Part.Name, "FKE1", 4) == 0);
162 ++It;
163 EXPECT_TRUE(memcmp(It->Part.Name, "FKE2", 4) == 0);
164 ++It;
165 EXPECT_TRUE(memcmp(It->Part.Name, "FKE3", 4) == 0);
166 ++It;
167 EXPECT_TRUE(memcmp(It->Part.Name, "FKE4", 4) == 0);
168 ++It;
169 EXPECT_TRUE(memcmp(It->Part.Name, "FKE5", 4) == 0);
170 ++It;
171 EXPECT_TRUE(memcmp(It->Part.Name, "FKE6", 4) == 0);
172 ++It; // Don't increment past the end
173 EXPECT_TRUE(memcmp(It->Part.Name, "FKE6", 4) == 0);
177 // This test verify DXIL part are correctly parsed.
178 // This test is based on the binary output constructed from this yaml.
179 // --- !dxcontainer
180 // Header:
181 // Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
182 // 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
183 // Version:
184 // Major: 1
185 // Minor: 0
186 // PartCount: 1
187 // Parts:
188 // - Name: DXIL
189 // Size: 28
190 // Program:
191 // MajorVersion: 6
192 // MinorVersion: 5
193 // ShaderKind: 5
194 // Size: 8
195 // DXILMajorVersion: 1
196 // DXILMinorVersion: 5
197 // DXILSize: 4
198 // DXIL: [ 0x42, 0x43, 0xC0, 0xDE, ]
199 // ...
200 TEST(DXCFile, ParseDXILPart) {
201 uint8_t Buffer[] = {
202 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
204 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
205 0x44, 0x58, 0x49, 0x4c, 0x1c, 0x00, 0x00, 0x00, 0x65, 0x00, 0x05, 0x00,
206 0x08, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x05, 0x01, 0x00, 0x00,
207 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde};
208 DXContainer C =
209 llvm::cantFail(DXContainer::create(getMemoryBuffer<116>(Buffer)));
210 EXPECT_EQ(C.getHeader().PartCount, 1u);
211 const std::optional<object::DXContainer::DXILData> &DXIL = C.getDXIL();
212 EXPECT_TRUE(DXIL.has_value());
213 dxbc::ProgramHeader Header = DXIL->first;
214 EXPECT_EQ(Header.getMajorVersion(), 6u);
215 EXPECT_EQ(Header.getMinorVersion(), 5u);
216 EXPECT_EQ(Header.ShaderKind, 5u);
217 EXPECT_EQ(Header.Size, 8u);
218 EXPECT_EQ(Header.Bitcode.MajorVersion, 1u);
219 EXPECT_EQ(Header.Bitcode.MinorVersion, 5u);
222 static Expected<DXContainer>
223 generateDXContainer(StringRef Yaml, SmallVectorImpl<char> &BinaryData) {
224 DXContainerYAML::Object Obj;
225 SMDiagnostic GenerateDiag;
226 yaml::Input YIn(
227 Yaml, /*Ctxt=*/nullptr,
228 [](const SMDiagnostic &Diag, void *DiagContext) {
229 *static_cast<SMDiagnostic *>(DiagContext) = Diag;
231 &GenerateDiag);
233 YIn >> Obj;
234 if (YIn.error())
235 return createStringError(YIn.error(), GenerateDiag.getMessage());
237 raw_svector_ostream OS(BinaryData);
238 std::string ErrorMsg;
239 if (!yaml::yaml2dxcontainer(
240 Obj, OS, [&ErrorMsg](const Twine &Msg) { ErrorMsg = Msg.str(); }))
241 return createStringError(YIn.error(), ErrorMsg);
243 MemoryBufferRef BinaryDataRef = MemoryBufferRef(OS.str(), "");
245 return DXContainer::create(BinaryDataRef);
248 TEST(DXCFile, PSVResourceIterators) {
249 const char *Yaml = R"(
250 --- !dxcontainer
251 Header:
252 Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
253 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
254 Version:
255 Major: 1
256 Minor: 0
257 PartCount: 2
258 Parts:
259 - Name: PSV0
260 Size: 144
261 PSVInfo:
262 Version: 0
263 ShaderStage: 14
264 PayloadSizeInBytes: 4092
265 MinimumWaveLaneCount: 0
266 MaximumWaveLaneCount: 4294967295
267 ResourceStride: 16
268 Resources:
269 - Type: 1
270 Space: 1
271 LowerBound: 1
272 UpperBound: 1
273 - Type: 2
274 Space: 2
275 LowerBound: 2
276 UpperBound: 2
277 - Type: 3
278 Space: 3
279 LowerBound: 3
280 UpperBound: 3
281 - Name: DXIL
282 Size: 24
283 Program:
284 MajorVersion: 6
285 MinorVersion: 0
286 ShaderKind: 14
287 Size: 6
288 DXILMajorVersion: 1
289 DXILMinorVersion: 0
290 DXILSize: 0
294 SmallVector<char, 256> BinaryData;
295 auto C = generateDXContainer(Yaml, BinaryData);
297 ASSERT_THAT_EXPECTED(C, Succeeded());
299 const auto &PSVInfo = C->getPSVInfo();
300 ASSERT_TRUE(PSVInfo.has_value());
302 EXPECT_EQ(PSVInfo->getResourceCount(), 3u);
304 auto It = PSVInfo->getResources().begin();
306 EXPECT_TRUE(It == PSVInfo->getResources().begin());
308 dxbc::PSV::v2::ResourceBindInfo Binding;
310 Binding = *It;
311 EXPECT_EQ(Binding.Type, 1u);
312 EXPECT_EQ(Binding.Flags, 0u);
314 ++It;
315 Binding = *It;
317 EXPECT_EQ(Binding.Type, 2u);
318 EXPECT_EQ(Binding.Flags, 0u);
320 --It;
321 Binding = *It;
323 EXPECT_TRUE(It == PSVInfo->getResources().begin());
325 EXPECT_EQ(Binding.Type, 1u);
326 EXPECT_EQ(Binding.Flags, 0u);
328 --It;
329 Binding = *It;
331 EXPECT_EQ(Binding.Type, 1u);
332 EXPECT_EQ(Binding.Flags, 0u);
334 ++It;
335 Binding = *It;
337 EXPECT_EQ(Binding.Type, 2u);
338 EXPECT_EQ(Binding.Flags, 0u);
340 ++It;
341 Binding = *It;
343 EXPECT_EQ(Binding.Type, 3u);
344 EXPECT_EQ(Binding.Flags, 0u);
346 EXPECT_FALSE(It == PSVInfo->getResources().end());
348 ++It;
349 Binding = *It;
351 EXPECT_TRUE(It == PSVInfo->getResources().end());
352 EXPECT_FALSE(It != PSVInfo->getResources().end());
354 EXPECT_EQ(Binding.Type, 0u);
355 EXPECT_EQ(Binding.Flags, 0u);
358 auto Old = It++;
359 Binding = *Old;
361 EXPECT_TRUE(Old == PSVInfo->getResources().end());
362 EXPECT_FALSE(Old != PSVInfo->getResources().end());
364 EXPECT_EQ(Binding.Type, 0u);
365 EXPECT_EQ(Binding.Flags, 0u);
368 Binding = *It;
370 EXPECT_TRUE(It == PSVInfo->getResources().end());
372 EXPECT_EQ(Binding.Type, 0u);
373 EXPECT_EQ(Binding.Flags, 0u);
376 auto Old = It--;
377 Binding = *Old;
378 EXPECT_TRUE(Old == PSVInfo->getResources().end());
380 EXPECT_EQ(Binding.Type, 0u);
381 EXPECT_EQ(Binding.Flags, 0u);
384 Binding = *It;
386 EXPECT_EQ(Binding.Type, 3u);
387 EXPECT_EQ(Binding.Flags, 0u);
390 // The malicious file bits in these tests are mutations of the binary produced
391 // by the following YAML:
393 // --- !dxcontainer
394 // Header:
395 // Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
396 // 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
397 // Version:
398 // Major: 1
399 // Minor: 0
400 // PartCount: 3
401 // Parts:
402 // - Name: DXIL
403 // Size: 24
404 // Program:
405 // MajorVersion: 6
406 // MinorVersion: 0
407 // ShaderKind: 14
408 // Size: 6
409 // DXILMajorVersion: 1
410 // DXILMinorVersion: 0
411 // DXILSize: 0
412 // - Name: PSV0
413 // Size: 36
414 // PSVInfo:
415 // Version: 0
416 // ShaderStage: 5
417 // MinimumWaveLaneCount: 0
418 // MaximumWaveLaneCount: 0
419 // ResourceStride: 16
420 // Resources: []
421 // - Name: BLEH
422 // Size: 16
423 // ...
425 TEST(DXCFile, MaliciousFiles) {
427 // In this file blob, the file size is specified as 96 bytes (0x60), and the
428 // PSV0 data is specified as 24 bytes (0x18) which extends beyond the size of
429 // the file.
431 uint8_t Buffer[] = {
432 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
434 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
435 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C, 0x18, 0x00, 0x00, 0x00,
436 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C,
437 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
438 0x50, 0x53, 0x56, 0x30, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
439 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
441 EXPECT_THAT_EXPECTED(
442 DXContainer::create(getMemoryBuffer<96>(Buffer)),
443 FailedWithMessage(
444 "Pipeline state data extends beyond the bounds of the part"));
447 // PSV extends beyond part, but in file range. In this blob the file size is
448 // 144 bytes (0x90), and the PSV part is 36 bytes (0x24), and the PSV data is
449 // 40 bytes (0x40).
451 uint8_t Buffer[] = {
452 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
454 0x90, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
455 0x4C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C,
456 0x18, 0x00, 0x00, 0x00, 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00,
457 0x44, 0x58, 0x49, 0x4C, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
458 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0x24, 0x00, 0x00, 0x00,
459 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
462 0x42, 0x4C, 0x45, 0x48, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
463 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
465 EXPECT_THAT_EXPECTED(
466 DXContainer::create(getMemoryBuffer<144>(Buffer)),
467 FailedWithMessage(
468 "Pipeline state data extends beyond the bounds of the part"));
471 // In this file blob, the file is 116 bytes (0x74). The file structure is
472 // valid except that it specifies 1 16 byte resource binding which would
473 // extend beyond the range of the part and file.
475 uint8_t Buffer[] = {
476 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
477 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
478 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
479 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C, 0x18, 0x00, 0x00, 0x00,
480 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C,
481 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482 0x50, 0x53, 0x56, 0x30, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
487 EXPECT_THAT_EXPECTED(
488 DXContainer::create(getMemoryBuffer<116>(Buffer)),
489 FailedWithMessage(
490 "Resource binding data extends beyond the bounds of the part"));
493 // In this file blob, the file is 116 bytes (0x74). The file structure is
494 // valid except that it specifies 1 16 byte resource binding which would
495 // extend beyond the range of the part and into the `BLEH` part.
497 uint8_t Buffer[] = {
498 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
500 0x90, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
501 0x4C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C,
502 0x18, 0x00, 0x00, 0x00, 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00,
503 0x44, 0x58, 0x49, 0x4C, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
504 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0x24, 0x00, 0x00, 0x00,
505 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
508 0x42, 0x4C, 0x45, 0x48, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511 EXPECT_THAT_EXPECTED(
512 DXContainer::create(getMemoryBuffer<144>(Buffer)),
513 FailedWithMessage(
514 "Resource binding data extends beyond the bounds of the part"));
518 // This test verifies that the resource iterator follows the stride even if the
519 // stride doesn't match an expected or known value. In this test, the resource
520 // data is structured validly, with 32 bytes per resource. This test is based on
521 // editing the binary output constructed from this yaml.
523 // --- !dxcontainer
524 // Header:
525 // Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
526 // 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
527 // Version:
528 // Major: 1
529 // Minor: 0
530 // PartCount: 2
531 // Parts:
532 // - Name: DXIL
533 // Size: 24
534 // Program:
535 // MajorVersion: 6
536 // MinorVersion: 0
537 // ShaderKind: 14
538 // Size: 6
539 // DXILMajorVersion: 1
540 // DXILMinorVersion: 0
541 // DXILSize: 0
542 // - Name: PSV0
543 // Size: 100
544 // PSVInfo:
545 // Version: 0
546 // ShaderStage: 5
547 // MinimumWaveLaneCount: 0
548 // MaximumWaveLaneCount: 0
549 // ResourceStride: 16
550 // Resources:
551 // - Type: 1
552 // Space: 2
553 // LowerBound: 3
554 // UpperBound: 4
555 // - Type: 5
556 // Space: 6
557 // LowerBound: 7
558 // UpperBound: 8
559 // ...
560 TEST(DXCFile, PSVResourceIteratorsStride) {
561 uint8_t Buffer[] = {
562 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
564 0x28, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C, 0x18, 0x00, 0x00, 0x00,
565 0x60, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4C, 0x00, 0x01, 0x00, 0x00,
566 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0x64, 0x00, 0x00, 0x00,
567 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
569 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
570 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
572 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00,
575 DXContainer C =
576 llvm::cantFail(DXContainer::create(getMemoryBuffer<180>(Buffer)));
578 const auto &PSVInfo = C.getPSVInfo();
579 ASSERT_TRUE(PSVInfo.has_value());
581 ASSERT_EQ(PSVInfo->getResourceCount(), 2u);
583 auto It = PSVInfo->getResources().begin();
585 EXPECT_TRUE(It == PSVInfo->getResources().begin());
587 dxbc::PSV::v2::ResourceBindInfo Binding;
589 Binding = *It;
590 EXPECT_EQ(Binding.Type, 1u);
591 EXPECT_EQ(Binding.Space, 2u);
592 EXPECT_EQ(Binding.LowerBound, 3u);
593 EXPECT_EQ(Binding.UpperBound, 4u);
595 ++It;
596 Binding = *It;
598 EXPECT_EQ(Binding.Type, 5u);
599 EXPECT_EQ(Binding.Space, 6u);
600 EXPECT_EQ(Binding.LowerBound, 7u);
601 EXPECT_EQ(Binding.UpperBound, 8u);
603 --It;
604 Binding = *It;
606 EXPECT_TRUE(It == PSVInfo->getResources().begin());
608 EXPECT_EQ(Binding.Type, 1u);
609 EXPECT_EQ(Binding.Space, 2u);
610 EXPECT_EQ(Binding.LowerBound, 3u);
611 EXPECT_EQ(Binding.UpperBound, 4u);
613 --It;
614 Binding = *It;
616 EXPECT_EQ(Binding.Type, 1u);
617 EXPECT_EQ(Binding.Space, 2u);
618 EXPECT_EQ(Binding.LowerBound, 3u);
619 EXPECT_EQ(Binding.UpperBound, 4u);
621 ++It;
622 Binding = *It;
624 EXPECT_EQ(Binding.Type, 5u);
625 EXPECT_EQ(Binding.Space, 6u);
626 EXPECT_EQ(Binding.LowerBound, 7u);
627 EXPECT_EQ(Binding.UpperBound, 8u);;
630 EXPECT_FALSE(It == PSVInfo->getResources().end());
632 ++It;
633 Binding = *It;
635 EXPECT_TRUE(It == PSVInfo->getResources().end());
636 EXPECT_FALSE(It != PSVInfo->getResources().end());
638 EXPECT_EQ(Binding.Type, 0u);
639 EXPECT_EQ(Binding.Flags, 0u);
642 // This test binary is created using mutations of the yaml in the SigElements
643 // test found under test/ObjectYAML/DXContainer/SigElements.yaml.
645 TEST(DXCFile, MisalignedStringTable) {
646 uint8_t Buffer[] = {
647 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
649 0xb4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
650 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x18, 0x00, 0x00, 0x00,
651 0x60, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c,
652 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653 0x50, 0x53, 0x56, 0x30, 0x68, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
656 0x05, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x10, 0x20, 0x40,
657 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
661 EXPECT_THAT_EXPECTED(DXContainer::create(getMemoryBuffer<168>(Buffer)),
662 FailedWithMessage("String table misaligned"));
665 // This test binary is created using mutations of the yaml in the SigElements
666 // test found under test/ObjectYAML/DXContainer/SigElements.yaml.
667 TEST(DXCFile, SigElementsExtendBeyondPart) {
668 uint8_t Buffer[] = {
669 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
671 0xb4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
672 0x48, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x18, 0x00, 0x00, 0x00,
673 0x60, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c,
674 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675 0x50, 0x53, 0x56, 0x30, 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
678 0x05, 0x80, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x08, 0x10, 0x20, 0x40,
679 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x49, 0x4e, 0x00,
680 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
681 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x02, 0x00, 0x42, 0x00, 0x02, 0x00, 0x03, 0x00};
683 EXPECT_THAT_EXPECTED(
684 DXContainer::create(getMemoryBuffer<164>(Buffer)),
685 FailedWithMessage(
686 "Signature elements extend beyond the size of the part"));
689 TEST(DXCFile, MalformedSignature) {
691 The tests here exercise the DXContainer Signature section parser. These tests
692 are based on modifying the binary described by the following yaml:
694 --- !dxcontainer
695 Header:
696 Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
697 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
698 Version:
699 Major: 1
700 Minor: 0
701 FileSize: 128
702 PartCount: 1
703 PartOffsets: [ 64 ]
704 Parts:
705 - Name: ISG1
706 Size: 52
707 Signature:
708 Parameters:
709 - Stream: 0
710 Name: AAA
711 Index: 0
712 SystemValue: Undefined
713 CompType: Float32
714 Register: 0
715 Mask: 7
716 ExclusiveMask: 2
717 MinPrecision: Default
720 The unmodified hex sequence is:
722 uint8_t Buffer[] = {
723 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80,
725 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
726 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
727 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
728 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08,
729 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
730 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
731 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00,
732 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
739 // This binary says the signature has 10 parameters, but the part data is
740 // only big enough for 1.
741 uint8_t Buffer[] = {
742 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
743 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
744 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
746 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
747 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
748 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00};
753 EXPECT_THAT_EXPECTED(
754 DXContainer::create(getMemoryBuffer<164>(Buffer)),
755 FailedWithMessage(
756 "Signature parameters extend beyond the part boundary"));
761 // This binary only has one parameter, but the start offset is beyond the
762 // size of the part.
763 uint8_t Buffer[] = {
764 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
766 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
770 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
771 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00};
775 EXPECT_THAT_EXPECTED(
776 DXContainer::create(getMemoryBuffer<164>(Buffer)),
777 FailedWithMessage(
778 "Signature parameters extend beyond the part boundary"));
783 // This parameter has a name offset of 3, which is before the start of the
784 // string table.
785 uint8_t Buffer[] = {
786 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
788 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
791 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
792 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
793 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
795 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00};
797 EXPECT_THAT_EXPECTED(
798 DXContainer::create(getMemoryBuffer<164>(Buffer)),
799 FailedWithMessage("Invalid parameter name offset: name starts before "
800 "the first name offset"));
804 // This parameter has a name offset of 255, which is after the end of the
805 // part.
806 uint8_t Buffer[] = {
807 0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
809 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
813 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
816 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
817 0x00, 0x00, 0x00, 0x00};
818 EXPECT_THAT_EXPECTED(
819 DXContainer::create(getMemoryBuffer<164>(Buffer)),
820 FailedWithMessage("Invalid parameter name offset: name starts after "
821 "the end of the part data"));