replayer_test.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // Copyright (c) 2020 Google LLC
  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. #include "source/fuzz/replayer.h"
  15. #include "gtest/gtest.h"
  16. #include "source/fuzz/data_descriptor.h"
  17. #include "source/fuzz/fuzzer_util.h"
  18. #include "source/fuzz/instruction_descriptor.h"
  19. #include "source/fuzz/transformation_add_constant_scalar.h"
  20. #include "source/fuzz/transformation_add_global_variable.h"
  21. #include "source/fuzz/transformation_add_parameter.h"
  22. #include "source/fuzz/transformation_add_synonym.h"
  23. #include "source/fuzz/transformation_flatten_conditional_branch.h"
  24. #include "source/fuzz/transformation_split_block.h"
  25. #include "test/fuzz/fuzz_test_util.h"
  26. namespace spvtools {
  27. namespace fuzz {
  28. namespace {
  29. TEST(ReplayerTest, PartialReplay) {
  30. const std::string kTestShader = R"(
  31. OpCapability Shader
  32. %1 = OpExtInstImport "GLSL.std.450"
  33. OpMemoryModel Logical GLSL450
  34. OpEntryPoint Fragment %4 "main"
  35. OpExecutionMode %4 OriginUpperLeft
  36. OpSource ESSL 310
  37. OpName %4 "main"
  38. OpName %8 "g"
  39. OpName %11 "x"
  40. %2 = OpTypeVoid
  41. %3 = OpTypeFunction %2
  42. %6 = OpTypeInt 32 1
  43. %7 = OpTypePointer Private %6
  44. %8 = OpVariable %7 Private
  45. %9 = OpConstant %6 10
  46. %10 = OpTypePointer Function %6
  47. %4 = OpFunction %2 None %3
  48. %5 = OpLabel
  49. %11 = OpVariable %10 Function
  50. OpStore %8 %9
  51. %12 = OpLoad %6 %8
  52. OpStore %11 %12
  53. %13 = OpLoad %6 %8
  54. OpStore %11 %13
  55. %14 = OpLoad %6 %8
  56. OpStore %11 %14
  57. %15 = OpLoad %6 %8
  58. OpStore %11 %15
  59. %16 = OpLoad %6 %8
  60. OpStore %11 %16
  61. %17 = OpLoad %6 %8
  62. OpStore %11 %17
  63. %18 = OpLoad %6 %8
  64. OpStore %11 %18
  65. %19 = OpLoad %6 %8
  66. OpStore %11 %19
  67. %20 = OpLoad %6 %8
  68. OpStore %11 %20
  69. %21 = OpLoad %6 %8
  70. OpStore %11 %21
  71. %22 = OpLoad %6 %8
  72. OpStore %11 %22
  73. OpReturn
  74. OpFunctionEnd
  75. )";
  76. const auto env = SPV_ENV_UNIVERSAL_1_3;
  77. spvtools::ValidatorOptions validator_options;
  78. std::vector<uint32_t> binary_in;
  79. SpirvTools t(env);
  80. t.SetMessageConsumer(kConsoleMessageConsumer);
  81. ASSERT_TRUE(t.Assemble(kTestShader, &binary_in, kFuzzAssembleOption));
  82. ASSERT_TRUE(t.Validate(binary_in));
  83. protobufs::TransformationSequence transformations;
  84. for (uint32_t id = 12; id <= 22; id++) {
  85. *transformations.add_transformation() =
  86. TransformationSplitBlock(
  87. MakeInstructionDescriptor(id, spv::Op::OpLoad, 0), id + 100)
  88. .ToMessage();
  89. }
  90. {
  91. // Full replay
  92. protobufs::FactSequence empty_facts;
  93. auto replayer_result =
  94. Replayer(env, kConsoleMessageConsumer, binary_in, empty_facts,
  95. transformations, 11, true, validator_options)
  96. .Run();
  97. // Replay should succeed.
  98. ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete,
  99. replayer_result.status);
  100. // All transformations should be applied.
  101. ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
  102. transformations, replayer_result.applied_transformations));
  103. const std::string kFullySplitShader = R"(
  104. OpCapability Shader
  105. %1 = OpExtInstImport "GLSL.std.450"
  106. OpMemoryModel Logical GLSL450
  107. OpEntryPoint Fragment %4 "main"
  108. OpExecutionMode %4 OriginUpperLeft
  109. OpSource ESSL 310
  110. OpName %4 "main"
  111. OpName %8 "g"
  112. OpName %11 "x"
  113. %2 = OpTypeVoid
  114. %3 = OpTypeFunction %2
  115. %6 = OpTypeInt 32 1
  116. %7 = OpTypePointer Private %6
  117. %8 = OpVariable %7 Private
  118. %9 = OpConstant %6 10
  119. %10 = OpTypePointer Function %6
  120. %4 = OpFunction %2 None %3
  121. %5 = OpLabel
  122. %11 = OpVariable %10 Function
  123. OpStore %8 %9
  124. OpBranch %112
  125. %112 = OpLabel
  126. %12 = OpLoad %6 %8
  127. OpStore %11 %12
  128. OpBranch %113
  129. %113 = OpLabel
  130. %13 = OpLoad %6 %8
  131. OpStore %11 %13
  132. OpBranch %114
  133. %114 = OpLabel
  134. %14 = OpLoad %6 %8
  135. OpStore %11 %14
  136. OpBranch %115
  137. %115 = OpLabel
  138. %15 = OpLoad %6 %8
  139. OpStore %11 %15
  140. OpBranch %116
  141. %116 = OpLabel
  142. %16 = OpLoad %6 %8
  143. OpStore %11 %16
  144. OpBranch %117
  145. %117 = OpLabel
  146. %17 = OpLoad %6 %8
  147. OpStore %11 %17
  148. OpBranch %118
  149. %118 = OpLabel
  150. %18 = OpLoad %6 %8
  151. OpStore %11 %18
  152. OpBranch %119
  153. %119 = OpLabel
  154. %19 = OpLoad %6 %8
  155. OpStore %11 %19
  156. OpBranch %120
  157. %120 = OpLabel
  158. %20 = OpLoad %6 %8
  159. OpStore %11 %20
  160. OpBranch %121
  161. %121 = OpLabel
  162. %21 = OpLoad %6 %8
  163. OpStore %11 %21
  164. OpBranch %122
  165. %122 = OpLabel
  166. %22 = OpLoad %6 %8
  167. OpStore %11 %22
  168. OpReturn
  169. OpFunctionEnd
  170. )";
  171. ASSERT_TRUE(IsEqual(env, kFullySplitShader,
  172. replayer_result.transformed_module.get()));
  173. }
  174. {
  175. // Half replay
  176. protobufs::FactSequence empty_facts;
  177. auto replayer_result =
  178. Replayer(env, kConsoleMessageConsumer, binary_in, empty_facts,
  179. transformations, 5, true, validator_options)
  180. .Run();
  181. // Replay should succeed.
  182. ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete,
  183. replayer_result.status);
  184. // The first 5 transformations should be applied
  185. ASSERT_EQ(5, replayer_result.applied_transformations.transformation_size());
  186. for (uint32_t i = 0; i < 5; i++) {
  187. ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
  188. transformations.transformation(i),
  189. replayer_result.applied_transformations.transformation(i)));
  190. }
  191. const std::string kHalfSplitShader = R"(
  192. OpCapability Shader
  193. %1 = OpExtInstImport "GLSL.std.450"
  194. OpMemoryModel Logical GLSL450
  195. OpEntryPoint Fragment %4 "main"
  196. OpExecutionMode %4 OriginUpperLeft
  197. OpSource ESSL 310
  198. OpName %4 "main"
  199. OpName %8 "g"
  200. OpName %11 "x"
  201. %2 = OpTypeVoid
  202. %3 = OpTypeFunction %2
  203. %6 = OpTypeInt 32 1
  204. %7 = OpTypePointer Private %6
  205. %8 = OpVariable %7 Private
  206. %9 = OpConstant %6 10
  207. %10 = OpTypePointer Function %6
  208. %4 = OpFunction %2 None %3
  209. %5 = OpLabel
  210. %11 = OpVariable %10 Function
  211. OpStore %8 %9
  212. OpBranch %112
  213. %112 = OpLabel
  214. %12 = OpLoad %6 %8
  215. OpStore %11 %12
  216. OpBranch %113
  217. %113 = OpLabel
  218. %13 = OpLoad %6 %8
  219. OpStore %11 %13
  220. OpBranch %114
  221. %114 = OpLabel
  222. %14 = OpLoad %6 %8
  223. OpStore %11 %14
  224. OpBranch %115
  225. %115 = OpLabel
  226. %15 = OpLoad %6 %8
  227. OpStore %11 %15
  228. OpBranch %116
  229. %116 = OpLabel
  230. %16 = OpLoad %6 %8
  231. OpStore %11 %16
  232. %17 = OpLoad %6 %8
  233. OpStore %11 %17
  234. %18 = OpLoad %6 %8
  235. OpStore %11 %18
  236. %19 = OpLoad %6 %8
  237. OpStore %11 %19
  238. %20 = OpLoad %6 %8
  239. OpStore %11 %20
  240. %21 = OpLoad %6 %8
  241. OpStore %11 %21
  242. %22 = OpLoad %6 %8
  243. OpStore %11 %22
  244. OpReturn
  245. OpFunctionEnd
  246. )";
  247. ASSERT_TRUE(IsEqual(env, kHalfSplitShader,
  248. replayer_result.transformed_module.get()));
  249. }
  250. {
  251. // Empty replay
  252. protobufs::FactSequence empty_facts;
  253. auto replayer_result =
  254. Replayer(env, kConsoleMessageConsumer, binary_in, empty_facts,
  255. transformations, 0, true, validator_options)
  256. .Run();
  257. // Replay should succeed.
  258. ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete,
  259. replayer_result.status);
  260. // No transformations should be applied
  261. ASSERT_EQ(0, replayer_result.applied_transformations.transformation_size());
  262. ASSERT_TRUE(
  263. IsEqual(env, kTestShader, replayer_result.transformed_module.get()));
  264. }
  265. {
  266. // Invalid replay: too many transformations
  267. protobufs::FactSequence empty_facts;
  268. // The number of transformations requested to be applied exceeds the number
  269. // of transformations
  270. auto replayer_result =
  271. Replayer(env, kConsoleMessageConsumer, binary_in, empty_facts,
  272. transformations, 12, true, validator_options)
  273. .Run();
  274. // Replay should not succeed.
  275. ASSERT_EQ(Replayer::ReplayerResultStatus::kTooManyTransformationsRequested,
  276. replayer_result.status);
  277. // No transformations should be applied
  278. ASSERT_EQ(0, replayer_result.applied_transformations.transformation_size());
  279. // The output binary should be empty
  280. ASSERT_EQ(nullptr, replayer_result.transformed_module);
  281. }
  282. }
  283. TEST(ReplayerTest, CheckFactsAfterReplay) {
  284. const std::string kTestShader = R"(
  285. OpCapability Shader
  286. %1 = OpExtInstImport "GLSL.std.450"
  287. OpMemoryModel Logical GLSL450
  288. OpEntryPoint Fragment %4 "main"
  289. OpExecutionMode %4 OriginUpperLeft
  290. OpSource ESSL 320
  291. %2 = OpTypeVoid
  292. %3 = OpTypeFunction %2
  293. %8 = OpTypeInt 32 1
  294. %9 = OpTypePointer Function %8
  295. %50 = OpTypePointer Private %8
  296. %11 = OpConstant %8 1
  297. %4 = OpFunction %2 None %3
  298. %5 = OpLabel
  299. %10 = OpVariable %9 Function
  300. OpStore %10 %11
  301. %12 = OpFunctionCall %2 %6
  302. OpReturn
  303. OpFunctionEnd
  304. %6 = OpFunction %2 None %3
  305. %7 = OpLabel
  306. OpReturn
  307. OpFunctionEnd
  308. )";
  309. const auto env = SPV_ENV_UNIVERSAL_1_3;
  310. spvtools::ValidatorOptions validator_options;
  311. std::vector<uint32_t> binary_in;
  312. SpirvTools t(env);
  313. t.SetMessageConsumer(kConsoleMessageConsumer);
  314. ASSERT_TRUE(t.Assemble(kTestShader, &binary_in, kFuzzAssembleOption));
  315. ASSERT_TRUE(t.Validate(binary_in));
  316. protobufs::TransformationSequence transformations;
  317. *transformations.add_transformation() =
  318. TransformationAddConstantScalar(100, 8, {42}, true).ToMessage();
  319. *transformations.add_transformation() =
  320. TransformationAddGlobalVariable(101, 50, spv::StorageClass::Private, 100,
  321. true)
  322. .ToMessage();
  323. *transformations.add_transformation() =
  324. TransformationAddParameter(6, 102, 8, {{12, 100}}, 103).ToMessage();
  325. *transformations.add_transformation() =
  326. TransformationAddSynonym(
  327. 11,
  328. protobufs::TransformationAddSynonym::SynonymType::
  329. TransformationAddSynonym_SynonymType_COPY_OBJECT,
  330. 104, MakeInstructionDescriptor(12, spv::Op::OpFunctionCall, 0))
  331. .ToMessage();
  332. // Full replay
  333. protobufs::FactSequence empty_facts;
  334. auto replayer_result =
  335. Replayer(env, kConsoleMessageConsumer, binary_in, empty_facts,
  336. transformations, transformations.transformation_size(), true,
  337. validator_options)
  338. .Run();
  339. // Replay should succeed.
  340. ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete, replayer_result.status);
  341. // All transformations should be applied.
  342. ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
  343. transformations, replayer_result.applied_transformations));
  344. const std::string kExpected = R"(
  345. OpCapability Shader
  346. %1 = OpExtInstImport "GLSL.std.450"
  347. OpMemoryModel Logical GLSL450
  348. OpEntryPoint Fragment %4 "main"
  349. OpExecutionMode %4 OriginUpperLeft
  350. OpSource ESSL 320
  351. %2 = OpTypeVoid
  352. %3 = OpTypeFunction %2
  353. %8 = OpTypeInt 32 1
  354. %9 = OpTypePointer Function %8
  355. %50 = OpTypePointer Private %8
  356. %11 = OpConstant %8 1
  357. %100 = OpConstant %8 42
  358. %101 = OpVariable %50 Private %100
  359. %103 = OpTypeFunction %2 %8
  360. %4 = OpFunction %2 None %3
  361. %5 = OpLabel
  362. %10 = OpVariable %9 Function
  363. OpStore %10 %11
  364. %104 = OpCopyObject %8 %11
  365. %12 = OpFunctionCall %2 %6 %100
  366. OpReturn
  367. OpFunctionEnd
  368. %6 = OpFunction %2 None %103
  369. %102 = OpFunctionParameter %8
  370. %7 = OpLabel
  371. OpReturn
  372. OpFunctionEnd
  373. )";
  374. ASSERT_TRUE(
  375. IsEqual(env, kExpected, replayer_result.transformed_module.get()));
  376. ASSERT_TRUE(
  377. replayer_result.transformation_context->GetFactManager()->IdIsIrrelevant(
  378. 100));
  379. ASSERT_TRUE(replayer_result.transformation_context->GetFactManager()
  380. ->PointeeValueIsIrrelevant(101));
  381. ASSERT_TRUE(
  382. replayer_result.transformation_context->GetFactManager()->IdIsIrrelevant(
  383. 102));
  384. ASSERT_TRUE(
  385. replayer_result.transformation_context->GetFactManager()->IsSynonymous(
  386. MakeDataDescriptor(11, {}), MakeDataDescriptor(104, {})));
  387. }
  388. TEST(ReplayerTest, ReplayWithOverflowIds) {
  389. const std::string kTestShader = R"(
  390. OpCapability Shader
  391. %1 = OpExtInstImport "GLSL.std.450"
  392. OpMemoryModel Logical GLSL450
  393. OpEntryPoint Fragment %4 "main"
  394. OpExecutionMode %4 OriginUpperLeft
  395. OpSource ESSL 320
  396. %2 = OpTypeVoid
  397. %3 = OpTypeFunction %2
  398. %6 = OpTypeInt 32 1
  399. %7 = OpTypePointer Function %6
  400. %50 = OpTypePointer Private %6
  401. %9 = OpConstant %6 2
  402. %11 = OpConstant %6 0
  403. %12 = OpTypeBool
  404. %17 = OpConstant %6 1
  405. %4 = OpFunction %2 None %3
  406. %5 = OpLabel
  407. %8 = OpVariable %7 Function
  408. OpStore %8 %9
  409. %10 = OpLoad %6 %8
  410. %13 = OpSGreaterThan %12 %10 %11
  411. OpSelectionMerge %15 None
  412. OpBranchConditional %13 %14 %15
  413. %14 = OpLabel
  414. %16 = OpLoad %6 %8
  415. %18 = OpIAdd %6 %16 %17
  416. OpStore %8 %18
  417. OpBranch %15
  418. %15 = OpLabel
  419. OpReturn
  420. OpFunctionEnd
  421. )";
  422. const auto env = SPV_ENV_UNIVERSAL_1_3;
  423. spvtools::ValidatorOptions validator_options;
  424. std::vector<uint32_t> binary_in;
  425. SpirvTools t(env);
  426. t.SetMessageConsumer(kConsoleMessageConsumer);
  427. ASSERT_TRUE(t.Assemble(kTestShader, &binary_in, kFuzzAssembleOption));
  428. ASSERT_TRUE(t.Validate(binary_in));
  429. protobufs::TransformationSequence transformations;
  430. *transformations.add_transformation() =
  431. TransformationFlattenConditionalBranch(5, true, 0, 0, 0, {}).ToMessage();
  432. *transformations.add_transformation() =
  433. TransformationAddGlobalVariable(101, 50, spv::StorageClass::Private, 11,
  434. true)
  435. .ToMessage();
  436. protobufs::FactSequence empty_facts;
  437. auto replayer_result =
  438. Replayer(env, kConsoleMessageConsumer, binary_in, empty_facts,
  439. transformations, transformations.transformation_size(), true,
  440. validator_options)
  441. .Run();
  442. // Replay should succeed.
  443. ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete, replayer_result.status);
  444. // All transformations should be applied.
  445. ASSERT_EQ(2, replayer_result.applied_transformations.transformation_size());
  446. }
  447. } // namespace
  448. } // namespace fuzz
  449. } // namespace spvtools