Pārlūkot izejas kodu

gpu: fix a buffer overflow in our shader compilation wrapper.

undefined
Sam Hocevar pirms 11 gadiem
vecāks
revīzija
73891294fe
1 mainītis faili ar 56 papildinājumiem un 30 dzēšanām
  1. +56
    -30
      src/gpu/shader.cpp

+ 56
- 30
src/gpu/shader.cpp Parādīt failu

@@ -39,7 +39,25 @@ using namespace std;
namespace lol namespace lol
{ {


static const char* attribute_names[] = { struct ShaderType
{
enum Value
{
Vertex = 1,
Fragment,
Geometry,
TessControl,
TessEval,
}
m_value;

inline ShaderType(Value v) : m_value(v) {}
inline ShaderType(int v) : m_value((Value)v) {}
inline operator Value() { return m_value; }
};

static const char* attribute_names[] =
{
"in_Position", "in_Position",
"in_BlendWeight", "in_BlendWeight",
"in_BlendIndices", "in_BlendIndices",
@@ -87,7 +105,7 @@ private:


/* Shader patcher */ /* Shader patcher */
static int GetVersion(); static int GetVersion();
static void Patch(char *dst, char const *vert, char const *frag); static String Patch(String const &code, ShaderType type);


/* Global shader cache */ /* Global shader cache */
static Shader *shaders[]; static Shader *shaders[];
@@ -200,8 +218,9 @@ Shader::Shader(char const *vert, char const *frag)
{ nullptr, nullptr } { nullptr, nullptr }
}; };
#elif !defined __CELLOS_LV2__ #elif !defined __CELLOS_LV2__
char buf[4096], errbuf[4096]; char errbuf[4096];
char const *shader = buf; String shader_code;
GLchar const *gl_code;
GLint status; GLint status;
GLsizei len; GLsizei len;
#else #else
@@ -232,9 +251,10 @@ Shader::Shader(char const *vert, char const *frag)
&data->vert_shader); &data->vert_shader);
shader_code->Release(); shader_code->Release();
#elif !defined __CELLOS_LV2__ #elif !defined __CELLOS_LV2__
ShaderData::Patch(buf, vert, nullptr); shader_code = ShaderData::Patch(vert, ShaderType::Vertex);
data->vert_id = glCreateShader(GL_VERTEX_SHADER); data->vert_id = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(data->vert_id, 1, &shader, nullptr); gl_code = shader_code.C();
glShaderSource(data->vert_id, 1, &gl_code, nullptr);
glCompileShader(data->vert_id); glCompileShader(data->vert_id);


glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf); glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf);
@@ -242,12 +262,12 @@ Shader::Shader(char const *vert, char const *frag)
if (status != GL_TRUE) if (status != GL_TRUE)
{ {
Log::Error("failed to compile vertex shader: %s", errbuf); Log::Error("failed to compile vertex shader: %s", errbuf);
Log::Error("shader source:\n%s\n", buf); Log::Error("shader source:\n%s\n", shader_code.C());
} }
else if (len > 16) else if (len > 16)
{ {
Log::Debug("compile log for vertex shader: %s", errbuf); Log::Debug("compile log for vertex shader: %s", errbuf);
Log::Debug("shader source:\n%s\n", buf); Log::Debug("shader source:\n%s\n", shader_code.C());
} }
#else #else
data->vert_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, vert, data->vert_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, vert,
@@ -276,9 +296,10 @@ Shader::Shader(char const *vert, char const *frag)
&data->frag_shader); &data->frag_shader);
shader_code->Release(); shader_code->Release();
#elif !defined __CELLOS_LV2__ #elif !defined __CELLOS_LV2__
ShaderData::Patch(buf, nullptr, frag); shader_code = ShaderData::Patch(frag, ShaderType::Fragment);
data->frag_id = glCreateShader(GL_FRAGMENT_SHADER); data->frag_id = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(data->frag_id, 1, &shader, nullptr); gl_code = shader_code.C();
glShaderSource(data->frag_id, 1, &gl_code, nullptr);
glCompileShader(data->frag_id); glCompileShader(data->frag_id);


glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf); glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf);
@@ -286,12 +307,12 @@ Shader::Shader(char const *vert, char const *frag)
if (status != GL_TRUE) if (status != GL_TRUE)
{ {
Log::Error("failed to compile fragment shader: %s", errbuf); Log::Error("failed to compile fragment shader: %s", errbuf);
Log::Error("shader source:\n%s\n", buf); Log::Error("shader source:\n%s\n", shader_code.C());
} }
else if (len > 16) else if (len > 16)
{ {
Log::Debug("compile log for fragment shader: %s", errbuf); Log::Debug("compile log for fragment shader: %s", errbuf);
Log::Debug("shader source:\n%s\n", buf); Log::Debug("shader source:\n%s\n", shader_code.C());
} }
#else #else
data->frag_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, frag, data->frag_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, frag,
@@ -858,18 +879,19 @@ int ShaderData::GetVersion()
return version; return version;
} }


