• 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 struct TranslatorCacheKey
23 {
operator ==TranslatorCacheKey24     bool operator==(const TranslatorCacheKey &other) const
25     {
26         return type == other.type && spec == other.spec && output == other.output;
27     }
28 
29     uint32_t type   = 0;
30     uint32_t spec   = 0;
31     uint32_t output = 0;
32 };
33 
34 namespace std
35 {
36 
37 template <>
38 struct hash<TranslatorCacheKey>
39 {
operator ()std::hash40     std::size_t operator()(const TranslatorCacheKey &k) const
41     {
42         return (hash<uint32_t>()(k.type) << 1) ^ (hash<uint32_t>()(k.spec) >> 1) ^
43                hash<uint32_t>()(k.output);
44     }
45 };
46 }  // namespace std
47 
48 struct TCompilerDeleter
49 {
operator ()TCompilerDeleter50     void operator()(TCompiler *compiler) const { DeleteCompiler(compiler); }
51 };
52 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)53 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
54 {
55     // Reserve some size for future compile options
56     const size_t kHeaderSize = 128;
57 
58     if (size <= kHeaderSize)
59     {
60         return 0;
61     }
62 
63     // Make sure the rest of data will be a valid C string so that we don't have to copy it.
64     if (data[size - 1] != 0)
65     {
66         return 0;
67     }
68 
69     uint32_t type    = *reinterpret_cast<const uint32_t *>(data);
70     uint32_t spec    = *reinterpret_cast<const uint32_t *>(data + 4);
71     uint32_t output  = *reinterpret_cast<const uint32_t *>(data + 8);
72     uint64_t options = *reinterpret_cast<const uint64_t *>(data + 12);
73 
74     if (type != GL_FRAGMENT_SHADER && type != GL_VERTEX_SHADER)
75     {
76         return 0;
77     }
78 
79     if (spec != SH_GLES2_SPEC && type != SH_WEBGL_SPEC && spec != SH_GLES3_SPEC &&
80         spec != SH_WEBGL2_SPEC)
81     {
82         return 0;
83     }
84 
85     ShShaderOutput shaderOutput = static_cast<ShShaderOutput>(output);
86     if (!(IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput)) &&
87         (options & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u)
88     {
89         // This compiler option is only available in ESSL and GLSL.
90         return 0;
91     }
92 
93     std::vector<uint32_t> validOutputs;
94     validOutputs.push_back(SH_ESSL_OUTPUT);
95     validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT);
96     validOutputs.push_back(SH_GLSL_130_OUTPUT);
97     validOutputs.push_back(SH_GLSL_140_OUTPUT);
98     validOutputs.push_back(SH_GLSL_150_CORE_OUTPUT);
99     validOutputs.push_back(SH_GLSL_330_CORE_OUTPUT);
100     validOutputs.push_back(SH_GLSL_400_CORE_OUTPUT);
101     validOutputs.push_back(SH_GLSL_410_CORE_OUTPUT);
102     validOutputs.push_back(SH_GLSL_420_CORE_OUTPUT);
103     validOutputs.push_back(SH_GLSL_430_CORE_OUTPUT);
104     validOutputs.push_back(SH_GLSL_440_CORE_OUTPUT);
105     validOutputs.push_back(SH_GLSL_450_CORE_OUTPUT);
106     validOutputs.push_back(SH_HLSL_3_0_OUTPUT);
107     validOutputs.push_back(SH_HLSL_4_1_OUTPUT);
108     validOutputs.push_back(SH_HLSL_4_0_FL9_3_OUTPUT);
109     bool found = false;
110     for (auto valid : validOutputs)
111     {
112         found = found || (valid == output);
113     }
114     if (!found)
115     {
116         return 0;
117     }
118 
119     size -= kHeaderSize;
120     data += kHeaderSize;
121 
122     if (!sh::Initialize())
123     {
124         return 0;
125     }
126 
127     TranslatorCacheKey key;
128     key.type   = type;
129     key.spec   = spec;
130     key.output = output;
131 
132     using UniqueTCompiler = std::unique_ptr<TCompiler, TCompilerDeleter>;
133     static angle::base::NoDestructor<std::unordered_map<TranslatorCacheKey, UniqueTCompiler>>
134         translators;
135 
136     if (translators->find(key) == translators->end())
137     {
138         UniqueTCompiler translator(
139             ConstructCompiler(type, static_cast<ShShaderSpec>(spec), shaderOutput));
140 
141         if (translator == nullptr)
142         {
143             return 0;
144         }
145 
146         ShBuiltInResources resources;
147         sh::InitBuiltInResources(&resources);
148 
149         // Enable all the extensions to have more coverage
150         resources.OES_standard_derivatives        = 1;
151         resources.OES_EGL_image_external          = 1;
152         resources.OES_EGL_image_external_essl3    = 1;
153         resources.NV_EGL_stream_consumer_external = 1;
154         resources.ARB_texture_rectangle           = 1;
155         resources.EXT_blend_func_extended         = 1;
156         resources.EXT_draw_buffers                = 1;
157         resources.EXT_frag_depth                  = 1;
158         resources.EXT_shader_texture_lod          = 1;
159         resources.WEBGL_debug_shader_precision    = 1;
160         resources.EXT_shader_framebuffer_fetch    = 1;
161         resources.NV_shader_framebuffer_fetch     = 1;
162         resources.ARM_shader_framebuffer_fetch    = 1;
163         resources.EXT_YUV_target                  = 1;
164         resources.APPLE_clip_distance             = 1;
165         resources.MaxDualSourceDrawBuffers        = 1;
166         resources.EXT_gpu_shader5                 = 1;
167         resources.MaxClipDistances                = 1;
168 
169         if (!translator->Init(resources))
170         {
171             return 0;
172         }
173 
174         (*translators)[key] = std::move(translator);
175     }
176 
177     auto &translator = (*translators)[key];
178 
179     const char *shaderStrings[] = {reinterpret_cast<const char *>(data)};
180     translator->compile(shaderStrings, 1, options);
181 
182     return 0;
183 }
184