• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // translator_fuzzer.cpp: A libfuzzer fuzzer for the shader translator.
8 
9 #include <cstddef>
10 #include <cstdint>
11 #include <iostream>
12 #include <memory>
13 #include <unordered_map>
14 
15 #include "angle_gl.h"
16 #include "anglebase/no_destructor.h"
17 #include "compiler/translator/Compiler.h"
18 #include "compiler/translator/util.h"
19 
20 using namespace sh;
21 
22 namespace
23 {
24 struct TranslatorCacheKey
25 {
operator ==__anonf0820b9a0111::TranslatorCacheKey26     bool operator==(const TranslatorCacheKey &other) const
27     {
28         return type == other.type && spec == other.spec && output == other.output;
29     }
30 
31     uint32_t type   = 0;
32     uint32_t spec   = 0;
33     uint32_t output = 0;
34 };
35 }  // anonymous namespace
36 
37 namespace std
38 {
39 
40 template <>
41 struct hash<TranslatorCacheKey>
42 {
operator ()std::hash43     std::size_t operator()(const TranslatorCacheKey &k) const
44     {
45         return (hash<uint32_t>()(k.type) << 1) ^ (hash<uint32_t>()(k.spec) >> 1) ^
46                hash<uint32_t>()(k.output);
47     }
48 };
49 }  // namespace std
50 
51 struct TCompilerDeleter
52 {
operator ()TCompilerDeleter53     void operator()(TCompiler *compiler) const { DeleteCompiler(compiler); }
54 };
55 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)56 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
57 {
58     ShaderDumpHeader header{};
59     if (size <= sizeof(header))
60     {
61         return 0;
62     }
63 
64     // Make sure the rest of data will be a valid C string so that we don't have to copy it.
65     if (data[size - 1] != 0)
66     {
67         return 0;
68     }
69 
70     memcpy(&header, data, sizeof(header));
71     ShCompileOptions options{};
72     memcpy(&options, &header.basicCompileOptions, offsetof(ShCompileOptions, metal));
73     memcpy(&options.metal, &header.metalCompileOptions, sizeof(options.metal));
74     memcpy(&options.pls, &header.plsCompileOptions, sizeof(options.pls));
75     size -= sizeof(header);
76     data += sizeof(header);
77     uint32_t type = header.type;
78     uint32_t spec = header.spec;
79 
80     if (type != GL_FRAGMENT_SHADER && type != GL_VERTEX_SHADER)
81     {
82         return 0;
83     }
84 
85     if (spec != SH_GLES2_SPEC && type != SH_WEBGL_SPEC && spec != SH_GLES3_SPEC &&
86         spec != SH_WEBGL2_SPEC)
87     {
88         return 0;
89     }
90 
91     ShShaderOutput shaderOutput = static_cast<ShShaderOutput>(header.output);
92 
93     bool hasUnsupportedOptions = false;
94 
95     const bool hasMacGLSLOptions = options.rewriteFloatUnaryMinusOperator ||
96                                    options.addAndTrueToLoopCondition ||
97                                    options.rewriteDoWhileLoops || options.unfoldShortCircuit ||
98                                    options.rewriteRowMajorMatrices;
99 
100     if (!IsOutputGLSL(shaderOutput) && !IsOutputESSL(shaderOutput))
101     {
102         hasUnsupportedOptions =
103             hasUnsupportedOptions || options.emulateAtan2FloatFunction || options.clampFragDepth ||
104             options.regenerateStructNames || options.rewriteRepeatedAssignToSwizzled ||
105             options.useUnusedStandardSharedBlocks || options.selectViewInNvGLSLVertexShader;
106 
107         hasUnsupportedOptions = hasUnsupportedOptions || hasMacGLSLOptions;
108     }
109     else
110     {
111 #if !defined(ANGLE_PLATFORM_APPLE)
112         hasUnsupportedOptions = hasUnsupportedOptions || hasMacGLSLOptions;
113 #endif
114     }
115     if (!IsOutputSPIRV(shaderOutput))
116     {
117         hasUnsupportedOptions =
118             hasUnsupportedOptions || options.emulateSeamfulCubeMapSampling ||
119             options.useSpecializationConstant || options.addVulkanXfbEmulationSupportCode ||
120             options.roundOutputAfterDithering || options.addAdvancedBlendEquationsEmulation;
121     }
122     if (!IsOutputHLSL(shaderOutput))
123     {
124         hasUnsupportedOptions = hasUnsupportedOptions ||
125                                 options.expandSelectHLSLIntegerPowExpressions ||
126                                 options.allowTranslateUniformBlockToStructuredBuffer ||
127                                 options.rewriteIntegerUnaryMinusOperator;
128     }
129 
130     // If there are any options not supported with this output, don't attempt to run the translator.
131     if (hasUnsupportedOptions)
132     {
133         return 0;
134     }
135 
136     // Make sure the rest of the options are in a valid range.
137     options.pls.fragmentSyncType = static_cast<ShFragmentSynchronizationType>(
138         static_cast<uint32_t>(options.pls.fragmentSyncType) %
139         static_cast<uint32_t>(ShFragmentSynchronizationType::InvalidEnum));
140 
141     std::vector<uint32_t> validOutputs;
142     validOutputs.push_back(SH_ESSL_OUTPUT);
143     validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT);
144     validOutputs.push_back(SH_GLSL_130_OUTPUT);
145     validOutputs.push_back(SH_GLSL_140_OUTPUT);
146     validOutputs.push_back(SH_GLSL_150_CORE_OUTPUT);
147     validOutputs.push_back(SH_GLSL_330_CORE_OUTPUT);
148     validOutputs.push_back(SH_GLSL_400_CORE_OUTPUT);
149     validOutputs.push_back(SH_GLSL_410_CORE_OUTPUT);
150     validOutputs.push_back(SH_GLSL_420_CORE_OUTPUT);
151     validOutputs.push_back(SH_GLSL_430_CORE_OUTPUT);
152     validOutputs.push_back(SH_GLSL_440_CORE_OUTPUT);
153     validOutputs.push_back(SH_GLSL_450_CORE_OUTPUT);
154     validOutputs.push_back(SH_SPIRV_VULKAN_OUTPUT);
155     validOutputs.push_back(SH_HLSL_3_0_OUTPUT);
156     validOutputs.push_back(SH_HLSL_4_1_OUTPUT);
157     validOutputs.push_back(SH_HLSL_4_0_FL9_3_OUTPUT);
158     bool found = false;
159     for (auto valid : validOutputs)
160     {
161         found = found || (valid == shaderOutput);
162     }
163     if (!found)
164     {
165         return 0;
166     }
167 
168     if (!sh::Initialize())
169     {
170         return 0;
171     }
172 
173     TranslatorCacheKey key;
174     key.type   = type;
175     key.spec   = spec;
176     key.output = shaderOutput;
177 
178     using UniqueTCompiler = std::unique_ptr<TCompiler, TCompilerDeleter>;
179     static angle::base::NoDestructor<angle::HashMap<TranslatorCacheKey, UniqueTCompiler>>
180         translators;
181 
182     if (translators->find(key) == translators->end())
183     {
184         UniqueTCompiler translator(
185             ConstructCompiler(type, static_cast<ShShaderSpec>(spec), shaderOutput));
186 
187         if (translator == nullptr)
188         {
189             return 0;
190         }
191 
192         ShBuiltInResources resources;
193         sh::InitBuiltInResources(&resources);
194 
195         // Enable all the extensions to have more coverage
196         resources.OES_standard_derivatives        = 1;
197         resources.OES_EGL_image_external          = 1;
198         resources.OES_EGL_image_external_essl3    = 1;
199         resources.NV_EGL_stream_consumer_external = 1;
200         resources.ARB_texture_rectangle           = 1;
201         resources.EXT_blend_func_extended         = 1;
202         resources.EXT_conservative_depth          = 1;
203         resources.EXT_draw_buffers                = 1;
204         resources.EXT_frag_depth                  = 1;
205         resources.EXT_shader_texture_lod          = 1;
206         resources.EXT_shader_framebuffer_fetch    = 1;
207         resources.NV_shader_framebuffer_fetch     = 1;
208         resources.ARM_shader_framebuffer_fetch    = 1;
209         resources.EXT_YUV_target                  = 1;
210         resources.APPLE_clip_distance             = 1;
211         resources.MaxDualSourceDrawBuffers        = 1;
212         resources.EXT_gpu_shader5                 = 1;
213         resources.MaxClipDistances                = 1;
214         resources.EXT_shadow_samplers             = 1;
215         resources.EXT_clip_cull_distance          = 1;
216         resources.ANGLE_clip_cull_distance        = 1;
217         resources.EXT_primitive_bounding_box      = 1;
218         resources.OES_primitive_bounding_box      = 1;
219 
220         if (!translator->Init(resources))
221         {
222             return 0;
223         }
224 
225         (*translators)[key] = std::move(translator);
226     }
227 
228     auto &translator = (*translators)[key];
229 
230     options.limitExpressionComplexity = true;
231     const char *shaderStrings[]       = {reinterpret_cast<const char *>(data)};
232     translator->compile(shaderStrings, 1, options);
233 
234     return 0;
235 }
236