• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "gtest/gtest.h"
16 #include "source/table.h"
17 #include "spirv-tools/libspirv.h"
18 
19 namespace spvtools {
20 namespace {
21 
22 // TODO(antiagainst): Use public C API for setting the consumer once exists.
23 #ifndef SPIRV_TOOLS_SHAREDLIB
SetContextMessageConsumer(spv_context context,MessageConsumer consumer)24 void SetContextMessageConsumer(spv_context context, MessageConsumer consumer) {
25   spvtools::SetContextMessageConsumer(context, consumer);
26 }
27 #else
28 void SetContextMessageConsumer(spv_context, MessageConsumer) {}
29 #endif
30 
31 // The default consumer is a null std::function.
TEST(CInterface,DefaultConsumerNullDiagnosticForValidInput)32 TEST(CInterface, DefaultConsumerNullDiagnosticForValidInput) {
33   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
34   const char input_text[] =
35       "OpCapability Shader\n"
36       "OpCapability Linkage\n"
37       "OpMemoryModel Logical GLSL450";
38 
39   spv_binary binary = nullptr;
40   EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
41                                          sizeof(input_text), &binary, nullptr));
42 
43   {
44     // Sadly the compiler don't allow me to feed binary directly to
45     // spvValidate().
46     spv_const_binary_t b{binary->code, binary->wordCount};
47     EXPECT_EQ(SPV_SUCCESS, spvValidate(context, &b, nullptr));
48   }
49 
50   spv_text text = nullptr;
51   EXPECT_EQ(SPV_SUCCESS, spvBinaryToText(context, binary->code,
52                                          binary->wordCount, 0, &text, nullptr));
53 
54   spvTextDestroy(text);
55   spvBinaryDestroy(binary);
56   spvContextDestroy(context);
57 }
58 
59 // The default consumer is a null std::function.
TEST(CInterface,DefaultConsumerNullDiagnosticForInvalidAssembling)60 TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidAssembling) {
61   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
62   const char input_text[] = "%1 = OpName";
63 
64   spv_binary binary = nullptr;
65   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
66             spvTextToBinary(context, input_text, sizeof(input_text), &binary,
67                             nullptr));
68   spvBinaryDestroy(binary);
69   spvContextDestroy(context);
70 }
71 
72 // The default consumer is a null std::function.
TEST(CInterface,DefaultConsumerNullDiagnosticForInvalidDiassembling)73 TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidDiassembling) {
74   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
75   const char input_text[] = "OpNop";
76 
77   spv_binary binary = nullptr;
78   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
79                                          sizeof(input_text), &binary, nullptr));
80   // Change OpNop to an invalid (wordcount|opcode) word.
81   binary->code[binary->wordCount - 1] = 0xffffffff;
82 
83   spv_text text = nullptr;
84   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
85             spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
86                             nullptr));
87 
88   spvTextDestroy(text);
89   spvBinaryDestroy(binary);
90   spvContextDestroy(context);
91 }
92 
93 // The default consumer is a null std::function.
TEST(CInterface,DefaultConsumerNullDiagnosticForInvalidValidating)94 TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidValidating) {
95   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
96   const char input_text[] = "OpNop";
97 
98   spv_binary binary = nullptr;
99   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
100                                          sizeof(input_text), &binary, nullptr));
101 
102   spv_const_binary_t b{binary->code, binary->wordCount};
103   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
104 
105   spvBinaryDestroy(binary);
106   spvContextDestroy(context);
107 }
108 
TEST(CInterface,SpecifyConsumerNullDiagnosticForAssembling)109 TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) {
110   const char input_text[] = "     OpName\n";
111 
112   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
113   int invocation = 0;
114   SetContextMessageConsumer(
115       context,
116       [&invocation](spv_message_level_t level, const char* source,
117                     const spv_position_t& position, const char* message) {
118         ++invocation;
119         EXPECT_EQ(SPV_MSG_ERROR, level);
120         // The error happens at scanning the beginning of second line.
121         EXPECT_STREQ("input", source);
122         EXPECT_EQ(1u, position.line);
123         EXPECT_EQ(0u, position.column);
124         EXPECT_EQ(12u, position.index);
125         EXPECT_STREQ(
126             "Expected operand for OpName instruction, but found the end of the "
127             "stream.",
128             message);
129       });
130 
131   spv_binary binary = nullptr;
132   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
133             spvTextToBinary(context, input_text, sizeof(input_text), &binary,
134                             nullptr));
135 #ifndef SPIRV_TOOLS_SHAREDLIB
136   EXPECT_EQ(1, invocation);
137 #endif
138   spvBinaryDestroy(binary);
139   spvContextDestroy(context);
140 }
141 
TEST(CInterface,SpecifyConsumerNullDiagnosticForDisassembling)142 TEST(CInterface, SpecifyConsumerNullDiagnosticForDisassembling) {
143   const char input_text[] = "OpNop";
144 
145   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
146   int invocation = 0;
147   SetContextMessageConsumer(
148       context,
149       [&invocation](spv_message_level_t level, const char* source,
150                     const spv_position_t& position, const char* message) {
151         ++invocation;
152         EXPECT_EQ(SPV_MSG_ERROR, level);
153         EXPECT_STREQ("input", source);
154         EXPECT_EQ(0u, position.line);
155         EXPECT_EQ(0u, position.column);
156         EXPECT_EQ(1u, position.index);
157         EXPECT_STREQ("Invalid opcode: 65535", message);
158       });
159 
160   spv_binary binary = nullptr;
161   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
162                                          sizeof(input_text), &binary, nullptr));
163   // Change OpNop to an invalid (wordcount|opcode) word.
164   binary->code[binary->wordCount - 1] = 0xffffffff;
165 
166   spv_text text = nullptr;
167   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
168             spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
169                             nullptr));
170 #ifndef SPIRV_TOOLS_SHAREDLIB
171   EXPECT_EQ(1, invocation);
172 #endif
173 
174   spvTextDestroy(text);
175   spvBinaryDestroy(binary);
176   spvContextDestroy(context);
177 }
178 
TEST(CInterface,SpecifyConsumerNullDiagnosticForValidating)179 TEST(CInterface, SpecifyConsumerNullDiagnosticForValidating) {
180   const char input_text[] = "OpNop";
181 
182   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
183   int invocation = 0;
184   SetContextMessageConsumer(
185       context,
186       [&invocation](spv_message_level_t level, const char* source,
187                     const spv_position_t& position, const char* message) {
188         ++invocation;
189         EXPECT_EQ(SPV_MSG_ERROR, level);
190         EXPECT_STREQ("input", source);
191         EXPECT_EQ(0u, position.line);
192         EXPECT_EQ(0u, position.column);
193         // TODO(antiagainst): what validation reports is not a word offset here.
194         // It is inconsistent with diassembler. Should be fixed.
195         EXPECT_EQ(1u, position.index);
196         EXPECT_STREQ(
197             "Nop cannot appear before the memory model instruction\n"
198             "  OpNop\n",
199             message);
200       });
201 
202   spv_binary binary = nullptr;
203   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
204                                          sizeof(input_text), &binary, nullptr));
205 
206   spv_const_binary_t b{binary->code, binary->wordCount};
207   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
208 #ifndef SPIRV_TOOLS_SHAREDLIB
209   EXPECT_EQ(1, invocation);
210 #endif
211 
212   spvBinaryDestroy(binary);
213   spvContextDestroy(context);
214 }
215 
216 // When having both a consumer and an diagnostic object, the diagnostic object
217 // should take priority.
TEST(CInterface,SpecifyConsumerSpecifyDiagnosticForAssembling)218 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForAssembling) {
219   const char input_text[] = "     OpName";
220 
221   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
222   int invocation = 0;
223   SetContextMessageConsumer(
224       context,
225       [&invocation](spv_message_level_t, const char*, const spv_position_t&,
226                     const char*) { ++invocation; });
227 
228   spv_binary binary = nullptr;
229   spv_diagnostic diagnostic = nullptr;
230   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
231             spvTextToBinary(context, input_text, sizeof(input_text), &binary,
232                             &diagnostic));
233   EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
234   EXPECT_STREQ(
235       "Expected operand for OpName instruction, but found the end of the "
236       "stream.",
237       diagnostic->error);
238 
239   spvDiagnosticDestroy(diagnostic);
240   spvBinaryDestroy(binary);
241   spvContextDestroy(context);
242 }
243 
TEST(CInterface,SpecifyConsumerSpecifyDiagnosticForDisassembling)244 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForDisassembling) {
245   const char input_text[] = "OpNop";
246 
247   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
248   int invocation = 0;
249   SetContextMessageConsumer(
250       context,
251       [&invocation](spv_message_level_t, const char*, const spv_position_t&,
252                     const char*) { ++invocation; });
253 
254   spv_binary binary = nullptr;
255   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
256                                          sizeof(input_text), &binary, nullptr));
257   // Change OpNop to an invalid (wordcount|opcode) word.
258   binary->code[binary->wordCount - 1] = 0xffffffff;
259 
260   spv_diagnostic diagnostic = nullptr;
261   spv_text text = nullptr;
262   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
263             spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
264                             &diagnostic));
265 
266   EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
267   EXPECT_STREQ("Invalid opcode: 65535", diagnostic->error);
268 
269   spvTextDestroy(text);
270   spvDiagnosticDestroy(diagnostic);
271   spvBinaryDestroy(binary);
272   spvContextDestroy(context);
273 }
274 
TEST(CInterface,SpecifyConsumerSpecifyDiagnosticForValidating)275 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForValidating) {
276   const char input_text[] = "OpNop";
277 
278   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
279   int invocation = 0;
280   SetContextMessageConsumer(
281       context,
282       [&invocation](spv_message_level_t, const char*, const spv_position_t&,
283                     const char*) { ++invocation; });
284 
285   spv_binary binary = nullptr;
286   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
287                                          sizeof(input_text), &binary, nullptr));
288 
289   spv_diagnostic diagnostic = nullptr;
290   spv_const_binary_t b{binary->code, binary->wordCount};
291   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, &diagnostic));
292 
293   EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
294   EXPECT_STREQ(
295       "Nop cannot appear before the memory model instruction\n"
296       "  OpNop\n",
297       diagnostic->error);
298 
299   spvDiagnosticDestroy(diagnostic);
300   spvBinaryDestroy(binary);
301   spvContextDestroy(context);
302 }
303 
304 }  // namespace
305 }  // namespace spvtools
306