简体   繁体   中英

glCompileShader segfault because of an if statement

This fragment shader compiles and works without a problem:

#version 330 core
uniform sampler2D sampler;
uniform vec3 clr;
vec2 pos;
void main(void) {
    pos.x = gl_FragCoord.x / 960.0;
    pos.y = gl_FragCoord.y / 540.0;
    gl_FragColor = vec4(clr,1) * texture(sampler, pos.st);
}

This throws segmentation fault somewhere inside glCompileShader :

#version 330 core
uniform sampler2D sampler;
uniform vec3 clr;
vec2 pos;
void main(void) {
    pos.x = gl_FragCoord.x / 960.0;
    pos.y = gl_FragCoord.y / 540.0;
    if (texture(sampler, pos.st).r > 0.5) {
        gl_FragColor = vec4(clr, 1) * 0.5;
    }
    else {
        gl_FragColor = vec4(clr, 1);
    }
}

Everything else is identical. Does anyone know the reason behind this?

This throws segmentation fault somewhere inside glCompileShader

Problems like these are usually caused by out-of-bounds memory access. The API of glShaderSource is specified (version 4.5) as following (emphasis by me):

The command

void glShaderSource( GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length );

loads source code into the shader object named shader. string is an array of count pointers to optionally null-terminated character strings that make up the source code. The length argument is an array with the number of chars in each string (the string length). If an element in length is negative, its accompanying string is null-terminated. If length is NULL, all strings in the string argument are considered null-terminated.

This means that if you don't null-terminate your shader strings OpenGL expects you to pass it length information or vice versa.

Why is this important is your case? The one important difference between your two shader sources is the length of the shader source string. And it's quite possible that after the end of the shorter source a couple of null bytes may appear¹. And the small change of making your shader source string just a little bit longer may have a huge effect on where it's going to end up in memory and what comes after it.

So why might your shader source string not be null-terminated? For example if you read it from a file and allocate the memory to be exactly the file size. In that case there's not going to be a null-termination character.

The takeaway is: Either properly null-terminate your shader source strings or explicitly pass in the shader source string length. Preferably do both (it never hurts to be paranoid about out-of-bounds memory access).


1: Maybe leftovers from a previous allocation at the same memory spot, or maybe your source string was short enough that it fit into a single page and the malloc implementation decided that requesting a fresh page would be appropriate (and fresh pages usually read zero unless it's not explicitly requested to not initialize them).

The code below should work fine. The problem in your code is tricky as it might be the problem during optimisation.

Also, isn't it 'texture2D' instead of 'texture'?

#version 330 core
uniform sampler2D sampler;
uniform vec3 clr;
vec2 pos;
void main(void) {
    pos.x = gl_FragCoord.x / 960.0;
    pos.y = gl_FragCoord.y / 540.0;

    float rValue = texture(sampler, pos.st).r;

    gl_FragColor = vec4(clr, 1.0) * mix(1.0, 0.5, rValue > 0.5);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM