You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If you have a function returning a struct and you directly try to access a member from this struct from the function call, but this member does not actually exist, glslang, as a library, and glslangValidator will crash.
Shader example :
#version460struct A {
float x;
};
A test() {
return A(1.0);
}
void main() {
test().z; // A.z does not exist, causes a crash
}
Crash happens during the parsing stage, in ParseHelper.cpp, in the handleDotDereference function :
error(loc, "no such field in structure", field.c_str(), structName.c_str());
The while loop is checking if baseSymbol is a TIntermSymbol, and if it is not, tries to dereference it as a binary node, which is nullptr in this case, causing a crash.
The difference between
test().z; // A.z does not exist, causes a crash
and
A c = A(1.0);
float b = c.z; // A.z does not exist, does not crash
is that baseSymbol is of type TIntermAggregate in the first case and TIntermSymbol in the second.
TIntermAggregate does not have a getAsSymbolNode nor a getAsBinaryNode member function and use the base class TIntermNode implementations instead, which both return nullptr.
getAsBinaryNode is implemented by TIntermBinary, so
auto baseSymbol = base;
while (baseSymbol->getAsSymbolNode() == nullptr)
baseSymbol = baseSymbol->getAsBinaryNode()->getLeft();
is trying to get a TIntermSymbol and estimates that if baseSymbol is not a TIntermSymbol, then it is a TIntermBinary, which is not the case here, as it is a TIntermAggregate.
One possible fix is to isolate both cases, one where baseSymbol is a TIntermBinary and one where baseSymbol is a TIntermAggregate, then getting the name of either the TIntermSymbol or the TIntermAggregate and write a different message when the error is from a TIntermAggregate :
auto baseSymbol = base;
while (baseSymbol->getAsSymbolNode() == nullptr) {
if (baseSymbol->getAsBinaryNode() == nullptr) {
break;
}
baseSymbol = baseSymbol->getAsBinaryNode()->getLeft();
}
TString structName;
if (baseSymbol->getAsSymbolNode() != nullptr) {
structName.append("\'").append(baseSymbol->getAsSymbolNode()->getName().c_str()).append("\'");
error(loc, "no such field in structure", field.c_str(), structName.c_str());
} elseif (baseSymbol->getAsAggregate() != nullptr) {
structName.append("\'").append(baseSymbol->getAsAggregate()->getName().c_str()).append("\'");
structName.erase(structName.end() - 2);
error(loc, "no such field in structure returned by function", field.c_str(), structName.c_str());
}
I don't know if any more types can reach this code path so I am not sure if it actually works in all cases.
With the example code :
ERROR: 0:15: 'z' : no such field in structure returned by function 'test'
ERROR: 0:15: '' : compilation terminated
ERROR: 2 compilation errors. No code generated.
The text was updated successfully, but these errors were encountered:
I improvised off your code above. The non-symbol case didn't seem general enough to me, so I bailed and only printed the bad member name and not the struct expression for this case. It shouldn't crash now, and if someone wants to add more code to generate a nicer message for the non-symbol case, they are welcome.
kd-11
pushed a commit
to kd-11/glslang
that referenced
this issue
Dec 11, 2023
If you have a function returning a struct and you directly try to access a member from this struct from the function call, but this member does not actually exist, glslang, as a library, and glslangValidator will crash.
Shader example :
Crash happens during the parsing stage, in ParseHelper.cpp, in the
handleDotDereference
function :glslang/glslang/MachineIndependent/ParseHelper.cpp
Lines 1037 to 1042 in 06a7078
The while loop is checking if
baseSymbol
is aTIntermSymbol
, and if it is not, tries to dereference it as a binary node, which isnullptr
in this case, causing a crash.The difference between
test().z; // A.z does not exist, causes a crash
and
is that
baseSymbol
is of typeTIntermAggregate
in the first case andTIntermSymbol
in the second.TIntermAggregate
does not have agetAsSymbolNode
nor agetAsBinaryNode
member function and use the base classTIntermNode
implementations instead, which both returnnullptr
.getAsBinaryNode
is implemented byTIntermBinary
, sois trying to get a
TIntermSymbol
and estimates that ifbaseSymbol
is not aTIntermSymbol
, then it is aTIntermBinary
, which is not the case here, as it is aTIntermAggregate
.One possible fix is to isolate both cases, one where
baseSymbol
is aTIntermBinary
and one wherebaseSymbol
is aTIntermAggregate
, then getting the name of either theTIntermSymbol
or theTIntermAggregate
and write a different message when the error is from aTIntermAggregate
:I don't know if any more types can reach this code path so I am not sure if it actually works in all cases.
With the example code :
The text was updated successfully, but these errors were encountered: