MKII
MKII

Reputation: 911

Confused about behaviour of shaders in OpenGL - switching declarations creates errors and crashes

I'm creating functions to load shaders, to create meshes, and the like, thus I started a simple program to test the functionalities I was adding, one by one, and I found a problem with this bit:

const char* vertexShader = prm.LoadShader ( "simple_vs.glsl" ).c_str ();
const char* fragmentShader = prm.LoadShader ( "simple_fs.glsl" ).c_str ();

GLuint vs = glCreateShader ( GL_VERTEX_SHADER );
glShaderSource ( vs, 1, &vertexShader, NULL );
glCompileShader ( vs );
GLuint fs = glCreateShader ( GL_FRAGMENT_SHADER );
glShaderSource ( fs, 1, &fragmentShader, NULL );
glCompileShader ( fs );

If I tried to compile it, I would get no errors, but there would be a black screen. If I removed the fragment shader, it would display a triangle, as it was meant to, without any colors. If I switched the two declarations, as in:

const char* fragmentShader = prm.LoadShader ( "simple_fs.glsl" ).c_str ();
const char* vertexShader = prm.LoadShader ( "simple_vs.glsl" ).c_str ();

I would get an error, and my program would crash:

Error code #3: Shader info for shader 1: WARNING: 0:1: '#version' : 
version number deprecated in OGL 3.0 forward compatible context driver
ERROR: 0:1: '#extension' :  'GL_ARB_separate_shader_objects' is not
supported

However, if I put it like this:

const char* vertexShader = prm.LoadShader ( "simple_vs.glsl" ).c_str ();

GLuint vs = glCreateShader ( GL_VERTEX_SHADER );
glShaderSource ( vs, 1, &vertexShader, NULL );
glCompileShader ( vs );

const char* fragmentShader = prm.LoadShader ( "simple_fs.glsl" ).c_str ();

GLuint fs = glCreateShader ( GL_FRAGMENT_SHADER );
glShaderSource ( fs, 1, &fragmentShader, NULL );
glCompileShader ( fs );

It works perfectly fine. I am completely clueless as to why this is the case, as I ran the original code with no issues in prior versions of my program. I already checked the prm.LoadShader function, it works fine, and returns the expected value. None of the changes I have made to the program deal with shaders, so I am confused about this bizzarely particular behaviour. Can someone with more experience explain why exactly this is happening?

Upvotes: 0

Views: 379

Answers (1)

Joseph Mansfield
Joseph Mansfield

Reputation: 110658

Presumably prm.LoadShader returns a std::string by value. Calling c_str gives you the internal character storage of a std::string, which only lives as long as the std::string does. By the end of each of the LoadShader lines, the std::string that was returned is destroyed because it was a temporary object, and the pointers you've stored are no longer pointing at valid character arrays.

You can easily get around it by storing a local copy of the returned strings.

std::string vertexShader = prm.LoadShader ( "simple_vs.glsl" );
const char* cVertexShader = vertexShader.c_str();
std::string fragmentShader = prm.LoadShader ( "simple_fs.glsl" );
const char* cFragmentShader = vertexShader.c_str();

GLuint vs = glCreateShader ( GL_VERTEX_SHADER );
glShaderSource ( vs, 1, &cVertexShader, NULL );
glCompileShader ( vs );
GLuint fs = glCreateShader ( GL_FRAGMENT_SHADER );
glShaderSource ( fs, 1, &cFragmentShader, NULL );
glCompileShader ( fs );

Upvotes: 4

Related Questions