/* Simple shader source patching for old GLSL versions. /*
* Simple shader source patching for old GLSL versions.
*/ */
void ShaderData::Patch(char *dst, char const *vert, char const *frag) String ShaderData::Patch(String const &code, ShaderType type)
{ {
int ver_driver = GetVersion(); int ver_driver = GetVersion();


strcpy(dst, vert ? vert : frag); String patched_code = code;
if (ver_driver >= 130) if (ver_driver >= 130)
return; return patched_code;


int ver_shader = 110; int ver_shader = 110;
char *parser = strstr(dst, "#version"); char *parser = strstr(patched_code.C(), "#version");
if (parser) if (parser)
ver_shader = atoi(parser + strlen("#version")); ver_shader = atoi(parser + strlen("#version"));


@@ -878,7 +900,7 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag)
{ {
/* FIXME: this isn't elegant but honestly, we don't care, this /* FIXME: this isn't elegant but honestly, we don't care, this
* whole file is going to die soon. */ * whole file is going to die soon. */
char *p = strstr(dst, "#version"); char *p = strstr(patched_code.C(), "#version");
if (p) if (p)
{ {
p += 8; p += 8;
@@ -891,17 +913,17 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag)


if (ver_shader > 120 && ver_driver <= 120) if (ver_shader > 120 && ver_driver <= 120)
{ {
char const *end = dst + strlen(dst) + 1; char const *end = patched_code.C() + patched_code.Count() + 1;


/* Find main() */ /* Find main() */
parser = strstr(dst, "main"); parser = strstr(patched_code.C(), "main");
if (!parser) return; if (!parser) return patched_code;
parser = strstr(parser, "("); parser = strstr(parser, "(");
if (!parser) return; if (!parser) return patched_code;
parser = strstr(parser, ")"); parser = strstr(parser, ")");
if (!parser) return; if (!parser) return patched_code;
parser = strstr(parser, "{"); parser = strstr(parser, "{");
if (!parser) return; if (!parser) return patched_code;
char *main = parser + 1; char *main = parser + 1;


/* Perform main() replaces */ /* Perform main() replaces */
@@ -939,7 +961,7 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag)


for (char const * const *rep = main_replaces; rep[0]; rep += 2) for (char const * const *rep = main_replaces; rep[0]; rep += 2)
{ {
char *match = strstr(dst, rep[0]); char *match = strstr(patched_code.C(), rep[0]);
if (match && match < main) if (match && match < main)
{ {
size_t l0 = strlen(rep[0]); size_t l0 = strlen(rep[0]);
@@ -956,10 +978,10 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag)
char const * const fast_replaces[] = char const * const fast_replaces[] =
{ {
"#version 130", "#version 120", "#version 130", "#version 120",
"in vec2", vert ? "attribute vec2" : "varying vec2", "in vec2", type == ShaderType::Vertex ? "attribute vec2" : "varying vec2",
"in vec3", vert ? "attribute vec3" : "varying vec3", "in vec3", type == ShaderType::Vertex ? "attribute vec3" : "varying vec3",
"in vec4", vert ? "attribute vec4" : "varying vec4", "in vec4", type == ShaderType::Vertex ? "attribute vec4" : "varying vec4",
"in mat4", vert ? "attribute mat4" : "varying mat4", "in mat4", type == ShaderType::Vertex ? "attribute mat4" : "varying mat4",
"out vec2", "varying vec2", "out vec2", "varying vec2",
"out vec3", "varying vec3", "out vec3", "varying vec3",
"out vec4", "varying vec4", "out vec4", "varying vec4",
@@ -970,7 +992,7 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag)
for (char const * const *rep = fast_replaces; rep[0]; rep += 2) for (char const * const *rep = fast_replaces; rep[0]; rep += 2)
{ {
char *match; char *match;
while ((match = strstr(dst, rep[0]))) while ((match = strstr(patched_code.C(), rep[0])))
{ {
size_t l0 = strlen(rep[0]); size_t l0 = strlen(rep[0]);
size_t l1 = strlen(rep[1]); size_t l1 = strlen(rep[1]);
@@ -984,6 +1006,10 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag)
} }
} }
} }

patched_code.Resize(strlen(patched_code.C()));

return patched_code;
} }


} /* namespace lol */ } /* namespace lol */


||||||
x
 
000:0
Notiek ielāde…
Atcelt
Saglabāt