diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp index 75828189cd..97edf3ee7f 100644 --- a/src/compiler/translator/ParseContext.cpp +++ b/src/compiler/translator/ParseContext.cpp @@ -6750,6 +6750,37 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( new TVariable(&symbolTable, instanceName, interfaceBlockType, instanceName.empty() ? SymbolType::Empty : instanceSymbolType); + // Bandaid fix: enforce kWebGLMaxVariableSizeInBytes for interface blocks. + // addInterfaceBlock() creates the instance TVariable directly and never + // reaches declareVariable(), so the size check at line 2144 was structurally + // bypassed for UBOs. CalculateVariableSize() does not recurse into + // interface-block fields (only EbtStruct), so validate per-field here using + // the same gating as checkVariableSize(): WebGL only, vertex/fragment only, + // no prior errors. Each field is sized with std140 (the only layout WebGL + // permits for UBOs); a single oversized field is sufficient to reject. + if (mCompileOptions.rejectWebglShadersWithLargeVariables && numErrors() == 0 && + (mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER)) + { + angle::base::CheckedNumeric blockSize = 0; + for (const TField *field : *fieldList) + { + blockSize += CalculateVariableSize(field->type(), /*isStd140=*/true); + } + if (arraySizes != nullptr) + { + for (unsigned int dim : *arraySizes) + { + blockSize *= dim; + } + } + if (blockSize.ValueOrDefault(std::numeric_limits::max()) > + kWebGLMaxVariableSizeInBytes) + { + error(nameLine, "Size of declared variable exceeds implementation-defined limit", + instanceName.empty() ? blockName : instanceName); + } + } + checkVariableLocations(nameLine, instanceVariable); declareIRVariable(instanceVariable, sized);