Rearrange glBindProgram() code to do all error checking before changing
the binding. Prevent a potential dangling pointer error. SF Bug 1544507.
This commit is contained in:
@@ -1770,103 +1770,95 @@ compatible_program_targets(GLenum t1, GLenum t2)
|
|||||||
void GLAPIENTRY
|
void GLAPIENTRY
|
||||||
_mesa_BindProgram(GLenum target, GLuint id)
|
_mesa_BindProgram(GLenum target, GLuint id)
|
||||||
{
|
{
|
||||||
struct gl_program *prog;
|
struct gl_program *curProg, *newProg;
|
||||||
GET_CURRENT_CONTEXT(ctx);
|
GET_CURRENT_CONTEXT(ctx);
|
||||||
ASSERT_OUTSIDE_BEGIN_END(ctx);
|
ASSERT_OUTSIDE_BEGIN_END(ctx);
|
||||||
|
|
||||||
FLUSH_VERTICES(ctx, _NEW_PROGRAM);
|
FLUSH_VERTICES(ctx, _NEW_PROGRAM);
|
||||||
|
|
||||||
|
/* Error-check target and get curProg */
|
||||||
if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
|
if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
|
||||||
(ctx->Extensions.NV_vertex_program ||
|
(ctx->Extensions.NV_vertex_program ||
|
||||||
ctx->Extensions.ARB_vertex_program)) {
|
ctx->Extensions.ARB_vertex_program)) {
|
||||||
/*** Vertex program binding ***/
|
curProg = &ctx->VertexProgram.Current->Base;
|
||||||
struct gl_vertex_program *curProg = ctx->VertexProgram.Current;
|
|
||||||
if (curProg->Base.Id == id) {
|
|
||||||
/* binding same program - no change */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (curProg->Base.Id != 0) {
|
|
||||||
/* decrement refcount on previously bound vertex program */
|
|
||||||
curProg->Base.RefCount--;
|
|
||||||
/* and delete if refcount goes below one */
|
|
||||||
if (curProg->Base.RefCount <= 0) {
|
|
||||||
/* the program ID was already removed from the hash table */
|
|
||||||
ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if ((target == GL_FRAGMENT_PROGRAM_NV
|
else if ((target == GL_FRAGMENT_PROGRAM_NV
|
||||||
&& ctx->Extensions.NV_fragment_program) ||
|
&& ctx->Extensions.NV_fragment_program) ||
|
||||||
(target == GL_FRAGMENT_PROGRAM_ARB
|
(target == GL_FRAGMENT_PROGRAM_ARB
|
||||||
&& ctx->Extensions.ARB_fragment_program)) {
|
&& ctx->Extensions.ARB_fragment_program)) {
|
||||||
/*** Fragment program binding ***/
|
curProg = &ctx->FragmentProgram.Current->Base;
|
||||||
struct gl_fragment_program *curProg = ctx->FragmentProgram.Current;
|
|
||||||
if (curProg->Base.Id == id) {
|
|
||||||
/* binding same program - no change */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (curProg->Base.Id != 0) {
|
|
||||||
/* decrement refcount on previously bound fragment program */
|
|
||||||
curProg->Base.RefCount--;
|
|
||||||
/* and delete if refcount goes below one */
|
|
||||||
if (curProg->Base.RefCount <= 0) {
|
|
||||||
/* the program ID was already removed from the hash table */
|
|
||||||
ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
|
_mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: binding to a non-existant program is not an error.
|
/*
|
||||||
|
* Get pointer to new program to bind.
|
||||||
|
* NOTE: binding to a non-existant program is not an error.
|
||||||
* That's supposed to be caught in glBegin.
|
* That's supposed to be caught in glBegin.
|
||||||
*/
|
*/
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
/* Bind default program */
|
/* Bind a default program */
|
||||||
prog = NULL;
|
newProg = NULL;
|
||||||
if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
|
if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
|
||||||
prog = ctx->Shared->DefaultVertexProgram;
|
newProg = ctx->Shared->DefaultVertexProgram;
|
||||||
else
|
else
|
||||||
prog = ctx->Shared->DefaultFragmentProgram;
|
newProg = ctx->Shared->DefaultFragmentProgram;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Bind user program */
|
/* Bind a user program */
|
||||||
prog = _mesa_lookup_program(ctx, id);
|
newProg = _mesa_lookup_program(ctx, id);
|
||||||
if (!prog || prog == &_mesa_DummyProgram) {
|
if (!newProg || newProg == &_mesa_DummyProgram) {
|
||||||
/* allocate a new program now */
|
/* allocate a new program now */
|
||||||
prog = ctx->Driver.NewProgram(ctx, target, id);
|
newProg = ctx->Driver.NewProgram(ctx, target, id);
|
||||||
if (!prog) {
|
if (!newProg) {
|
||||||
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
|
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_mesa_HashInsert(ctx->Shared->Programs, id, prog);
|
_mesa_HashInsert(ctx->Shared->Programs, id, newProg);
|
||||||
}
|
}
|
||||||
else if (!compatible_program_targets(prog->Target, target)) {
|
else if (!compatible_program_targets(newProg->Target, target)) {
|
||||||
_mesa_error(ctx, GL_INVALID_OPERATION,
|
_mesa_error(ctx, GL_INVALID_OPERATION,
|
||||||
"glBindProgramNV/ARB(target mismatch)");
|
"glBindProgramNV/ARB(target mismatch)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bind now */
|
/** All error checking is complete now **/
|
||||||
|
|
||||||
|
if (curProg->Id == id) {
|
||||||
|
/* binding same program - no change */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unbind/delete oldProg */
|
||||||
|
if (curProg->Id != 0) {
|
||||||
|
/* decrement refcount on previously bound fragment program */
|
||||||
|
curProg->RefCount--;
|
||||||
|
/* and delete if refcount goes below one */
|
||||||
|
if (curProg->RefCount <= 0) {
|
||||||
|
/* the program ID was already removed from the hash table */
|
||||||
|
ctx->Driver.DeleteProgram(ctx, curProg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bind newProg */
|
||||||
if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
|
if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
|
||||||
ctx->VertexProgram.Current = (struct gl_vertex_program *) prog;
|
ctx->VertexProgram.Current = (struct gl_vertex_program *) newProg;
|
||||||
}
|
}
|
||||||
else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) {
|
else if (target == GL_FRAGMENT_PROGRAM_NV ||
|
||||||
ctx->FragmentProgram.Current = (struct gl_fragment_program *) prog;
|
target == GL_FRAGMENT_PROGRAM_ARB) {
|
||||||
|
ctx->FragmentProgram.Current = (struct gl_fragment_program *) newProg;
|
||||||
}
|
}
|
||||||
|
newProg->RefCount++;
|
||||||
|
|
||||||
/* Never null pointers */
|
/* Never null pointers */
|
||||||
ASSERT(ctx->VertexProgram.Current);
|
ASSERT(ctx->VertexProgram.Current);
|
||||||
ASSERT(ctx->FragmentProgram.Current);
|
ASSERT(ctx->FragmentProgram.Current);
|
||||||
|
|
||||||
if (prog)
|
|
||||||
prog->RefCount++;
|
|
||||||
|
|
||||||
if (ctx->Driver.BindProgram)
|
if (ctx->Driver.BindProgram)
|
||||||
ctx->Driver.BindProgram(ctx, target, prog);
|
ctx->Driver.BindProgram(ctx, target, newProg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user