devkitPro / citro3d

Homebrew PICA200 GPU wrapper library for Nintendo 3DS
zlib License
244 stars 34 forks source link

Use-after-free in C3D_BindProgram #65

Open neobrain opened 8 months ago

neobrain commented 8 months ago

Freeing a shaderProgram_s that was previously bound using C3D_BindProgram will cause the next call to C3D_BindProgram to crash, even if the original program was never used after freeing it.

The problem is C3D_Context carries around a reference to the old program for tracking dirty state, however that reference becomes invalid when that program is freed.

What makes this problem even worse is that you can't unbind a program, e.g. by calling C3D_BindProgram(nullptr), since there's no null check in that function.

neobrain commented 8 months ago

For reference, here's a (probably) usable workaround in case anyone else comes across this issue:

void UnbindC3DProgram() {
    static DVLE_s dummy_dvle {};
    static shaderInstance_s dummy_shader = {
        .dvle = &dummy_dvle
    };
    static shaderProgram_s dummy_program = {
        .vertexShader = &dummy_shader
    };
    C3D_BindProgram(&dummy_program);
}

(This is clearly not ideal since C3D_BindProgram wasn't written to be called on placeholder programs.)