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