Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactOut of bounds read in ANGLE
DescriptionOut of bounds read in ANGLE
ComponentANGLE
Bug ClassOOB
Tracker513468021
Fix commit8c8f35f183d9 (angle/angle) +8/-4
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Files Changed

  • src/compiler/translator/Types.cpp
From 8c8f35f183d9d248c4b4ee84323512f5000c8494 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <[email protected]>
Date: Wed, 20 May 2026 16:16:56 -0400
Subject: [PATCH] Translator: Don't cap object sizes to INT_MAX

The calculations are done in size_t, so the cap is changed to size_t's
MAX value instead.

Fixes a crash if a _very_ big struct is declared, but used only in a way
that's constant folded.  The test itself is impossible to put in the CQ
due to its long execution time.

Bug: chromium:513468021
Change-Id: Ia378f915ed509ce52162153054229cc22a9a91af
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7865643
Commit-Queue: Shahbaz Youssefi <[email protected]>
Reviewed-by: Geoff Lang <[email protected]>
---

diff --git a/src/compiler/translator/Types.cpp b/src/compiler/translator/Types.cpp
index a3564df..42ccdcc 100644
--- a/src/compiler/translator/Types.cpp
+++ b/src/compiler/translator/Types.cpp
@@ -517,8 +517,10 @@
 
     for (size_t arraySize : mArraySizes)
     {
-        if (arraySize > INT_MAX / totalSize)
-            totalSize = INT_MAX;
+        if (arraySize > std::numeric_limits<size_t>::max() / totalSize)
+        {
+            totalSize = std::numeric_limits<size_t>::max();
+        }
         else
             totalSize *= arraySize;
     }
@@ -877,8 +879,10 @@
     for (const TField *field : *mFields)
     {
         size_t fieldSize = field->type()->getObjectSize();
-        if (fieldSize > INT_MAX - size)
-            size = INT_MAX;
+        if (fieldSize > std::numeric_limits<size_t>::max() - size)
+        {
+            size = std::numeric_limits<size_t>::max();
+        }
         else
             size += fieldSize;
     }
Loading diff…

Original Bug Report

reported by [email protected]

Out-of-Bounds Read in ANGLE Constant Folding due to Size Calculation Inconsistency

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A potential inconsistency between how structure sizes are clamped and how field offsets are calculated in the ANGLE compiler could lead to an out-of-bounds read. This issue could allow a crafted shader to leak memory from the GPU process heap into the translated shader source.

Affected files:

  • third_party/angle/src/compiler/translator/IntermNode.cpp
  • third_party/angle/src/compiler/translator/Types.cpp

Estimated timestamp from git blame: 2013-07-30

A potential out-of-bounds (OOB) read vulnerability exists in the ANGLE compiler’s constant folding implementation. The issue stems from a discrepancy between the clamping logic used during structure size calculation and the logic used to compute field offsets during constant folding of structure indexing.

Root Cause Analysis

In third_party/angle/src/compiler/translator/Types.cpp, the method TFieldListCollection::calculateObjectSize() calculates the total size (in elements) of a structure and saturates the result at INT_MAX if it exceeds that limit:

size_t TFieldListCollection::calculateObjectSize() const {
    size_t size = 0;
    for (const TField *field : *mFields) {
        size_t fieldSize = field->type()->getObjectSize();
        if (fieldSize > INT_MAX - size)
            size = INT_MAX; // Saturated clamp
        else
            size += fieldSize;
    }
    return size;
}

This clamped size is used to allocate the buffer for constant folding in TIntermAggregate::getConstantValue(). However, when constant-folding a field access (EOpIndexDirectStruct), the offset into this buffer is calculated in TIntermBinary::getConstantValue() (IntermNode.cpp) by summing the sizes of all preceding fields using size_t arithmetic without the same clamping logic:

// third_party/angle/src/compiler/translator/IntermNode.cpp
size_t previousFieldsSize = 0;
for (int i = 0; i < index; ++i)
    previousFieldsSize += fields[i]->type()->getObjectSize(); // Un-clamped summation
constIndexingResult = leftConstantValue + previousFieldsSize; // Potential OOB pointer

On 64-bit systems, previousFieldsSize can exceed INT_MAX, causing constIndexingResult to point beyond the allocated TConstantUnion array. Although ANGLE generally restricts constant folding to types with 16 or fewer components, this inconsistency represents a potential bypass if large objects are incorrectly permitted to fold or if specific internal invariants are violated.

Potential Exploitation Path

An attacker could attempt to trigger this by defining a shader with nested structures that exceed the INT_MAX element limit. By using an inline constructor and accessing a trailing field, the attacker may reach the vulnerable offset calculation. If the indexing operation is folded, the resulting leaked heap memory from the GPU process would be embedded as a literal in the translated shader source, which can be retrieved via the WEBGL_debug_shaders extension or by reading back rendered pixels.

Suggested Fix

Ensure that all offset calculations in the constant folder use the same saturated arithmetic or explicit overflow checks as the size calculation. Specifically, in TIntermBinary::getConstantValue, the summation of previousFieldsSize should be checked against the allocated size of the left-hand side constant buffer.

Note: These are potential steps based on code analysis; our current environment does not support executing a proof of concept.

Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker