1 // Copyright 2017 The SwiftShader Authors. All Rights Reserved.
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
15 #include "OpenGL/compiler/InitializeGlobals.h"
16 #include "OpenGL/compiler/InitializeParseContext.h"
17 #include "OpenGL/compiler/TranslatorASM.h"
18
19 // TODO: Debug macros of the GLSL compiler clash with core SwiftShader's.
20 // They should not be exposed through the interface headers above.
21 #undef ASSERT
22 #undef UNIMPLEMENTED
23
24 #include "Renderer/VertexProcessor.hpp"
25 #include "Shader/VertexProgram.hpp"
26
27 #include <cstdint>
28 #include <memory>
29 #include <cassert>
30
31 namespace {
32
33 // TODO(cwallez@google.com): Like in ANGLE, disable most of the pool allocator for fuzzing
34 // This is a helper class to make sure all the resources used by the compiler are initialized
35 class ScopedPoolAllocatorAndTLS {
36 public:
ScopedPoolAllocatorAndTLS()37 ScopedPoolAllocatorAndTLS() {
38 InitializeParseContextIndex();
39 InitializePoolIndex();
40 SetGlobalPoolAllocator(&allocator);
41 }
~ScopedPoolAllocatorAndTLS()42 ~ScopedPoolAllocatorAndTLS() {
43 SetGlobalPoolAllocator(nullptr);
44 FreePoolIndex();
45 FreeParseContextIndex();
46 }
47
48 private:
49 TPoolAllocator allocator;
50 };
51
52 // Trivial implementation of the glsl::Shader interface that fakes being an API-level
53 // shader object.
54 class FakeVS : public glsl::Shader {
55 public:
FakeVS(sw::VertexShader * bytecode)56 FakeVS(sw::VertexShader* bytecode) : bytecode(bytecode) {
57 }
58
getShader() const59 sw::Shader *getShader() const override {
60 return bytecode;
61 }
getVertexShader() const62 sw::VertexShader *getVertexShader() const override {
63 return bytecode;
64 }
65
66 private:
67 sw::VertexShader* bytecode;
68 };
69
70 } // anonymous namespace
71
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)72 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
73 {
74 // Data layout:
75 //
76 // byte: boolean states
77 // {
78 // byte: stream type
79 // byte: stream count and normalized
80 // } [MAX_VERTEX_INPUTS]
81 // {
82 // byte[32]: reserved sampler state
83 // } [VERTEX_TEXTURE_IMAGE_UNITS]
84 //
85 // char source[] // null terminated
86 const size_t kHeaderSize = 1 + 2 * sw::MAX_VERTEX_INPUTS + 32 * sw::VERTEX_TEXTURE_IMAGE_UNITS;
87
88 if(size <= kHeaderSize)
89 {
90 return 0;
91 }
92
93 if(data[size - 1] != 0)
94 {
95 return 0;
96 }
97
98 std::unique_ptr<ScopedPoolAllocatorAndTLS> allocatorAndTLS(new ScopedPoolAllocatorAndTLS);
99 std::unique_ptr<sw::VertexShader> shader(new sw::VertexShader);
100 std::unique_ptr<FakeVS> fakeVS(new FakeVS(shader.get()));
101
102 std::unique_ptr<TranslatorASM> glslCompiler(new TranslatorASM(fakeVS.get(), GL_VERTEX_SHADER));
103
104 // TODO(cwallez@google.com): have a function to init to default values somewhere
105 ShBuiltInResources resources;
106 resources.MaxVertexAttribs = sw::MAX_VERTEX_INPUTS;
107 resources.MaxVertexUniformVectors = sw::VERTEX_UNIFORM_VECTORS - 3;
108 resources.MaxVaryingVectors = MIN(sw::MAX_VERTEX_OUTPUTS, sw::MAX_VERTEX_INPUTS);
109 resources.MaxVertexTextureImageUnits = sw::VERTEX_TEXTURE_IMAGE_UNITS;
110 resources.MaxCombinedTextureImageUnits = sw::TEXTURE_IMAGE_UNITS + sw::VERTEX_TEXTURE_IMAGE_UNITS;
111 resources.MaxTextureImageUnits = sw::TEXTURE_IMAGE_UNITS;
112 resources.MaxFragmentUniformVectors = sw::FRAGMENT_UNIFORM_VECTORS - 3;
113 resources.MaxDrawBuffers = sw::RENDERTARGETS;
114 resources.MaxVertexOutputVectors = 16; // ???
115 resources.MaxFragmentInputVectors = 15; // ???
116 resources.MinProgramTexelOffset = sw::MIN_PROGRAM_TEXEL_OFFSET;
117 resources.MaxProgramTexelOffset = sw::MAX_PROGRAM_TEXEL_OFFSET;
118 resources.OES_standard_derivatives = 1;
119 resources.OES_fragment_precision_high = 1;
120 resources.OES_EGL_image_external = 1;
121 resources.OES_EGL_image_external_essl3 = 1;
122 resources.EXT_draw_buffers = 1;
123 resources.ARB_texture_rectangle = 1;
124 resources.MaxCallStackDepth = 16;
125
126 glslCompiler->Init(resources);
127
128 const char* glslSource = reinterpret_cast<const char*>(data + kHeaderSize);
129 if (!glslCompiler->compile(&glslSource, 1, SH_OBJECT_CODE))
130 {
131 return 0;
132 }
133
134 std::unique_ptr<sw::VertexShader> bytecodeShader(new sw::VertexShader(fakeVS->getVertexShader()));
135
136 sw::VertexProcessor::State state;
137
138 state.textureSampling = bytecodeShader->containsTextureSampling();
139 state.positionRegister = bytecodeShader->getPositionRegister();
140 state.pointSizeRegister = bytecodeShader->getPointSizeRegister();
141
142 state.preTransformed = (data[0] & 0x01) != 0;
143 state.superSampling = (data[0] & 0x02) != 0;
144 state.multiSampling = (data[0] & 0x04) != 0;
145
146 state.transformFeedbackQueryEnabled = (data[0] & 0x08) != 0;
147 state.transformFeedbackEnabled = (data[0] & 0x10) != 0;
148 state.verticesPerPrimitive = 1 + ((data[0] & 0x20) != 0) + ((data[0] & 0x40) != 0);
149
150 if((data[0] & 0x80) != 0) // Unused/reserved.
151 {
152 return 0;
153 }
154
155 constexpr int MAX_ATTRIBUTE_COMPONENTS = 4;
156
157 struct Stream
158 {
159 uint8_t count : BITS(MAX_ATTRIBUTE_COMPONENTS);
160 bool normalized : 1;
161 uint8_t reserved : 8 - BITS(MAX_ATTRIBUTE_COMPONENTS) - 1;
162 };
163
164 for(int i = 0; i < sw::MAX_VERTEX_INPUTS; i++)
165 {
166 sw::StreamType type = (sw::StreamType)data[1 + 2 * i + 0];
167 Stream stream = (Stream&)data[1 + 2 * i + 1];
168
169 if(type > sw::STREAMTYPE_LAST) return 0;
170 if(stream.count > MAX_ATTRIBUTE_COMPONENTS) return 0;
171 if(stream.reserved != 0) return 0;
172
173 state.input[i].type = type;
174 state.input[i].count = stream.count;
175 state.input[i].normalized = stream.normalized;
176 state.input[i].attribType = bytecodeShader->getAttribType(i);
177 }
178
179 for(unsigned int i = 0; i < sw::VERTEX_TEXTURE_IMAGE_UNITS; i++)
180 {
181 // TODO
182 // if(bytecodeShader->usesSampler(i))
183 // {
184 // state.samplerState[i] = context->sampler[sw::TEXTURE_IMAGE_UNITS + i].samplerState();
185 // }
186
187 for(int j = 0; j < 32; j++)
188 {
189 if(data[1 + 2 * sw::MAX_VERTEX_INPUTS + 32 * i + j] != 0)
190 {
191 return 0;
192 }
193 }
194 }
195
196 for(int i = 0; i < sw::MAX_VERTEX_OUTPUTS; i++)
197 {
198 state.output[i].xWrite = bytecodeShader->getOutput(i, 0).active();
199 state.output[i].yWrite = bytecodeShader->getOutput(i, 1).active();
200 state.output[i].zWrite = bytecodeShader->getOutput(i, 2).active();
201 state.output[i].wWrite = bytecodeShader->getOutput(i, 3).active();
202 }
203
204 sw::VertexProgram program(state, bytecodeShader.get());
205 program.generate();
206
207 sw::Routine *routine = program("VertexRoutine");
208 assert(routine);
209 const void *entry = routine->getEntry();
210 assert(entry); (void)entry;
211 delete routine;
212
213 return 0;
214 }
215
216 #if defined(FUZZER_STANDALONE_REPRODUCE)
main(int argc,char * argv[])217 int main(int argc, char *argv[])
218 {
219 FILE *file = fopen("clusterfuzz-testcase", "r");
220
221 fseek(file, 0L, SEEK_END);
222 long numbytes = ftell(file);
223 fseek(file, 0L, SEEK_SET);
224 uint8_t *buffer = (uint8_t*)calloc(numbytes, sizeof(uint8_t));
225 fread(buffer, sizeof(char), numbytes, file);
226 fclose(file);
227
228 while(true)
229 {
230 LLVMFuzzerTestOneInput(buffer, numbytes);
231 }
232
233 free(buffer);
234
235 return 0;
236 }
237 #endif
238