transformation_function_call_test.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  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/transformation_function_call.h"
  15. #include "gtest/gtest.h"
  16. #include "source/fuzz/fuzzer_util.h"
  17. #include "source/fuzz/instruction_descriptor.h"
  18. #include "test/fuzz/fuzz_test_util.h"
  19. namespace spvtools {
  20. namespace fuzz {
  21. namespace {
  22. TEST(TransformationFunctionCallTest, BasicTest) {
  23. std::string shader = R"(
  24. OpCapability Shader
  25. %1 = OpExtInstImport "GLSL.std.450"
  26. OpMemoryModel Logical GLSL450
  27. OpEntryPoint Fragment %4 "main"
  28. OpExecutionMode %4 OriginUpperLeft
  29. OpSource ESSL 310
  30. %2 = OpTypeVoid
  31. %3 = OpTypeFunction %2
  32. %6 = OpTypeInt 32 1
  33. %7 = OpTypePointer Function %6
  34. %8 = OpTypeFunction %6 %7
  35. %12 = OpTypeFloat 32
  36. %13 = OpTypePointer Function %12
  37. %14 = OpTypeFunction %6 %7 %13
  38. %27 = OpConstant %6 1
  39. %50 = OpConstant %12 1
  40. %57 = OpTypeBool
  41. %58 = OpConstantFalse %57
  42. %204 = OpUndef %6
  43. %4 = OpFunction %2 None %3
  44. %5 = OpLabel
  45. %61 = OpVariable %7 Function
  46. %62 = OpVariable %7 Function
  47. %65 = OpVariable %13 Function
  48. %66 = OpVariable %7 Function
  49. %68 = OpVariable %13 Function
  50. %71 = OpVariable %7 Function
  51. %72 = OpVariable %13 Function
  52. %73 = OpVariable %7 Function
  53. %75 = OpVariable %13 Function
  54. %78 = OpVariable %7 Function
  55. %98 = OpAccessChain %7 %71
  56. %99 = OpCopyObject %7 %71
  57. OpSelectionMerge %60 None
  58. OpBranchConditional %58 %59 %60
  59. %59 = OpLabel
  60. OpBranch %60
  61. %60 = OpLabel
  62. OpReturn
  63. OpFunctionEnd
  64. %10 = OpFunction %6 None %8
  65. %9 = OpFunctionParameter %7
  66. %11 = OpLabel
  67. %26 = OpLoad %6 %9
  68. %28 = OpIAdd %6 %26 %27
  69. OpSelectionMerge %97 None
  70. OpBranchConditional %58 %96 %97
  71. %96 = OpLabel
  72. OpBranch %97
  73. %97 = OpLabel
  74. OpReturnValue %28
  75. OpFunctionEnd
  76. %17 = OpFunction %6 None %14
  77. %15 = OpFunctionParameter %7
  78. %16 = OpFunctionParameter %13
  79. %18 = OpLabel
  80. %31 = OpVariable %7 Function
  81. %32 = OpLoad %6 %15
  82. OpStore %31 %32
  83. %33 = OpFunctionCall %6 %10 %31
  84. OpReturnValue %33
  85. OpFunctionEnd
  86. %21 = OpFunction %6 None %14
  87. %19 = OpFunctionParameter %7
  88. %20 = OpFunctionParameter %13
  89. %22 = OpLabel
  90. %36 = OpLoad %6 %19
  91. %37 = OpLoad %12 %20
  92. %38 = OpConvertFToS %6 %37
  93. %39 = OpIAdd %6 %36 %38
  94. OpReturnValue %39
  95. OpFunctionEnd
  96. %24 = OpFunction %6 None %8
  97. %23 = OpFunctionParameter %7
  98. %25 = OpLabel
  99. %44 = OpVariable %7 Function
  100. %46 = OpVariable %13 Function
  101. %51 = OpVariable %7 Function
  102. %52 = OpVariable %13 Function
  103. %42 = OpLoad %6 %23
  104. %43 = OpConvertSToF %12 %42
  105. %45 = OpLoad %6 %23
  106. OpStore %44 %45
  107. OpStore %46 %43
  108. %47 = OpFunctionCall %6 %17 %44 %46
  109. %48 = OpLoad %6 %23
  110. %49 = OpIAdd %6 %48 %27
  111. OpStore %51 %49
  112. OpStore %52 %50
  113. %53 = OpFunctionCall %6 %17 %51 %52
  114. %54 = OpIAdd %6 %47 %53
  115. OpReturnValue %54
  116. OpFunctionEnd
  117. %200 = OpFunction %6 None %14
  118. %201 = OpFunctionParameter %7
  119. %202 = OpFunctionParameter %13
  120. %203 = OpLabel
  121. OpSelectionMerge %206 None
  122. OpBranchConditional %58 %205 %206
  123. %205 = OpLabel
  124. OpBranch %206
  125. %206 = OpLabel
  126. OpReturnValue %204
  127. OpFunctionEnd
  128. )";
  129. const auto env = SPV_ENV_UNIVERSAL_1_4;
  130. const auto consumer = nullptr;
  131. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  132. spvtools::ValidatorOptions validator_options;
  133. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  134. kConsoleMessageConsumer));
  135. TransformationContext transformation_context(
  136. MakeUnique<FactManager>(context.get()), validator_options);
  137. transformation_context.GetFactManager()->AddFactBlockIsDead(59);
  138. transformation_context.GetFactManager()->AddFactBlockIsDead(11);
  139. transformation_context.GetFactManager()->AddFactBlockIsDead(18);
  140. transformation_context.GetFactManager()->AddFactBlockIsDead(25);
  141. transformation_context.GetFactManager()->AddFactBlockIsDead(96);
  142. transformation_context.GetFactManager()->AddFactBlockIsDead(205);
  143. transformation_context.GetFactManager()->AddFactFunctionIsLivesafe(21);
  144. transformation_context.GetFactManager()->AddFactFunctionIsLivesafe(200);
  145. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  146. 71);
  147. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  148. 72);
  149. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  150. 19);
  151. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  152. 20);
  153. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  154. 23);
  155. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  156. 44);
  157. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  158. 46);
  159. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  160. 51);
  161. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  162. 52);
  163. // Livesafe functions with argument types: 21(7, 13), 200(7, 13)
  164. // Non-livesafe functions with argument types: 4(), 10(7), 17(7, 13), 24(7)
  165. // Call graph edges:
  166. // 17 -> 10
  167. // 24 -> 17
  168. // Bad transformations
  169. // Too many arguments
  170. ASSERT_FALSE(TransformationFunctionCall(
  171. 100, 21, {71, 72, 71},
  172. MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  173. .IsApplicable(context.get(), transformation_context));
  174. // Too few arguments
  175. ASSERT_FALSE(
  176. TransformationFunctionCall(
  177. 100, 21, {71}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  178. .IsApplicable(context.get(), transformation_context));
  179. // Arguments are the wrong way around (types do not match)
  180. ASSERT_FALSE(TransformationFunctionCall(
  181. 100, 21, {72, 71},
  182. MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  183. .IsApplicable(context.get(), transformation_context));
  184. // 21 is not an appropriate argument
  185. ASSERT_FALSE(TransformationFunctionCall(
  186. 100, 21, {21, 72},
  187. MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  188. .IsApplicable(context.get(), transformation_context));
  189. // 300 does not exist
  190. ASSERT_FALSE(TransformationFunctionCall(
  191. 100, 21, {300, 72},
  192. MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  193. .IsApplicable(context.get(), transformation_context));
  194. // 71 is not a function
  195. ASSERT_FALSE(TransformationFunctionCall(
  196. 100, 71, {71, 72},
  197. MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  198. .IsApplicable(context.get(), transformation_context));
  199. // 500 does not exist
  200. ASSERT_FALSE(TransformationFunctionCall(
  201. 100, 500, {71, 72},
  202. MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  203. .IsApplicable(context.get(), transformation_context));
  204. // Id is not fresh
  205. ASSERT_FALSE(
  206. TransformationFunctionCall(
  207. 21, 21, {71, 72}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  208. .IsApplicable(context.get(), transformation_context));
  209. // Access chain as pointer parameter
  210. ASSERT_FALSE(TransformationFunctionCall(
  211. 100, 21, {98, 72},
  212. MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  213. .IsApplicable(context.get(), transformation_context));
  214. // Copied object as pointer parameter
  215. ASSERT_FALSE(TransformationFunctionCall(
  216. 100, 21, {99, 72},
  217. MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  218. .IsApplicable(context.get(), transformation_context));
  219. // Non-livesafe called from original live block
  220. ASSERT_FALSE(TransformationFunctionCall(
  221. 100, 10, {71},
  222. MakeInstructionDescriptor(99, spv::Op::OpSelectionMerge, 0))
  223. .IsApplicable(context.get(), transformation_context));
  224. // Non-livesafe called from livesafe function
  225. ASSERT_FALSE(TransformationFunctionCall(
  226. 100, 10, {19},
  227. MakeInstructionDescriptor(38, spv::Op::OpConvertFToS, 0))
  228. .IsApplicable(context.get(), transformation_context));
  229. // Livesafe function called with pointer to non-arbitrary local variable
  230. ASSERT_FALSE(TransformationFunctionCall(
  231. 100, 21, {61, 72},
  232. MakeInstructionDescriptor(38, spv::Op::OpConvertFToS, 0))
  233. .IsApplicable(context.get(), transformation_context));
  234. // Direct recursion
  235. ASSERT_FALSE(
  236. TransformationFunctionCall(
  237. 100, 4, {}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
  238. .IsApplicable(context.get(), transformation_context));
  239. // Indirect recursion
  240. ASSERT_FALSE(
  241. TransformationFunctionCall(
  242. 100, 24, {9}, MakeInstructionDescriptor(96, spv::Op::OpBranch, 0))
  243. .IsApplicable(context.get(), transformation_context));
  244. // Parameter 23 is not available at the call site
  245. ASSERT_FALSE(
  246. TransformationFunctionCall(
  247. 104, 10, {23}, MakeInstructionDescriptor(205, spv::Op::OpBranch, 0))
  248. .IsApplicable(context.get(), transformation_context));
  249. // Good transformations
  250. {
  251. // Livesafe called from dead block: fine
  252. TransformationFunctionCall transformation(
  253. 100, 21, {71, 72}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0));
  254. ASSERT_TRUE(
  255. transformation.IsApplicable(context.get(), transformation_context));
  256. ApplyAndCheckFreshIds(transformation, context.get(),
  257. &transformation_context);
  258. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  259. context.get(), validator_options, kConsoleMessageConsumer));
  260. }
  261. {
  262. // Livesafe called from original live block: fine
  263. TransformationFunctionCall transformation(
  264. 101, 21, {71, 72},
  265. MakeInstructionDescriptor(98, spv::Op::OpAccessChain, 0));
  266. ASSERT_TRUE(
  267. transformation.IsApplicable(context.get(), transformation_context));
  268. ApplyAndCheckFreshIds(transformation, context.get(),
  269. &transformation_context);
  270. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  271. context.get(), validator_options, kConsoleMessageConsumer));
  272. }
  273. {
  274. // Livesafe called from livesafe function: fine
  275. TransformationFunctionCall transformation(
  276. 102, 200, {19, 20}, MakeInstructionDescriptor(36, spv::Op::OpLoad, 0));
  277. ASSERT_TRUE(
  278. transformation.IsApplicable(context.get(), transformation_context));
  279. ApplyAndCheckFreshIds(transformation, context.get(),
  280. &transformation_context);
  281. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  282. context.get(), validator_options, kConsoleMessageConsumer));
  283. }
  284. {
  285. // Dead called from dead block in injected function: fine
  286. TransformationFunctionCall transformation(
  287. 103, 10, {23}, MakeInstructionDescriptor(45, spv::Op::OpLoad, 0));
  288. ASSERT_TRUE(
  289. transformation.IsApplicable(context.get(), transformation_context));
  290. ApplyAndCheckFreshIds(transformation, context.get(),
  291. &transformation_context);
  292. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  293. context.get(), validator_options, kConsoleMessageConsumer));
  294. }
  295. {
  296. // Non-livesafe called from dead block in livesafe function: OK
  297. TransformationFunctionCall transformation(
  298. 104, 10, {201}, MakeInstructionDescriptor(205, spv::Op::OpBranch, 0));
  299. ASSERT_TRUE(
  300. transformation.IsApplicable(context.get(), transformation_context));
  301. ApplyAndCheckFreshIds(transformation, context.get(),
  302. &transformation_context);
  303. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  304. context.get(), validator_options, kConsoleMessageConsumer));
  305. }
  306. {
  307. // Livesafe called from dead block with non-arbitrary parameter
  308. TransformationFunctionCall transformation(
  309. 105, 21, {62, 65}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0));
  310. ASSERT_TRUE(
  311. transformation.IsApplicable(context.get(), transformation_context));
  312. ApplyAndCheckFreshIds(transformation, context.get(),
  313. &transformation_context);
  314. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  315. context.get(), validator_options, kConsoleMessageConsumer));
  316. }
  317. std::string after_transformation = R"(
  318. OpCapability Shader
  319. %1 = OpExtInstImport "GLSL.std.450"
  320. OpMemoryModel Logical GLSL450
  321. OpEntryPoint Fragment %4 "main"
  322. OpExecutionMode %4 OriginUpperLeft
  323. OpSource ESSL 310
  324. %2 = OpTypeVoid
  325. %3 = OpTypeFunction %2
  326. %6 = OpTypeInt 32 1
  327. %7 = OpTypePointer Function %6
  328. %8 = OpTypeFunction %6 %7
  329. %12 = OpTypeFloat 32
  330. %13 = OpTypePointer Function %12
  331. %14 = OpTypeFunction %6 %7 %13
  332. %27 = OpConstant %6 1
  333. %50 = OpConstant %12 1
  334. %57 = OpTypeBool
  335. %58 = OpConstantFalse %57
  336. %204 = OpUndef %6
  337. %4 = OpFunction %2 None %3
  338. %5 = OpLabel
  339. %61 = OpVariable %7 Function
  340. %62 = OpVariable %7 Function
  341. %65 = OpVariable %13 Function
  342. %66 = OpVariable %7 Function
  343. %68 = OpVariable %13 Function
  344. %71 = OpVariable %7 Function
  345. %72 = OpVariable %13 Function
  346. %73 = OpVariable %7 Function
  347. %75 = OpVariable %13 Function
  348. %78 = OpVariable %7 Function
  349. %101 = OpFunctionCall %6 %21 %71 %72
  350. %98 = OpAccessChain %7 %71
  351. %99 = OpCopyObject %7 %71
  352. OpSelectionMerge %60 None
  353. OpBranchConditional %58 %59 %60
  354. %59 = OpLabel
  355. %100 = OpFunctionCall %6 %21 %71 %72
  356. %105 = OpFunctionCall %6 %21 %62 %65
  357. OpBranch %60
  358. %60 = OpLabel
  359. OpReturn
  360. OpFunctionEnd
  361. %10 = OpFunction %6 None %8
  362. %9 = OpFunctionParameter %7
  363. %11 = OpLabel
  364. %26 = OpLoad %6 %9
  365. %28 = OpIAdd %6 %26 %27
  366. OpSelectionMerge %97 None
  367. OpBranchConditional %58 %96 %97
  368. %96 = OpLabel
  369. OpBranch %97
  370. %97 = OpLabel
  371. OpReturnValue %28
  372. OpFunctionEnd
  373. %17 = OpFunction %6 None %14
  374. %15 = OpFunctionParameter %7
  375. %16 = OpFunctionParameter %13
  376. %18 = OpLabel
  377. %31 = OpVariable %7 Function
  378. %32 = OpLoad %6 %15
  379. OpStore %31 %32
  380. %33 = OpFunctionCall %6 %10 %31
  381. OpReturnValue %33
  382. OpFunctionEnd
  383. %21 = OpFunction %6 None %14
  384. %19 = OpFunctionParameter %7
  385. %20 = OpFunctionParameter %13
  386. %22 = OpLabel
  387. %102 = OpFunctionCall %6 %200 %19 %20
  388. %36 = OpLoad %6 %19
  389. %37 = OpLoad %12 %20
  390. %38 = OpConvertFToS %6 %37
  391. %39 = OpIAdd %6 %36 %38
  392. OpReturnValue %39
  393. OpFunctionEnd
  394. %24 = OpFunction %6 None %8
  395. %23 = OpFunctionParameter %7
  396. %25 = OpLabel
  397. %44 = OpVariable %7 Function
  398. %46 = OpVariable %13 Function
  399. %51 = OpVariable %7 Function
  400. %52 = OpVariable %13 Function
  401. %42 = OpLoad %6 %23
  402. %43 = OpConvertSToF %12 %42
  403. %103 = OpFunctionCall %6 %10 %23
  404. %45 = OpLoad %6 %23
  405. OpStore %44 %45
  406. OpStore %46 %43
  407. %47 = OpFunctionCall %6 %17 %44 %46
  408. %48 = OpLoad %6 %23
  409. %49 = OpIAdd %6 %48 %27
  410. OpStore %51 %49
  411. OpStore %52 %50
  412. %53 = OpFunctionCall %6 %17 %51 %52
  413. %54 = OpIAdd %6 %47 %53
  414. OpReturnValue %54
  415. OpFunctionEnd
  416. %200 = OpFunction %6 None %14
  417. %201 = OpFunctionParameter %7
  418. %202 = OpFunctionParameter %13
  419. %203 = OpLabel
  420. OpSelectionMerge %206 None
  421. OpBranchConditional %58 %205 %206
  422. %205 = OpLabel
  423. %104 = OpFunctionCall %6 %10 %201
  424. OpBranch %206
  425. %206 = OpLabel
  426. OpReturnValue %204
  427. OpFunctionEnd
  428. )";
  429. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  430. }
  431. TEST(TransformationFunctionCallTest, DoNotInvokeEntryPoint) {
  432. std::string shader = R"(
  433. OpCapability Shader
  434. %1 = OpExtInstImport "GLSL.std.450"
  435. OpMemoryModel Logical GLSL450
  436. OpEntryPoint Fragment %4 "main"
  437. OpExecutionMode %4 OriginUpperLeft
  438. OpSource ESSL 310
  439. %2 = OpTypeVoid
  440. %3 = OpTypeFunction %2
  441. %4 = OpFunction %2 None %3
  442. %5 = OpLabel
  443. OpReturn
  444. OpFunctionEnd
  445. %10 = OpFunction %2 None %3
  446. %11 = OpLabel
  447. OpReturn
  448. OpFunctionEnd
  449. )";
  450. const auto env = SPV_ENV_UNIVERSAL_1_4;
  451. const auto consumer = nullptr;
  452. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  453. spvtools::ValidatorOptions validator_options;
  454. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  455. kConsoleMessageConsumer));
  456. TransformationContext transformation_context(
  457. MakeUnique<FactManager>(context.get()), validator_options);
  458. transformation_context.GetFactManager()->AddFactBlockIsDead(11);
  459. // 4 is an entry point, so it is not legal for it to be the target of a call.
  460. ASSERT_FALSE(
  461. TransformationFunctionCall(
  462. 100, 4, {}, MakeInstructionDescriptor(11, spv::Op::OpReturn, 0))
  463. .IsApplicable(context.get(), transformation_context));
  464. }
  465. } // namespace
  466. } // namespace fuzz
  467. } // namespace spvtools