High patch-now ~ plausible CVSS 8.8 chrome OOB 🔧 Commit mapped

Overview

High
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactBuffer overflow in ANGLE
DescriptionBuffer overflow in ANGLE
ComponentANGLE
Sub-componentTranslator
Bug ClassOOB
Action tierpatch-now — corruption primitive, web-reachable in default config (plausible) — upheld by independent review by AI
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Independent review by AIPlausible
Reviewer notes: Diff is a broad refactor (removes RegenerateStructNames); commit msg cites no security/overflow. Length-clamp in RenameAndDeclareStruct is present but the overflowed fixed-size sink is not shown; overflow/OOB-write primitive is inferred, not proven.
A second, independent AI reviewer (not a human) re-derived this analysis from the fixing commit and the vendor advisory, looking for errors.
Tracker529509587
Fix commit922804e75179 (angle/angle) +284/-936
CWECWE-122 (Heap buffer overflow)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-06-30 (per vendor advisory)
Fix landed2026-07-14 (public git)
Disclosed2026-08-25
Patch gapNot computed: several commits cite this bug and it is not yet established which one is the fix.

Background

ANGLE shader translator
the component that parses application GLSL/ESSL and re-emits it (GLSL/ESSL/HLSL/etc.) for the platform driver; it runs in the GPU process on WebGL-supplied shaders.
Struct name decoration
to keep names unique and consistent across shader stages, the translator rewrites a user struct’s name by appending a suffix (_0 for global structs, _<uniqueId> for function-local ones).
`kESSLMaxIdentifierLength`
the maximum identifier length ANGLE enforces for user identifiers; downstream code assumes identifiers do not exceed this bound.
`RegenerateStructNames`
the obsolete transformation this CL removes, which previously overwrote struct names with a unique prefix as a driver workaround.

Root Cause Analysis

Verify before building a PoC

This analysis is consistent with the fixing commit but not fully provable from it: part of the vulnerable path lives in code the fix commit does not touch. Confirm the trigger and the sink against the source before relying on it for exploit development.
What the commit does not establish: Diff is a broad refactor (removes RegenerateStructNames); commit msg cites no security/overflow. Length-clamp in RenameAndDeclareStruct is present but the overflowed fixed-size sink is not shown; overflow/OOB-write primitive is inferred, not proven.
When the translator renames a named struct it appends a uniqueness suffix to the struct’s name, but a user-supplied struct name may itself be as long as kESSLMaxIdentifierLength. Concatenating the suffix onto a name already at (or near) the maximum produced an identifier longer than kESSLMaxIdentifierLength, violating the invariant that decorated identifiers stay within that bound and overflowing a fixed-size buffer sized to it downstream (inferred sink, bug class buffer overflow). The new RenameAndDeclareStruct fixes this by reserving kAppendExtraChars (1 + 11, an underscore plus a 32-bit id) and truncating the base name to std::min(structure->name().length(), kESSLMaxIdentifierLength - kAppendExtraChars) before appending the suffix, guaranteeing the final name fits. The broader CL also reworks named-struct handling to always declare named structs globally and separately (prependPendingStructDeclarations, mGlobalNamedStructs/mFunctionLocalNamedStructs) and retires the regenerateStructNames option and its transformation, folding the safe renaming into parse. The change adds a length budget rather than relaxing any check.
Key insight
The single mistake was decorating a user-controlled struct name with a suffix without reserving room for it, letting the result exceed kESSLMaxIdentifierLength and overflow a fixed-size identifier buffer; the fix truncates the base name by kAppendExtraChars first so the decorated name is always in bounds.

Attack Path

  1. Craft an over-long struct name Author a GLSL/ESSL shader declaring a named struct whose name length is at or near kESSLMaxIdentifierLength.
  2. Submit via WebGL Compile the shader through a WebGL context so ANGLE’s translator processes it in the GPU process.
  3. Trigger decorated over-length name (pre-patch) The translator appends _0/_<uniqueId> to the already-maximal name, producing an identifier longer than kESSLMaxIdentifierLength.
  4. Buffer overflow The over-length name overruns a fixed-size buffer that assumed identifiers fit within the ESSL maximum (inferred), corresponding to the reported buffer overflow.

