Println! causes OpenGL program to not work?

Advertisements

I am currently developing a simple program in rust to draw a colored triangle to the screen. I followed the instructions from OpenGL. My program was working fine and the triangle rendered as expected:

After that I tried abstracting the code: The VAO, VBO and the ShaderProgram became a struct that handled binding, attaching the shaders and so on. That worked. Now to the problem:

When I tried to abstract the Attributes I ran into a problem. I added those two methods to the ShaderProgram struct, that should handle the enabling of attributes without having to hardcode things like the stride or the pointer at which position in the vector the attribute starts.

pub fn add_attribute(&mut self, name: &'a str, length: i32) {
    let mut props = VertexAttributeProps::new(name, length);
    self.attributes.push(props);
}
pub fn apply_attributes(&self) {
    const GL_FLOAT_SIZE: i32 = mem::size_of::<gl::types::GLfloat>() as i32;
    let stride = self
        .attributes
        .iter()
        .fold(0, |prev, attr| prev + attr.length)
        * GL_FLOAT_SIZE;

    let mut current_pos: i32 = 0;
    for attr_options in self.attributes.iter() {
        // println!("{:?}", current_pos);
        unsafe {
            let attribute = VertexAttribute::new(
                location,
                attr_options.length,
                gl::FLOAT,
                gl::FALSE,
                stride,
                (current_pos * GL_FLOAT_SIZE) as *const c_void,
            );
            attribute.enable();
        }
        current_pos = current_pos + attr_options.length;
    }
}

With that I wanted to add my attributes like this:

shader_program.add_attribute("position", 2);
shader_program.add_attribute("color", 3);
shader_program.apply_attributes();

instead of this nasty block:

let posAttrib: GLuint;
unsafe {
    posAttrib = gl::GetAttribLocation(
        shader_program.program_handle,
        "position".as_ptr() as *const i8,
    ) as u32;
    gl::EnableVertexAttribArray(posAttrib);
    gl::VertexAttribPointer(
        posAttrib,
        2,
        gl::FLOAT,
        gl::FALSE,
        5 * mem::size_of::<gl::types::GLfloat>() as i32,
        0 as *const c_void,
    )
}

let colAttrib: GLuint;
unsafe {
    colAttrib =
        gl::GetAttribLocation(shader_program.program_handle, "color".as_ptr() as *const i8)
            as u32;
    gl::EnableVertexAttribArray(colAttrib);
    gl::VertexAttribPointer(
        colAttrib,
        3,
        gl::FLOAT,
        gl::FALSE,
        5 * mem::size_of::<gl::types::GLfloat>() as i32,
        (2 * mem::size_of::<gl::types::GLfloat>()) as *const c_void,
    )
}

But that did not work.

So I tried debugging. (Yes, the source of the bug lies in this code, I have tested that). I tried comparing the nasty code with my abstraction. So I added this println! to the nasty code:

let posAttrib: GLuint;
unsafe {
    posAttrib = gl::GetAttribLocation(
        shader_program.program_handle,
        "position".as_ptr() as *const i8,
    ) as u32;

    // ???????
    println!("{}", posAttrib);
    // ???????

    gl::EnableVertexAttribArray(posAttrib);
    gl::VertexAttribPointer(
        posAttrib,
        2,
        gl::FLOAT,
        gl::FALSE,
        5 * mem::size_of::<gl::types::GLfloat>() as i32,
        0 as *const c_void,
    )
}

and the triangle stopped rendering. Removing it and the triangle is back. How can a simple println be so harmful? Is it some kind of timing issue where the println! takes to long and everything somehow breaks?

>Solution :

Your code has undefined behavior. Rust string literals are not null-terminated as glGetAttribLocation expects. So there’s an out-of-bounds read until who knows where.

You’d need to use "position\0" or CString to fix that.

Leave a ReplyCancel reply