mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Fix, Test] (MG_State, MG_Impl): reflection-backed glGetProgramiv queries answer zero instead of dereferencing a null TProgram
This commit is contained in:
@@ -516,12 +516,27 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
Artifacts().infoLog = "No program binary format is supported.";
|
Artifacts().infoLog = "No program binary format is supported.";
|
||||||
}
|
}
|
||||||
Bool GetValidateStatus() const { return m_validateStatus; }
|
Bool GetValidateStatus() const { return m_validateStatus; }
|
||||||
Int GetActiveAtomicCounterCount() const { return Artifacts().program->getNumAtomicCounters(); }
|
// Artifacts().program is null until a link produces reflection, and glGetProgramiv is
|
||||||
Int GetActiveAttributesCount() const { return Artifacts().program->getNumPipeInputs(); }
|
// perfectly legal on a program that never linked (GL 4.6 sec. 7.3: the queried state is
|
||||||
|
// simply its initial value, zero). Dereferencing it there took the process down with a
|
||||||
|
// SIGSEGV inside glslang::TProgram::getNumPipeInputs - KHR-GL30.api.coverage does exactly
|
||||||
|
// this after a failed glGetAttribLocation, and reached it as soon as the CopyTexImage2D
|
||||||
|
// throw ahead of it stopped killing the run first.
|
||||||
|
Int GetActiveAtomicCounterCount() const {
|
||||||
|
const auto& program = Artifacts().program;
|
||||||
|
return program ? program->getNumAtomicCounters() : 0;
|
||||||
|
}
|
||||||
|
Int GetActiveAttributesCount() const {
|
||||||
|
const auto& program = Artifacts().program;
|
||||||
|
return program ? program->getNumPipeInputs() : 0;
|
||||||
|
}
|
||||||
// GL-visible uniform blocks only: the synthesized MGL_GLOBAL_UBO the relaxed parse
|
// GL-visible uniform blocks only: the synthesized MGL_GLOBAL_UBO the relaxed parse
|
||||||
// materializes for default-block uniforms is filtered out by DoReflection.
|
// materializes for default-block uniforms is filtered out by DoReflection.
|
||||||
Int GetActiveUniformBlocksCount() const { return static_cast<Int>(Artifacts().glBlockIndexToTProgram.size()); }
|
Int GetActiveUniformBlocksCount() const { return static_cast<Int>(Artifacts().glBlockIndexToTProgram.size()); }
|
||||||
GLuint GetComputeLocalSize(Uint dim) const { return Artifacts().program->getLocalSize(static_cast<Int>(dim)); }
|
GLuint GetComputeLocalSize(Uint dim) const {
|
||||||
|
const auto& program = Artifacts().program;
|
||||||
|
return program ? program->getLocalSize(static_cast<Int>(dim)) : 0;
|
||||||
|
}
|
||||||
Int GetActiveAttributesMaxLength() const { return Artifacts().attribInNameMaxLength; }
|
Int GetActiveAttributesMaxLength() const { return Artifacts().attribInNameMaxLength; }
|
||||||
Int GetActiveUniformBlocksMaxNameLength() const { return Artifacts().uniformBlockNameMaxLength; }
|
Int GetActiveUniformBlocksMaxNameLength() const { return Artifacts().uniformBlockNameMaxLength; }
|
||||||
Uint GetUniformBlockIndex(const char* name) const {
|
Uint GetUniformBlockIndex(const char* name) const {
|
||||||
|
|||||||
@@ -1101,6 +1101,55 @@ void main() { color = u + v; }
|
|||||||
EXPECT_EQ(TakeError(), GL_NO_ERROR);
|
EXPECT_EQ(TakeError(), GL_NO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------- queries on an unlinked program ----
|
||||||
|
// glGetProgramiv is legal on a program that has never linked - GL 4.6 sec. 7.3 says the
|
||||||
|
// queried state simply has its initial value - but the reflection-backed pnames read
|
||||||
|
// Artifacts().program, which is null until a link produces one. That dereference was a
|
||||||
|
// SIGSEGV inside glslang::TProgram::getNumPipeInputs, and KHR-GL30.api.coverage walks into it
|
||||||
|
// (it queries GL_ACTIVE_ATTRIBUTES right after a glGetAttribLocation that failed). It only
|
||||||
|
// became reachable once the glCopyTexImage2D throw ahead of it in the same case stopped
|
||||||
|
// killing the run first.
|
||||||
|
TEST_F(ProgramInterfaceTest, ReflectionQueriesOnAnUnlinkedProgramAnswerZero) {
|
||||||
|
const GLuint neverLinked = CreateProgram();
|
||||||
|
ASSERT_NE(neverLinked, 0u);
|
||||||
|
ClearErrors();
|
||||||
|
|
||||||
|
for (const GLenum pname : {GL_ACTIVE_ATTRIBUTES, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, GL_ACTIVE_UNIFORMS,
|
||||||
|
GL_ACTIVE_UNIFORM_MAX_LENGTH, GL_ACTIVE_UNIFORM_BLOCKS,
|
||||||
|
GL_ACTIVE_ATOMIC_COUNTER_BUFFERS}) {
|
||||||
|
GLint value = -1;
|
||||||
|
GetProgramiv(neverLinked, pname, &value);
|
||||||
|
ClearErrors();
|
||||||
|
EXPECT_GE(value, 0) << "pname 0x" << std::hex << pname << " left its output untouched";
|
||||||
|
}
|
||||||
|
|
||||||
|
// A program that was linked and FAILED is the shape api.coverage actually hits.
|
||||||
|
const GLuint brokenSource = MakeProgram("#version 430\nvoid main() { this is not glsl }\n", kSimpleFs);
|
||||||
|
LinkProgram(brokenSource);
|
||||||
|
ClearErrors();
|
||||||
|
GLint linked = GL_TRUE;
|
||||||
|
GetProgramiv(brokenSource, GL_LINK_STATUS, &linked);
|
||||||
|
ASSERT_EQ(linked, GL_FALSE) << "the shader was supposed to fail to compile";
|
||||||
|
ClearErrors();
|
||||||
|
|
||||||
|
GLint attributes = -1;
|
||||||
|
GetProgramiv(brokenSource, GL_ACTIVE_ATTRIBUTES, &attributes);
|
||||||
|
ClearErrors();
|
||||||
|
EXPECT_EQ(attributes, 0);
|
||||||
|
|
||||||
|
// GL_COMPUTE_WORK_GROUP_SIZE is GL_INVALID_OPERATION on a program that has not linked (GL
|
||||||
|
// 4.6 sec. 7.13), so it is allowed to leave the output alone - but it still reaches
|
||||||
|
// GetComputeLocalSize(), and it may not do so through a null reflection.
|
||||||
|
GLint localSize[3] = {-1, -1, -1};
|
||||||
|
GetProgramiv(brokenSource, GL_COMPUTE_WORK_GROUP_SIZE, localSize);
|
||||||
|
const GLenum computeError = TakeError();
|
||||||
|
ClearErrors();
|
||||||
|
EXPECT_TRUE(computeError == GL_INVALID_OPERATION || (localSize[0] == 0 && localSize[1] == 0 &&
|
||||||
|
localSize[2] == 0))
|
||||||
|
<< "either the query is refused, or it answers the initial value - never both untouched "
|
||||||
|
"and unreported";
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------- length on every path ----
|
// ------------------------------------------------------------- length on every path ----
|
||||||
// glGetProgramResourceiv's *length is the caller's only signal for how many entries params
|
// glGetProgramResourceiv's *length is the caller's only signal for how many entries params
|
||||||
// holds, and callers are entitled to leave it uninitialised: the CTS declares `GLsizei
|
// holds, and callers are entitled to leave it uninitialised: the CTS declares `GLsizei
|
||||||
|
|||||||
Reference in New Issue
Block a user