Impact Assessment

A crafted shader with a maximally-long named struct causes a buffer overflow in ANGLE’s shader translator, which runs in the GPU process. The precondition is a WebGL context able to submit such a shader. The vendor advisory rates this high severity and does not report in-the-wild exploitation; NVD scores it CVSS 8.8. Any escalation beyond the overflow itself is not demonstrated by the patch.

Files Changed

  • src/libANGLE/renderer/gl/ShaderGL.cpp
  • src/libANGLE/renderer/gl/renderergl_utils.cpp
  • include/platform/autogen/FeaturesGL_autogen.h
  • src/compiler/translator/Symbol.h
  • util/autogen/angle_features_autogen.cpp
  • src/compiler.gni
  • src/compiler/translator/tree_ops/SeparateDeclarations.cpp
  • src/compiler/translator/Compiler.cpp
  • src/compiler/translator/Types.h
  • src/tests/compiler_tests/RegenerateStructNames_test.cpp
  • src/tests/gl_tests/GLSLOutputTest.cpp
  • src/compiler/translator/glslang_tab_autogen.cpp
  • src/tests/compiler_tests/WGSLOutput_test.cpp
  • src/tests/compiler_tests/SeparateDeclarations_test.cpp
  • src/compiler/translator/ParseContext.h
  • util/autogen/angle_features_autogen.h
  • src/compiler/fuzz/translator_fuzzer.cpp
  • src/compiler/translator/tree_ops/SeparateDeclarations.h
  • src/tests/gl_tests/GLSLTest.cpp
  • src/tests/compiler_tests/CollectVariables_test.cpp
  • src/compiler/translator/tree_ops/glsl/RegenerateStructNames.h
  • include/platform/gl_features.json
  • src/compiler/translator/glslang.y
  • src/compiler/translator/ParseContext.cpp
  • scripts/code_generation_hashes/ANGLE_shader_translator.json
  • src/tests/compiler_tests/TypeTracking_test.cpp
  • src/compiler/translator/tree_ops/glsl/RegenerateStructNames.cpp
  • include/GLSLANG/ShaderLang.h
  • src/tests/angle_unittests.gni

Audit Directions

  • Identifier decoration without a length budget
    Review every place a prefix/suffix is appended to a user-controlled name to confirm a kESSLMaxIdentifierLength-aware reservation/truncation exists.
  • Fixed-size identifier buffers
    Audit translator/output code that sizes buffers to the ESSL max identifier length and assumes no name ever exceeds it after mangling.
  • Name mangling in other transforms
    Check uniform/mapped-name generation and other renaming passes for the same overflow when input names approach the maximum length.
From 922804e75179e45560959b935b5aebc895876fdf Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Wed, 08 Jul 2026 17:19:31 -0400
Subject: [PATCH] Translator: Always declare named structs globally

... and separately.  This is required for an upcoming AST transformation
that references structs in helper functions, even if it's locally
declared in the shader.

At the same time, this change makes the RegenerateStructNames
transformation obsolete and allows SeparateDeclarations to be
simplified.

Bug: chromium:529509587
Change-Id: I76d76b7fccb478e05eeb365a2b56ec85b4cd1e4c
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/8065288
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
---
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h
index 889423e..dd5bba9 100644
--- a/include/GLSLANG/ShaderLang.h
+++ b/include/GLSLANG/ShaderLang.h
@@ -26,7 +26,7 @@
 
 // Version number for shader translation API.
 // It is incremented every time the API changes.
