Sfoglia il codice sorgente

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

undefined
Sam Hocevar 11 anni fa
parent
commit
73891294fe
1 ha cambiato i file con 56 aggiunte e 30 eliminazioni
  1. +56
    -30
      src/gpu/shader.cpp

+ 56
- 30
src/gpu/shader.cpp Vedi File

@@ -39,7 +39,25 @@ using namespace std;
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_BlendWeight",
"in_BlendIndices",
@@ -87,7 +105,7 @@ private:

/* Shader patcher */
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 */
static Shader *shaders[];
@@ -200,8 +218,9 @@ Shader::Shader(char const *vert, char const *frag)
{ nullptr, nullptr }
};
#elif !defined __CELLOS_LV2__
char buf[4096], errbuf[4096];
char const *shader = buf;
char errbuf[4096];
String shader_code;
GLchar const *gl_code;
GLint status;
GLsizei len;
#else
@@ -232,9 +251,10 @@ Shader::Shader(char const *vert, char const *frag)
&data->vert_shader);
shader_code->Release();
#elif !defined __CELLOS_LV2__
ShaderData::Patch(buf, vert, nullptr);
shader_code = ShaderData::Patch(vert, ShaderType::Vertex);
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);

glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf);
@@ -242,12 +262,12 @@ Shader::Shader(char const *vert, char const *frag)
if (status != GL_TRUE)
{
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)
{
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
data->vert_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, vert,
@@ -276,9 +296,10 @@ Shader::Shader(char const *vert, char const *frag)
&data->frag_shader);
shader_code->Release();
#elif !defined __CELLOS_LV2__
ShaderData::Patch(buf, nullptr, frag);
shader_code = ShaderData::Patch(frag, ShaderType::Fragment);
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);

glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf);
@@ -286,12 +307,12 @@ Shader::Shader(char const *vert, char const *frag)
if (status != GL_TRUE)
{
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)
{
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
data->frag_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, frag,
@@ -858,18 +879,19 @@ int ShaderData::GetVersion()
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();

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

int ver_shader = 110;
char *parser = strstr(dst, "#version");
char *parser = strstr(patched_code.C(), "#version");
if (parser)
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
* whole file is going to die soon. */
char *p = strstr(dst, "#version");
char *p = strstr(patched_code.C(), "#version");
if (p)
{
p += 8;
@@ -891,17 +913,17 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag)

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() */
parser = strstr(dst, "main");
if (!parser) return;
parser = strstr(patched_code.C(), "main");
if (!parser) return patched_code;
parser = strstr(parser, "(");
if (!parser) return;
if (!parser) return patched_code;
parser = strstr(parser, ")");
if (!parser) return;
if (!parser) return patched_code;
parser = strstr(parser, "{");
if (!parser) return;
if (!parser) return patched_code;
char *main = parser + 1;

/* 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)
{
char *match = strstr(dst, rep[0]);
char *match = strstr(patched_code.C(), rep[0]);
if (match && match < main)
{
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[] =
{
"#version 130", "#version 120",
"in vec2", vert ? "attribute vec2" : "varying vec2",
"in vec3", vert ? "attribute vec3" : "varying vec3",
"in vec4", vert ? "attribute vec4" : "varying vec4",
"in mat4", vert ? "attribute mat4" : "varying mat4",
"in vec2", type == ShaderType::Vertex ? "attribute vec2" : "varying vec2",
"in vec3", type == ShaderType::Vertex ? "attribute vec3" : "varying vec3",
"in vec4", type == ShaderType::Vertex ? "attribute vec4" : "varying vec4",
"in mat4", type == ShaderType::Vertex ? "attribute mat4" : "varying mat4",
"out vec2", "varying vec2",
"out vec3", "varying vec3",
"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)
{
char *match;
while ((match = strstr(dst, rep[0])))
while ((match = strstr(patched_code.C(), rep[0])))
{
size_t l0 = strlen(rep[0]);
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 */


Caricamento…
Annulla
Salva