Prevent stack overflow due to recursive swizzle of an l-value
Long chains of recursive swizzling could previously cause a stack
overflow in checkCanBeLValue. Fold recursive swizzling when it is
parsed to prevent this.
BUG=angleproject:2439
TEST=angle_unittests
Change-Id: I83b4c27442185709f6762d5ec23b93244010da05
Reviewed-on: https://chromium-review.googlesource.com/983593
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 1004f27..4e25c44 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -795,6 +795,7 @@
ASSERT(operandCopy != nullptr);
mOperand = operandCopy;
mSwizzleOffsets = node.mSwizzleOffsets;
+ mHasFoldedDuplicateOffsets = node.mHasFoldedDuplicateOffsets;
}
TIntermBinary::TIntermBinary(const TIntermBinary &node)
@@ -1041,7 +1042,8 @@
TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
: TIntermExpression(TType(EbtFloat, EbpUndefined)),
mOperand(operand),
- mSwizzleOffsets(swizzleOffsets)
+ mSwizzleOffsets(swizzleOffsets),
+ mHasFoldedDuplicateOffsets(false)
{
ASSERT(mSwizzleOffsets.size() <= 4);
promote();
@@ -1167,6 +1169,10 @@
bool TIntermSwizzle::hasDuplicateOffsets() const
{
+ if (mHasFoldedDuplicateOffsets)
+ {
+ return true;
+ }
int offsetCount[4] = {0u, 0u, 0u, 0u};
for (const auto offset : mSwizzleOffsets)
{
@@ -1179,6 +1185,11 @@
return false;
}
+void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)
+{
+ mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets;
+}
+
bool TIntermSwizzle::offsetsMatch(int offset) const
{
return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
@@ -1472,6 +1483,24 @@
TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
{
+ TIntermSwizzle *operandSwizzle = mOperand->getAsSwizzleNode();
+ if (operandSwizzle)
+ {
+ // We need to fold the two swizzles into one, so that repeated swizzling can't cause stack
+ // overflow in ParseContext::checkCanBeLValue().
+ bool hadDuplicateOffsets = operandSwizzle->hasDuplicateOffsets();
+ TVector<int> foldedOffsets;
+ for (int offset : mSwizzleOffsets)
+ {
+ // Offset should already be validated.
+ ASSERT(static_cast<size_t>(offset) < operandSwizzle->mSwizzleOffsets.size());
+ foldedOffsets.push_back(operandSwizzle->mSwizzleOffsets[offset]);
+ }
+ operandSwizzle->mSwizzleOffsets = foldedOffsets;
+ operandSwizzle->setType(getType());
+ operandSwizzle->setHasFoldedDuplicateOffsets(hadDuplicateOffsets);
+ return operandSwizzle;
+ }
TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
if (operandConstant == nullptr)
{