-#define ANGLE_SH_VERSION 414
+#define ANGLE_SH_VERSION 415
 
 enum ShShaderSpec
 {
@@ -236,8 +236,7 @@
     // Linux/Mac driver bugs.
     uint64_t scalarizeVecAndMatConstructorArgs : 1;
 
-    // This flag overwrites a struct name with a unique prefix.  It is intended as a workaround for
-    // drivers that do not handle struct scopes correctly, including all Mac drivers and Linux AMD.
+    // This flag is a no-op and will be removed once chromium code no longer references it.
     uint64_t regenerateStructNames : 1;
 
     // This flag works around a bug in the HLSL compiler optimizer that folds certain constant pow
diff --git a/include/platform/gl_features.json b/include/platform/gl_features.json
index 79e0837..f035663 100644
--- a/include/platform/gl_features.json
+++ b/include/platform/gl_features.json
@@ -387,15 +387,6 @@
             "issue": "http://crbug.com/642605"
         },
         {
-            "name": "regenerate_struct_names",
-            "category": "Workarounds",
-            "description": [
-                "All Mac drivers do not handle struct scopes correctly. This workaround overwrites a struct",
-                "name with a unique prefix."
-            ],
-            "issue": "http://crbug.com/403957"
-        },
-        {
             "name": "read_pixels_using_implementation_color_read_format_for_norm16",
             "category": "Workarounds",
             "description": [
diff --git a/scripts/code_generation_hashes/ANGLE_shader_translator.json b/scripts/code_generation_hashes/ANGLE_shader_translator.json
index be7aefc..39548fa 100644
--- a/scripts/code_generation_hashes/ANGLE_shader_translator.json
+++ b/scripts/code_generation_hashes/ANGLE_shader_translator.json
@@ -6,11 +6,11 @@
   "src/compiler/translator/glslang.l":
     "aa7542c5cad1b9476b76426958b58d61",
   "src/compiler/translator/glslang.y":
-    "06a935b7c9568df4de1de4cce95e668c",
+    "6c4f0838296500f96a99e2e0b0715529",
   "src/compiler/translator/glslang_lex_autogen.cpp":
     "93a9f8320f1ff165d2b31d9e8add91c3",
   "src/compiler/translator/glslang_tab_autogen.cpp":
-    "c9d45a90f418dc0f0d58a11a94951414",
+    "86d84b555871d272c2618e3c645c7dae",
   "src/compiler/translator/glslang_tab_autogen.h":
     "f1c4d0111ce0d8977503b38c9b7b23df",
   "tools/flex-bison/linux/bison.sha1":
diff --git a/src/compiler/fuzz/translator_fuzzer.cpp b/src/compiler/fuzz/translator_fuzzer.cpp
index 694bd6a..428fc56 100644
--- a/src/compiler/fuzz/translator_fuzzer.cpp
+++ b/src/compiler/fuzz/translator_fuzzer.cpp
@@ -100,10 +100,10 @@
 
     if (!IsOutputGLSL(shaderOutput) && !IsOutputESSL(shaderOutput))
     {
-        hasUnsupportedOptions =
-            hasUnsupportedOptions || options.emulateAtan2FloatFunction || options.clampFragDepth ||
-            options.regenerateStructNames || options.rewriteRepeatedAssignToSwizzled ||
-            options.useUnusedStandardSharedBlocks || options.selectViewInNvGLSLVertexShader;
+        hasUnsupportedOptions = hasUnsupportedOptions || options.emulateAtan2FloatFunction ||
+                                options.clampFragDepth || options.rewriteRepeatedAssignToSwizzled ||
+                                options.useUnusedStandardSharedBlocks ||
+                                options.selectViewInNvGLSLVertexShader;
 
         hasUnsupportedOptions = hasUnsupportedOptions || hasMacGLSLOptions;
     }
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index eb1d646..5a6c5e8 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -44,7 +44,6 @@
 #include "compiler/translator/tree_ops/SeparateDeclarations.h"
 #include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
 #include "compiler/translator/tree_ops/SplitSequenceOperator.h"
-#include "compiler/translator/tree_ops/glsl/RegenerateStructNames.h"
 #include "compiler/translator/tree_ops/glsl/RewriteRepeatedAssignToSwizzled.h"
 #include "compiler/translator/tree_ops/glsl/UseInterfaceBlockFields.h"
 #include "compiler/translator/tree_ops/glsl/apple/AddAndTrueToLoopCondition.h"
@@ -908,14 +907,6 @@
         }
     }
 
