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.EXT_draw_buffers = 1;
122 resources.ARB_texture_rectangle = 1;
123 resources.MaxCallStackDepth = 16;
124
125 glslCompiler->Init(resources);
126
127 const char* glslSource = reinterpret_cast<const char*>(data + kHeaderSize);
128 if (!glslCompiler->compile(&glslSource, 1, SH_OBJECT_CODE))
129 {
130 return 0;
131 }
132
133 std::unique_ptr<sw::VertexShader> bytecodeShader(new sw::VertexShader(fakeVS->getVertexShader()));
134
135 sw::VertexProcessor::State state;
136
137 state.textureSampling = bytecodeShader->containsTextureSampling();
138 state.positionRegister = bytecodeShader->getPositionRegister();
139 state.pointSizeRegister = bytecodeShader->getPointSizeRegister();
140
141 state.preTransformed = (data[0] & 0x01) != 0;
142 state.superSampling = (data[0] & 0x02) != 0;
143 state.multiSampling = (data[0] & 0x04) != 0;
144
145 state.transformFeedbackQueryEnabled = (data[0] & 0x08) != 0;
146 state.transformFeedbackEnabled = (data[0] & 0x10) != 0;
147 state.verticesPerPrimitive = 1 + ((data[0] & 0x20) != 0) + ((data[0] & 0x40) != 0);
148
149 if((data[0] & 0x80) != 0) // Unused/reserved.
150 {
151 return 0;
152 }
153
154 constexpr int MAX_ATTRIBUTE_COMPONENTS = 4;
155
156 struct Stream
157 {
158 uint8_t count : BITS(MAX_ATTRIBUTE_COMPONENTS);
159 bool normalized : 1;
160 uint8_t reserved : 8 - BITS(MAX_ATTRIBUTE_COMPONENTS) - 1;
161 };
162
163 for(int i = 0; i < sw::MAX_VERTEX_INPUTS; i++)
164 {
165 sw::StreamType type = (sw::StreamType)data[1 + 2 * i + 0];
166 Stream stream = (Stream&)data[1 + 2 * i + 1];
167
168 if(type > sw::STREAMTYPE_LAST) return 0;
169 if(stream.count > MAX_ATTRIBUTE_COMPONENTS) return 0;
170 if(stream.reserved != 0) return 0;
171
172 state.input[i].type = type;
173 state.input[i].count = stream.count;
174 state.input[i].normalized = stream.normalized;
175 state.input[i].attribType = bytecodeShader->getAttribType(i);
176 }
177
178 for(unsigned int i = 0; i < sw::VERTEX_TEXTURE_IMAGE_UNITS; i++)
179 {
180 // TODO
181 // if(bytecodeShader->usesSampler(i))
182 // {
183 // state.samplerState[i] = context->sampler[sw::TEXTURE_IMAGE_UNITS + i].samplerState();
184 // }
185
186 for(int j = 0; j < 32; j++)
187 {
188 if(data[1 + 2 * sw::MAX_VERTEX_INPUTS + 32 * i + j] != 0)
189 {
190 return 0;
191 }
192 }
193 }
194
195 for(int i = 0; i < sw::MAX_VERTEX_OUTPUTS; i++)
196 {
197 state.output[i].xWrite = bytecodeShader->getOutput(i, 0).active();
198 state.output[i].yWrite = bytecodeShader->getOutput(i, 1).active();
199 state.output[i].zWrite = bytecodeShader->getOutput(i, 2).active();
200 state.output[i].wWrite = bytecodeShader->getOutput(i, 3).active();
201 }
202
203 sw::VertexProgram program(state, bytecodeShader.get());
204 program.generate();
205
206 sw::Routine *routine = program(L"VertexRoutine");
207 assert(routine);
208 const void *entry = routine->getEntry();
209 assert(entry); (void)entry;
210 delete routine;
211
212 return 0;
213 }
214