3

It seems I can't have my GLSL shaders compiled. Once in a while (mainly after editing a file), I get following error while compiling:

----- SRC ----- (150 B) #version 330 core uniform mat4 mvpMatrix; in vec4 vertexPosition_modelspace; void main() { gl_Position = mvpMatrix * vertexPosition_modelspace; } gp! ----- END ----- SimpleTransform.vertexshader:Vertex shader failed to compile with the following errors: ERROR: 0:10: error(#132) Syntax error: 'gp' parse error ERROR: error(#273) 1 compilation errors. No code generated 

It's quite strange since I swear the file doesn't contain that awkward gp! part. Nevertheless I investigated it with cat

#version 330 core uniform mat4 mvpMatrix; in vec4 vertexPosition_modelspace; void main() { gl_Position = mvpMatrix * vertexPosition_modelspace; } 

and less

#version 330 core uniform mat4 mvpMatrix; in vec4 vertexPosition_modelspace; void main() { gl_Position = mvpMatrix * vertexPosition_modelspace; } 

and both of them proved me right.

I wonder what's causing this strange behaviour.

Here's link to my project. You should be able to easily compile it by entering src directory and typing make (Linux only). It requires GLFW, GLEW, GLM and GL3.

And the code itself:

Loading shader files

GLuint shader_load(GLenum type, const char filename[]) { if ((type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) || !filename) return 0; /* wczytywanie pliku shadera */ FILE *file = fopen(filename, "rb"); //okreslenie rozmiaru pliku fseek(file, 0, SEEK_END); uint32 iFileSize = ftell(file); fseek(file, 0, SEEK_SET); //wczytywanie char *tmp = new char[iFileSize]; memset(tmp, 0, sizeof(tmp)); uint32 iBytes = (uint32) fread(tmp, sizeof(char), iFileSize, file); fclose(file); if (iBytes != iFileSize) printf("Warning: reading error possible!\n"); #ifdef _DEBUG_ printf("----- SRC ----- (%d B)\n%s\n----- END -----\n", iBytes, tmp); #endif /* przygotowanie shadera */ GLuint shader = glCreateShader(type); glShaderSource(shader, 1, const_cast<const GLchar**>(&tmp), NULL); delete[] tmp; glCompileShader(shader); //kompilacja shadera /* sprawdzenie statusu kompilacji */ int status = GL_FALSE; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); int logsize = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logsize); char *log = new char[logsize]; glGetShaderInfoLog(shader, logsize, NULL, log); printf("%s:%s", filename, log); delete[] log; if (status != GL_TRUE) return 0; return shader; } 
6
  • Please show your relevant code here, you'll get a better response than waiting for someone to download and dig through your project. I'll guess there's some issue with not null-terminating the shader strings. Commented Aug 24, 2012 at 23:08
  • Don't send me your project to build it using some complicated platform-dependent build procedure. Just post the relevant code (most probably the shader loading code). That will last even once you removed your project and the link went dead next week. Commented Aug 24, 2012 at 23:09
  • @ChristianRau added loading shader source code Commented Aug 24, 2012 at 23:13
  • Also, if you use gDEBugger you can see what code actually gets sent to the graphics card for each shader. (Not all graphics drivers will show the shader source code when reporting error messages) Commented Aug 25, 2012 at 0:06
  • Added a sample snippet that shows how the fragment would have been written using std::string instead of juggling raw arrays, memset, off-by-ones and hairy casts :) Commented Aug 25, 2012 at 0:06

1 Answer 1

6

FIRST OFF Switch to C++ instead of C-with-a-cpp extension to avoid shipwrecks like this.

Analysis:


Running under valgrind shows

==15579== Invalid read of size 1 ==15579== at 0x5B95C65: vfprintf (vfprintf.c:1623) ==15579== by 0x5B9E768: printf (printf.c:35) ==15579== by 0x4019C1: shader_load(unsigned int, char const*) (shaders.cpp:88) ==15579== by 0x401B30: program_create(char const*, char const*) (shaders.cpp:120) ==15579== by 0x401D65: main (in /tmp/ogl-jg-3/test) ==15579== Address 0xb3018a6 is 0 bytes after a block of size 150 alloc'd ==15579== at 0x4C2864B: operator new[](unsigned long) (vg_replace_malloc.c:305) ==15579== by 0x401961: shader_load(unsigned int, char const*) (shaders.cpp:81) ==15579== by 0x401B30: program_create(char const*, char const*) (shaders.cpp:120) ==15579== by 0x401D65: main (in /tmp/ogl-jg-3/test) 

It tells you exactly that it tries to read beyond the end of the buffer tmp which is allocated in line 81. It seems you are somehow assuming it is null-terminated. Which it isn't. Add that:

//wczytywanie char *tmp = new char[iFileSize+1]; memset(tmp, 0, (iFileSize+1)*sizeof(char)); uint32 iBytes = (uint32) fread(tmp, sizeof(char), iFileSize, file); fclose(file); if (iBytes != iFileSize) printf("Warning: reading error possible!\n"); #ifdef _DEBUG_ printf("----- SRC ----- (%d B)\n%s\n----- END -----\n", iBytes, tmp); #endif 

And I get semi-decent output. The GL window stays blank, though

Update

To make it clearer what I meant by switch to C++ here's the idea:

GLuint shader_load(GLenum type, const char filename[]) { if ((type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) || !filename) return 0; GLuint shader = glCreateShader(type); std::string src; { /* wczytywanie pliku shadera */ std::ifstream ifs(filename, std::ios::binary); if (!std::getline(ifs, src, '\0')) std::cerr << "Warning: reading error possible!\n"; } #ifdef _DEBUG_ std::cout << "----- SRC ----- " << src.size() << " B \n" << src << "\n----- END -----\n"; #endif /* przygotowanie shadera */ const GLchar* sources[] = { src.c_str() }; glShaderSource(shader, 1, sources, NULL); glCompileShader(shader); //kompilacja shadera 
Sign up to request clarification or add additional context in comments.

8 Comments

Or, you could just pass the string length to glShaderSource in the 4th parameter, which is an array to integers holding the length's of the strings pointed to in the array elements in the 3rd parameter.
@datenwolf I would never have known, because I don't do graphics programming, and don't know the APIs :) Thanks for the useful note
While you switched to C++, why then use C files and the like and not just do a simple std::istream file(filename); std::string tmp(std::istreambuf_iterator<char>(file), (std::istreambuf_iterator())); instead of the whole fread and resize mess (not speak of an explicit fclose)? Your code isn't really any less C/C++ than his.
@ChristianRau Mostly because (a) it wasn't related to the question (b) it wasn't related to the answer (c) it wasn't my problem. But since you have a fair point, I updated the answer for it :)
@sehe I agree that it wasn't your problem and neither related to the question, but since you explicitly suggest him to switch from C/C++ to proper C++, it was pretty relevant for the answer.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.