-    if (compileOptions.regenerateStructNames)
-    {
-        if (!RegenerateStructNames(this, root, &mSymbolTable))
-        {
-            return false;
-        }
-    }
-
     if (compileOptions.emulateGLDrawID &&
         IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_multi_draw))
     {
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index e9198ba..dff5a36 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -24,6 +24,7 @@
 #include "common/utilities.h"
 #include "compiler/preprocessor/SourceLocation.h"
 #include "compiler/translator/Declarator.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
 #include "compiler/translator/ValidateGlobalInitializer.h"
 #include "compiler/translator/glslang.h"
 #include "compiler/translator/tree_util/BuiltIn.h"
@@ -459,6 +460,44 @@
             return 0;
     }
 }
+
+enum class StructureOriginalScope
+{
+    Global,
+    FunctionLocal,
+};
+
+TIntermDeclaration *RenameAndDeclareStruct(TSymbolTable *symbolTable,
+                                           TStructure *structure,
+                                           StructureOriginalScope scope)
+{
+    ASSERT(!structure->name().empty());
+
+    // We need +2 space for _0 if global, or +11 for "_uniqueId" if function-local.  Using +11
+    // always for simplicity.  +1 for the NUL terminator.
+    //
+    // If appending ID and the name is too long, cut off the end of the name.  The ID makes it
+    // unique.
+    constexpr uint32_t kAppendExtraChars = 1 + 11;  // underscore + 32-bit number
+    const ImmutableString name(
+        structure->name().data(),
+        std::min<size_t>(structure->name().length(), kESSLMaxIdentifierLength - kAppendExtraChars));
+
+    ImmutableStringBuilder builder(structure->name().length() + kAppendExtraChars);
+    builder << name << "_"
+            << (scope == StructureOriginalScope::Global ? 0 : structure->uniqueId().get());
+    structure->setName(builder);
+
+    TType *namedType = new TType(structure, true);
+    namedType->setQualifier(EvqGlobal);
+
+    TVariable *structVariable =
+        new TVariable(symbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
+    TIntermSymbol *structDeclarator       = new TIntermSymbol(structVariable);
+    TIntermDeclaration *structDeclaration = new TIntermDeclaration;
+    structDeclaration->appendDeclarator(structDeclarator);
+    return structDeclaration;
+}
 }  // namespace
 
 // This tracks each binding point's current default offset for inheritance of subsequent
@@ -6323,7 +6362,7 @@
         error(publicType.getLine(), "array constructor supported in GLSL ES 3.00 and above only",
               "[]");
     }
-    if (publicType.isStructSpecifier())
+    if (publicType.isStructSpecifierForValidation())
     {
         error(publicType.getLine(), "constructor can't be a structure definition",
               getBasicString(publicType.getBasicType()));
@@ -6362,7 +6401,7 @@
             error(nameLoc, "illegal use of type 'void'", name);
         }
     }
-    if (type.isStructSpecifier())
+    if (type.isStructSpecifierForValidation())
     {
         // ESSL 3.00.6 section 12.10.
         error(nameLoc, "Function parameter type cannot be a structure definition", name);
@@ -8430,7 +8469,8 @@
                                                    TFieldList *fieldList)
 {
     SymbolType structSymbolType = SymbolType::UserDefined;
-    if (structName.empty())
+    const bool isNamelessStruct = structName.empty();
+    if (isNamelessStruct)
     {
         structSymbolType = SymbolType::Empty;
     }
@@ -8539,10 +8579,24 @@
             angle::Span<const TField *const>(reorderedFields->data(), reorderedFields->size())),
         {}, false, false, symbolTable.atGlobalLevel());
 
+    // Nameless structs are declared inline with their variables.  But named structs are always
+    // separately declared at the end of parse.
     TTypeSpecifierNonArray typeSpecifierNonArray;
-    typeSpecifierNonArray.initializeStruct(structure, true, structLine);
+    typeSpecifierNonArray.initializeStruct(structure, isNamelessStruct, true, structLine);
     exitStructDeclaration();
 
+    if (!isNamelessStruct)
+    {
+        if (symbolTable.atGlobalLevel())
+        {
+            mGlobalNamedStructs.push_back(structure);
+        }
+        else
+        {
+            mFunctionLocalNamedStructs.push_back(structure);
+        }
+    }
+
     return typeSpecifierNonArray;
 }
 
