1 //===- DXContainerTest.cpp - Tests for DXContainerFile --------------------===//
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
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"
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};
40 DXContainer::create(getMemoryBuffer
<4>(Buffer
)),
41 FailedWithMessage("Reading structure out of file bounds"));
44 TEST(DXCFile
, EmptyFile
) {
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};
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
) {
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,
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.
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,
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};
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.
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
)),
126 "Part offset for part 1 begins before the previous part ends"));
129 TEST(DXCFile
, ParseEmptyParts
) {
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,
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);
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.
159 EXPECT_TRUE(memcmp(It
->Part
.Name
, "FKE0", 4) == 0);
161 EXPECT_TRUE(memcmp(It
->Part
.Name
, "FKE1", 4) == 0);
163 EXPECT_TRUE(memcmp(It
->Part
.Name
, "FKE2", 4) == 0);
165 EXPECT_TRUE(memcmp(It
->Part
.Name
, "FKE3", 4) == 0);
167 EXPECT_TRUE(memcmp(It
->Part
.Name
, "FKE4", 4) == 0);
169 EXPECT_TRUE(memcmp(It
->Part
.Name
, "FKE5", 4) == 0);
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.
181 // Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
182 // 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
195 // DXILMajorVersion: 1
196 // DXILMinorVersion: 5
198 // DXIL: [ 0x42, 0x43, 0xC0, 0xDE, ]
200 TEST(DXCFile
, ParseDXILPart
) {
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};
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
;
227 Yaml
, /*Ctxt=*/nullptr,
228 [](const SMDiagnostic
&Diag
, void *DiagContext
) {
229 *static_cast<SMDiagnostic
*>(DiagContext
) = Diag
;
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
"(
252 Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
253 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
264 PayloadSizeInBytes: 4092
265 MinimumWaveLaneCount: 0
266 MaximumWaveLaneCount: 4294967295
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
;
311 EXPECT_EQ(Binding
.Type
, 1u);
312 EXPECT_EQ(Binding
.Flags
, 0u);
317 EXPECT_EQ(Binding
.Type
, 2u);
318 EXPECT_EQ(Binding
.Flags
, 0u);
323 EXPECT_TRUE(It
== PSVInfo
->getResources().begin());
325 EXPECT_EQ(Binding
.Type
, 1u);
326 EXPECT_EQ(Binding
.Flags
, 0u);
331 EXPECT_EQ(Binding
.Type
, 1u);
332 EXPECT_EQ(Binding
.Flags
, 0u);
337 EXPECT_EQ(Binding
.Type
, 2u);
338 EXPECT_EQ(Binding
.Flags
, 0u);
343 EXPECT_EQ(Binding
.Type
, 3u);
344 EXPECT_EQ(Binding
.Flags
, 0u);
346 EXPECT_FALSE(It
== PSVInfo
->getResources().end());
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);
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);
370 EXPECT_TRUE(It
== PSVInfo
->getResources().end());
372 EXPECT_EQ(Binding
.Type
, 0u);
373 EXPECT_EQ(Binding
.Flags
, 0u);
378 EXPECT_TRUE(Old
== PSVInfo
->getResources().end());
380 EXPECT_EQ(Binding
.Type
, 0u);
381 EXPECT_EQ(Binding
.Flags
, 0u);
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:
395 // Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
396 // 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
409 // DXILMajorVersion: 1
410 // DXILMinorVersion: 0
417 // MinimumWaveLaneCount: 0
418 // MaximumWaveLaneCount: 0
419 // ResourceStride: 16
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
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
)),
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
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
)),
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.
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
)),
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.
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
)),
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.
525 // Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
526 // 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
539 // DXILMajorVersion: 1
540 // DXILMinorVersion: 0
547 // MinimumWaveLaneCount: 0
548 // MaximumWaveLaneCount: 0
549 // ResourceStride: 16
560 TEST(DXCFile
, PSVResourceIteratorsStride
) {
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,
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
;
590 EXPECT_EQ(Binding
.Type
, 1u);
591 EXPECT_EQ(Binding
.Space
, 2u);
592 EXPECT_EQ(Binding
.LowerBound
, 3u);
593 EXPECT_EQ(Binding
.UpperBound
, 4u);
598 EXPECT_EQ(Binding
.Type
, 5u);
599 EXPECT_EQ(Binding
.Space
, 6u);
600 EXPECT_EQ(Binding
.LowerBound
, 7u);
601 EXPECT_EQ(Binding
.UpperBound
, 8u);
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);
616 EXPECT_EQ(Binding
.Type
, 1u);
617 EXPECT_EQ(Binding
.Space
, 2u);
618 EXPECT_EQ(Binding
.LowerBound
, 3u);
619 EXPECT_EQ(Binding
.UpperBound
, 4u);
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());
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
) {
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
) {
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
)),
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:
696 Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
697 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
712 SystemValue: Undefined
717 MinPrecision: Default
720 The unmodified hex sequence is:
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.
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
)),
756 "Signature parameters extend beyond the part boundary"));
761 // This binary only has one parameter, but the start offset is beyond the
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
)),
778 "Signature parameters extend beyond the part boundary"));
783 // This parameter has a name offset of 3, which is before the start of the
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
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"));