0

Quite simply, I'm just trying to load a file into a string for my OpenGL shaders. I have tried both of the following:

std::string result = "";
std::ifstream stream(path, std::ios::in);
std::string line = "";
while (getline(stream, line))
    result += line + "\n";
stream.close();
return result.c_str();

as well as

std::ifstream stream(path, std::ios::in);
std::string result(std::istreambuf_iterator<char>(stream), (std::istreambuf_iterator<char>()));
stream.close();
return result.c_str();

I use these methods in my shader class here:

std::string basePath = std::string("shaders/");
std::string vertPath = basePath + name + ".vsh";
std::string fragPath = basePath + name + ".fsh";
const char* vertSrc = loadFile(vertPath.c_str());
const char* fragSrc = loadFile(fragPath.c_str());

I create a shader where name is "standard" and both load fine. Then I call the constructor again, but instead the name is "fxaa". The fragment shader loads in fine, but fxaa.vsh loaded like this:

#version 330 core

uniform sampler2D sampler;
uniform vec2 fbo_size;

in vec4 frag_color;
in vec2 tex_coord;

layout (location = 0) out vec4 final_color;

void main()
{
    float FXAA_SPAN_MAX = 8.0;
    float FXAA_REDUCE_MUL = 1.0 / 8.0;
    float FXAA_REDUCE_MIN = 1.0 / 128.0;

    vec3 rgbNW = texture(sampler, tex_coord + (vec2(-1.0, -1.0) / fbo_size)).rgb;
    vec3 rgbNE = texture(sampler, tex_coord + (vec2(1.0, -1.0) / fbo_size)).rgb;
    vec3 rgbSW = texture(sampler, tex_coord + (vec2(-1.0, 1.0) / fb

when it should of loaded like this:

#version 330 core

uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;

layout (location = 10) in vec3 vertex_in;
layout (location = 11) in vec4 color_in;
layout (location = 12) in vec2 tex_coord_in;

out vec4 frag_color;
out vec2 tex_coord;

void main()
{
    gl_Position = projection_matrix * view_matrix *
            model_matrix * vec4(vertex_in, 1.0);
    frag_color = color_in;
    tex_coord = tex_coord_in;
}

and the top of the fragment shader looks like what the vertex shader loaded as: (lines 1 - 21)

#version 330 core

uniform sampler2D sampler;
uniform vec2 fbo_size;

in vec4 frag_color;
in vec2 tex_coord;

layout (location = 0) out vec4 final_color;

void main()
{
    float FXAA_SPAN_MAX = 8.0;
    float FXAA_REDUCE_MUL = 1.0 / 8.0;
    float FXAA_REDUCE_MIN = 1.0 / 128.0;

    vec3 rgbNW = texture(sampler, tex_coord + (vec2(-1.0, -1.0) / fbo_size)).rgb;
    vec3 rgbNE = texture(sampler, tex_coord + (vec2(1.0, -1.0) / fbo_size)).rgb;
    vec3 rgbSW = texture(sampler, tex_coord + (vec2(-1.0, 1.0) / fbo_size)).rgb;
    vec3 rgbSE = texture(sampler, tex_coord + (vec2(1.0, 1.0) / fbo_size)).rgb;
    vec3 rgbM = texture(sampler, tex_coord).rgb;

I am a Java programmer at heart, so I am not familiar with C++'s IO system. I'm sure it's something I have to do with my ifstream or even my files or the entire file loader, however I do not know what.

1 Answers1

1

This is a common mistake that has nothing to do with how you load the file. The only relevant statements are these two:

std::string result = "";
...
return result.c_str();

result is an object (of type string) that is allocated as a local variable on the stack at the time it is defined. At the end of the function, it goes out of scope, and is destroyed, meaning that the string data it contains is freed.

The c_str() method returns a pointer to the internal storage of the string object. As soon as the string is destroyed, which as shown above happens on function exit, the internal storage is freed. The result is that the result you obtained from the c_str() method is invalid after this point, since it points to freed memory.

As a result, the function returns a pointer to freed memory, which can be reused for other memory allocations. So if you look at the returned content, the value can be overwritten because the memory is used by other allocations. Some memory allocation routines intentionally overwrite freed memory, particularly in debug mode, to make such errors more noticeable.

What you need to do is return a std::string object from the method, instead of a const char*. Then the value will be properly returned, and copied to the variable you assign it to.

Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
  • It appears there's still a problem. In the third code block I added, both `vertSrc` and `fragSrc` have the same value, even though they are separate files. –  Dec 29 '15 at 19:00
  • Actually, now it loads the first shader fine then loads random characters for the second shader's vertex shader then crashes on the fragment shader. –  Dec 29 '15 at 19:05
  • Sorry, I fixed it by first loading the source into an `std::string` and then copying the `c_str()`. (Same exact issue as this question.) –  Dec 29 '15 at 19:09