@@ -10243,6 +10297,39 @@
     }
 }
 
+void TParseContext::prependPendingStructDeclarations()
+{
+    TIntermSequence allStructDecls;
+
+    // Do the following for all structs:
+    //
+    // * First, modify the name of the struct.  This breaks the symbol table, as names cannot be
+    //   looked up anymore, but that's ok because this is the end of parse and no transformation
+    //   looks up user symbol names anymore.  The struct names are used during link to match
+    //   uniforms, and so for global structs, the name is suffixed by |_0| to be identical between
+    //   shader stages.  For function-local structs it's suffixed by |_uniqueId|
+    // * Then, create a global declarator for the struct and append it to the list of declarations.
+    //
+    // The whole list is prepended to the shader at the end.  Global structs are declared first, as
+    // they may be used by function-local structs.  Within global or function-local structs, they
+    // are declared in the order they are encountered in the shader for the same reason.
+
+    for (TStructure *structure : mGlobalNamedStructs)
+    {
+        allStructDecls.push_back(
+            RenameAndDeclareStruct(&symbolTable, structure, StructureOriginalScope::Global));
+    }
+
+    for (TStructure *structure : mFunctionLocalNamedStructs)
+    {
+        allStructDecls.push_back(
+            RenameAndDeclareStruct(&symbolTable, structure, StructureOriginalScope::FunctionLocal));
+    }
+
+    mTreeRoot->getSequence()->insert(mTreeRoot->getSequence()->begin(), allStructDecls.begin(),
+                                     allStructDecls.end());
+}
+
 void TParseContext::checkCallGraph()
 {
     // Verify that the call graph does not contain a loop.
@@ -10537,6 +10624,12 @@
     ASSERT(!mCompileOptions.useIR || mTreeRoot != nullptr);
 #endif
 
+    // Struct declarations are delayed to the end of parse, add them to the AST now
+    if (mTreeRoot != nullptr)
+    {
+        prependPendingStructDeclarations();
+    }
+
     // If gl_Position is expected to be zero-initialized, make sure it's declared to the IR; it
     // should still be done if gl_Position is statically not used by the shader.
     if (mCompileOptions.initGLPosition)
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index a23a99e..3d62dfa 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -764,6 +764,8 @@
     void checkVariableLocations(const TSourceLoc &line, const TVariable *variable);
     void postParseValidateFragmentOutputLocations();
 
+    void prependPendingStructDeclarations();
+
     void sizeUnsizedArrayTypes(uint32_t arraySize);
 
     enum class ControlFlowType
@@ -972,6 +974,13 @@
     // Potential errors to generate immediately upon encountering a pixel local storage uniform.
     std::vector<std::tuple<const TSourceLoc, PLSIllegalOperations>> mPLSPotentialErrors;
 
+    // Some transformations might need to create helper functions that reference a function local
+    // struct.  For this reason, local structs are promoted to global scope.  To avoid naming
+    // collisions, global structs are suffixed by |_0| and function-local structs are suffixed by
+    // |_uniqueId|.
+    TVector<TStructure *> mGlobalNamedStructs;
+    TVector<TStructure *> mFunctionLocalNamedStructs;
+
     // Track the locations used by input and output varyings to detect conflicts.
     LocationValidationMap mInputVaryingLocations;
     LocationValidationMap mOutputVaryingLocations;
diff --git a/src/compiler/translator/Symbol.h b/src/compiler/translator/Symbol.h
index bd77f29..4ba18b6 100644
--- a/src/compiler/translator/Symbol.h
+++ b/src/compiler/translator/Symbol.h
@@ -183,6 +183,10 @@
     void setAtGlobalScope(bool atGlobalScope) { mAtGlobalScope = atGlobalScope; }
     bool atGlobalScope() const { return mAtGlobalScope; }
 
+    // This function is temporary while transition to IR is happening.  It allows the AST to promote
+    // structs to the global scope at the end of parse.  Do not use.
+    void setName(const ImmutableString &name);
+
   private:
     friend class TSymbolTable;
     // For creating built-in structs.
@@ -207,12 +211,6 @@
           TFieldListCollection(fields)
     {}
 
-    // TODO(zmo): Find a way to get rid of the const_cast in function
-    // setName().  At the moment keep this function private so only
-    // friend class RegenerateStructNames may call it.
-    friend class RegenerateStructNamesTraverser;
-    void setName(const ImmutableString &name);
-
     bool mAtGlobalScope;
 };
 
