xref: /aosp_15_r20/external/angle/src/compiler/fuzz/translator_fuzzer.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 "common/hash_containers.h"
18 #include "compiler/translator/Compiler.h"
19 #include "compiler/translator/util.h"
20 
21 using namespace sh;
22 
23 namespace
24 {
25 struct TranslatorCacheKey
26 {
operator ==__anon9f0e5fbc0111::TranslatorCacheKey27     bool operator==(const TranslatorCacheKey &other) const
28     {
29         return type == other.type && spec == other.spec && output == other.output;
30     }
31 
32     uint32_t type   = 0;
33     uint32_t spec   = 0;
34     uint32_t output = 0;
35 };
36 }  // anonymous namespace
37 
38 namespace std
39 {
40 
41 template <>
42 struct hash<TranslatorCacheKey>
43 {
operator ()std::hash44     std::size_t operator()(const TranslatorCacheKey &k) const
45     {
46         return (hash<uint32_t>()(k.type) << 1) ^ (hash<uint32_t>()(k.spec) >> 1) ^
47                hash<uint32_t>()(k.output);
48     }
49 };
50 }  // namespace std
51 
52 struct TCompilerDeleter
53 {
operator ()TCompilerDeleter54     void operator()(TCompiler *compiler) const { DeleteCompiler(compiler); }
55 };
56 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)57 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
58 {
59     ShaderDumpHeader header{};
60     if (size <= sizeof(header))
61     {
62         return 0;
63     }
64 
65     // Make sure the rest of data will be a valid C string so that we don't have to copy it.
66     if (data[size - 1] != 0)
67     {
68         return 0;
69     }
70 
71     memcpy(&header, data, sizeof(header));
72     ShCompileOptions options{};
73     memcpy(&options, &header.basicCompileOptions, offsetof(ShCompileOptions, metal));
74     memcpy(&options.metal, &header.metalCompileOptions, sizeof(options.metal));
75     memcpy(&options.pls, &header.plsCompileOptions, sizeof(options.pls));
76     size -= sizeof(header);
77     data += sizeof(header);
78     uint32_t type = header.type;
79     uint32_t spec = header.spec;
80 
81     if (type != GL_FRAGMENT_SHADER && type != GL_VERTEX_SHADER)
82     {
83         return 0;
84     }
85 
86     if (spec != SH_GLES2_SPEC && type != SH_WEBGL_SPEC && spec != SH_GLES3_SPEC &&
87         spec != SH_WEBGL2_SPEC)
88     {
89         return 0;
90     }
91 
92     ShShaderOutput shaderOutput = static_cast<ShShaderOutput>(header.output);
93 
94     bool hasUnsupportedOptions = false;
95 
96     const bool hasMacGLSLOptions = options.rewriteFloatUnaryMinusOperator ||
97                                    options.addAndTrueToLoopCondition ||
98                                    options.rewriteDoWhileLoops || options.unfoldShortCircuit ||
99                                    options.rewriteRowMajorMatrices;
100 
101     if (!IsOutputGLSL(shaderOutput) && !IsOutputESSL(shaderOutput))
102     {
103         hasUnsupportedOptions =
104             hasUnsupportedOptions || options.emulateAtan2FloatFunction || options.clampFragDepth ||
105             options.regenerateStructNames || options.rewriteRepeatedAssignToSwizzled ||
106             options.useUnusedStandardSharedBlocks || options.selectViewInNvGLSLVertexShader;
107 
108         hasUnsupportedOptions = hasUnsupportedOptions || hasMacGLSLOptions;
109     }
110     else
111     {
112 #if !defined(ANGLE_PLATFORM_APPLE)
113         hasUnsupportedOptions = hasUnsupportedOptions || hasMacGLSLOptions;
114 #endif
115     }
116     if (!IsOutputSPIRV(shaderOutput))
117     {
118         hasUnsupportedOptions = hasUnsupportedOptions || options.useSpecializationConstant ||
119                                 options.addVulkanXfbEmulationSupportCode ||
120                                 options.roundOutputAfterDithering ||
121                                 options.addAdvancedBlendEquationsEmulation;
122     }
123     if (!IsOutputHLSL(shaderOutput))
124     {
125         hasUnsupportedOptions = hasUnsupportedOptions ||
126                                 options.expandSelectHLSLIntegerPowExpressions ||
127                                 options.allowTranslateUniformBlockToStructuredBuffer ||
128                                 options.rewriteIntegerUnaryMinusOperator;
129     }
130 
131     // If there are any options not supported with this output, don't attempt to run the translator.
132     if (hasUnsupportedOptions)
133     {
134         return 0;
135     }
136 
137     // Make sure the rest of the options are in a valid range.
138     options.pls.fragmentSyncType = static_cast<ShFragmentSynchronizationType>(
139         static_cast<uint32_t>(options.pls.fragmentSyncType) %
140         static_cast<uint32_t>(ShFragmentSynchronizationType::InvalidEnum));
141 
142     std::vector<uint32_t> validOutputs;
143     validOutputs.push_back(SH_ESSL_OUTPUT);
144     validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT);
145     validOutputs.push_back(SH_GLSL_130_OUTPUT);
146     validOutputs.push_back(SH_GLSL_140_OUTPUT);
147     validOutputs.push_back(SH_GLSL_150_CORE_OUTPUT);
148     validOutputs.push_back(SH_GLSL_330_CORE_OUTPUT);
149     validOutputs.push_back(SH_GLSL_400_CORE_OUTPUT);
150     validOutputs.push_back(SH_GLSL_410_CORE_OUTPUT);
151     validOutputs.push_back(SH_GLSL_420_CORE_OUTPUT);
152     validOutputs.push_back(SH_GLSL_430_CORE_OUTPUT);
153     validOutputs.push_back(SH_GLSL_440_CORE_OUTPUT);
154     validOutputs.push_back(SH_GLSL_450_CORE_OUTPUT);
155     validOutputs.push_back(SH_SPIRV_VULKAN_OUTPUT);
156     validOutputs.push_back(SH_HLSL_3_0_OUTPUT);
157     validOutputs.push_back(SH_HLSL_4_1_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.ARM_shader_framebuffer_fetch_depth_stencil = 1;
210         resources.EXT_YUV_target                  = 1;
211         resources.APPLE_clip_distance             = 1;
212         resources.MaxDualSourceDrawBuffers        = 1;
213         resources.EXT_gpu_shader5                 = 1;
214         resources.MaxClipDistances                = 1;
215         resources.EXT_shadow_samplers             = 1;
216         resources.EXT_clip_cull_distance          = 1;
217         resources.ANGLE_clip_cull_distance        = 1;
218         resources.EXT_primitive_bounding_box      = 1;
219         resources.OES_primitive_bounding_box      = 1;
220 
221         if (!translator->Init(resources))
222         {
223             return 0;
224         }
225 
226         (*translators)[key] = std::move(translator);
227     }
228 
229     auto &translator = (*translators)[key];
230 
231     options.limitExpressionComplexity = true;
232     const char *shaderStrings[]       = {reinterpret_cast<const char *>(data)};
233     translator->compile(shaderStrings, 1, options);
234 
235     return 0;
236 }
237