diff --git a/src/compiler/translator/Types.h b/src/compiler/translator/Types.h
index b3e6950..c447d17 100644
--- a/src/compiler/translator/Types.h
+++ b/src/compiler/translator/Types.h
@@ -435,7 +435,12 @@
     TSourceLoc line;
 
     // true if the type was defined by a struct specifier rather than a reference to a type name.
+    // Some structs may be hoisted out to be declared separately during parse and would have
+    // |isStructSpecifier == false|.  However, validation may still need to know if there was a
+    // struct defined in an invalid location, so |isStructSpecifierForValidation| would be true even
+    // if the type itself is no longer expected to declare the struct.
     bool isStructSpecifier;
+    bool isStructSpecifierForValidation;
 
     void initialize(TBasicType aType, const TSourceLoc &aLine)
     {
@@ -446,18 +451,22 @@
         userDef           = nullptr;
         line              = aLine;
         isStructSpecifier = false;
+        isStructSpecifierForValidation = false;
     }
 
     void initializeStruct(const TStructure *aUserDef,
                           bool aIsStructSpecifier,
+                          bool aIsStructSpecifierForValidation,
                           const TSourceLoc &aLine)
     {
+        ASSERT(!aIsStructSpecifier || aIsStructSpecifierForValidation);
         type              = EbtStruct;
         primarySize       = 1;
         secondarySize     = 1;
         userDef           = aUserDef;
         line              = aLine;
         isStructSpecifier = aIsStructSpecifier;
+        isStructSpecifierForValidation = aIsStructSpecifierForValidation;
     }
 
     void setAggregate(uint8_t size) { primarySize = size; }
@@ -500,6 +509,10 @@
     const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; }
 
     bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; }
+    bool isStructSpecifierForValidation() const
+    {
+        return typeSpecifierNonArray.isStructSpecifierForValidation;
+    }
 
     bool isStructureContainingArrays() const;
     bool isStructureContainingType(TBasicType t) const;
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index 560bade..8bba5d4 100644
--- a/src/compiler/translator/glslang.y
... (file diff truncated)
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/src/tests/angle_unittests.gni b/src/tests/angle_unittests.gni
index 628f197..b17edfa 100644
--- a/src/tests/angle_unittests.gni
+++ b/src/tests/angle_unittests.gni
@@ -108,10 +108,8 @@
   "compiler_tests/QualificationOrderESSL31_test.cpp",
   "compiler_tests/QualificationOrder_test.cpp",
   "compiler_tests/RecordConstantPrecision_test.cpp",
-  "compiler_tests/RegenerateStructNames_test.cpp",
   "compiler_tests/RemoveUnreferencedVariables_test.cpp",
   "compiler_tests/SamplerMultisample_test.cpp",
-  "compiler_tests/SeparateDeclarations_test.cpp",
   "compiler_tests/ShCompile_test.cpp",
   "compiler_tests/ShaderValidation_test.cpp",
   "compiler_tests/ShaderVariable_test.cpp",
diff --git a/src/tests/compiler_tests/CollectVariables_test.cpp b/src/tests/compiler_tests/CollectVariables_test.cpp
index b8e879f..18600ad 100644
--- a/src/tests/compiler_tests/CollectVariables_test.cpp
+++ b/src/tests/compiler_tests/CollectVariables_test.cpp
@@ -872,7 +872,7 @@
     EXPECT_FALSE(uniform.isArray());
     EXPECT_EQ("u", uniform.name);
     EXPECT_EQ("webgl_1", uniform.mappedName);
-    EXPECT_EQ("sType", uniform.structOrBlockName);
+    EXPECT_EQ("sType_0", uniform.structOrBlockName);
     EXPECT_TRUE(uniform.staticUse);
     EXPECT_TRUE(uniform.active);
diff --git a/src/tests/compiler_tests/RegenerateStructNames_test.cpp b/src/tests/compiler_tests/RegenerateStructNames_test.cpp
deleted file mode 100644
index 8f873e7..0000000
--- a/src/tests/compiler_tests/RegenerateStructNames_test.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-// Copyright 2017 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// RegenerateStructNames_test.cpp:
-//   Tests for regenerating struct names.
-//
-
-#include "GLSLANG/ShaderLang.h"
-#include "angle_gl.h"
-#include "gtest/gtest.h"
-#include "tests/test_utils/compiler_test.h"
-
-using namespace sh;
-
-class RegenerateStructNamesTest : public MatchOutputCodeTest
-{
-  public:
-    RegenerateStructNamesTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_ESSL_OUTPUT)
-    {
-        ShCompileOptions defaultCompileOptions      = {};
-        defaultCompileOptions.regenerateStructNames = true;
-        setDefaultCompileOptions(defaultCompileOptions);
-    }
-};
-
-// Test that a struct defined in a function scope is renamed. The global struct that's used as a
-// type of a uniform cannot be renamed.
-TEST_F(RegenerateStructNamesTest, GlobalStructAndLocalStructWithTheSameName)
-{
-    const std::string &shaderString =
-        R"(precision mediump float;
-
-        struct myStruct
-        {
-            float foo;
-        };
-
-        uniform myStruct us;
-
-        void main()
-        {
-            struct myStruct
-            {
-                vec2 bar;
-            };
-            myStruct scoped;
-            scoped.bar = vec2(1.0, 2.0) * us.foo;
-            gl_FragColor = vec4(scoped.bar, 0.0, 1.0);
-        })";
-    compile(shaderString);
-    EXPECT_TRUE(foundInCode("struct _umyStruct"));
-    EXPECT_TRUE(foundInCode("struct _u_webgl_struct_"));
-}
-
-// Test that a nameless struct is handled gracefully.
-TEST_F(RegenerateStructNamesTest, NamelessStruct)
-{
-    const std::string &shaderString =
-        R"(precision mediump float;
-
-        uniform float u;
-
-        void main()
-        {
-            struct
-            {
-                vec2 bar;
-            } scoped;
-            scoped.bar = vec2(1.0, 2.0) * u;
-            gl_FragColor = vec4(scoped.bar, 0.0, 1.0);
-        })";
-    compile(shaderString);
-    EXPECT_TRUE(foundInCode("struct"));
-}
diff --git a/src/tests/compiler_tests/SeparateDeclarations_test.cpp b/src/tests/compiler_tests/SeparateDeclarations_test.cpp
deleted file mode 100644
index 01fb3f6..0000000
--- a/src/tests/compiler_tests/SeparateDeclarations_test.cpp
+++ /dev/null
@@ -1,419 +0,0 @@
-//
-// Copyright 2024 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// SeparateDeclarations.cpp:
-//   Tests that compound declarations are rewritten to type declarations and variable declarations.
-//
-
-#include "GLSLANG/ShaderLang.h"
-#include "angle_gl.h"
-#include "gtest/gtest.h"
-#include "tests/test_utils/compiler_test.h"
-
-using namespace sh;
-
-namespace
-{
-
-class SeparateDeclarations : public MatchOutputCodeTest
-{
-  public:
-    SeparateDeclarations() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_ESSL_OUTPUT)
-    {
-        ShCompileOptions defaultCompileOptions = {};
-        defaultCompileOptions.validateAST      = true;
-        setDefaultCompileOptions(defaultCompileOptions);
-    }
-};
-
-class SeparateCompoundStructDeclarations : public MatchOutputCodeTest
-{
-  public:
-    SeparateCompoundStructDeclarations() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_ESSL_OUTPUT)
-    {
-        ShCompileOptions defaultCompileOptions                   = {};
-        defaultCompileOptions.validateAST                        = true;
-        defaultCompileOptions.separateCompoundStructDeclarations = true;
-        setDefaultCompileOptions(defaultCompileOptions);
-    }
-};
-
-class SeparateStructFunctionDeclarations : public MatchOutputCodeTest
-{
-  public:
-    SeparateStructFunctionDeclarations() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_ESSL_OUTPUT)
-    {
-        ShCompileOptions defaultCompileOptions = {};
-        defaultCompileOptions.validateAST      = true;
-        setDefaultCompileOptions(defaultCompileOptions);
-    }
-};
-
-TEST_F(SeparateDeclarations, Arrays)
-{
-    const char kShader[]   = R"(#version 300 es
-precision highp float;
-int a[1] = int[1](1), b[1] = int[1](2);
-out vec4 o;
-void main() {
-    if (a[0] == b[0])
-        o = vec4(1);
-})";
-    const char kExpected[] = R"(#version 300 es
-const mediump int sbbd = 1;
-mediump int _ua[1] = int[1](sbbd);
-const mediump int sbbe = 2;
-mediump int _ub[1] = int[1](sbbe);
-out highp vec4 _uo;
-void main(){
-  if ((_ua[0] == _ub[0]))
-  {
-    (_uo = vec4(1.0, 1.0, 1.0, 1.0));
-  }
-}
-)";
-    compile(kShader);
-    EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
-}
-
-TEST_F(SeparateDeclarations, StructNoChange)
-{
-    const char kShader[]   = R"(#version 300 es
-precision highp float;
-struct S { vec3 d; } a;
-out vec4 o;
-void main() {
-    if (a.d == vec3(2))
-        o = vec4(1);
-})";
-    const char kExpected[] = R"(#version 300 es
-struct _uS {
-  highp vec3 _ud;
-} _ua;
-out highp vec4 _uo;
-void main(){
-  if ((_ua._ud == vec3(2.0, 2.0, 2.0)))
-  {
-    (_uo = vec4(1.0, 1.0, 1.0, 1.0));
-  }
-}
-)";
-    compile(kShader);
-    EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
-}
-
-TEST_F(SeparateDeclarations, Structs)
-{
-    const char kShader[]   = R"(#version 300 es
-precision highp float;
-struct S { vec3 d; } a, b;
-out vec4 o;
-void main() {
-    if (a.d == b.d)
-        o = vec4(1);
-})";
-    const char kExpected[] = R"(#version 300 es
-struct _uS {
-  highp vec3 _ud;
-} _ua;
-_uS _ub;
-out highp vec4 _uo;
-void main(){
-  if ((_ua._ud == _ub._ud))
-  {
-    (_uo = vec4(1.0, 1.0, 1.0, 1.0));
-  }
-}
-)";
-    compile(kShader);
-    EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
-}
-
-TEST_F(SeparateDeclarations, AnonymousStructNoChange)
-{
-    const char kShader[]   = R"(#version 300 es
-precision highp float;
-struct { vec3 d; } a;
-out vec4 o;
-void main() {
-    if (any(lessThan(a.d, vec3(2))))
-        o = vec4(1);
-})";
-    const char kExpected[] = R"(#version 300 es
-struct {
-  highp vec3 _ud;
-} _ua;
-out highp vec4 _uo;
-void main(){
-  if (any(lessThan(_ua._ud, vec3(2.0, 2.0, 2.0))))
-  {
-    (_uo = vec4(1.0, 1.0, 1.0, 1.0));
-  }
-}
-)";
-    compile(kShader);
-    EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
-}
-
-TEST_F(SeparateDeclarations, AnonymousStructs)
-{
-    const char kShader[]   = R"(#version 300 es
-precision highp float;
-struct { vec3 d; } a, b;
-out vec4 o;
-void main() {
-    if (any(lessThan(a.d, b.d)))
-        o = vec4(1);
-})";
-    const char kExpected[] = R"(#version 300 es
-struct {
-  highp vec3 _ud;
-} _ua;
-struct {
-  highp vec3 _ud;
-} _ub;
-out highp vec4 _uo;
-void main(){
-  if (any(lessThan(_ua._ud, _ub._ud)))
-  {
-    (_uo = vec4(1.0, 1.0, 1.0, 1.0));
-  }
-}
-)";
-    compile(kShader);
... (truncated)
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.