Low watch CVSS 6.5 chrome Uninitialized Memory 🔧 Commit mapped

Overview

Low
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUninitialized resource in GPU
DescriptionUninitialized resource in GPU
ComponentGPU
Sub-componentGPU
Bug ClassUninitialized Memory
Action tierwatch — information disclosure — security-relevant, below the RCE-class bar
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.
Tracker516864349
Fix commit5300747616b2 (chromium/src) +110/-9
CWECWE-908
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-05-26 (per vendor advisory)
Fix landed2026-07-21 (public git)
Disclosed2026-08-25
Patch gap35 days — fix public in source before the advisory

Background

`ValidateAndDoTexSubImage`
the GPU service (command-buffer) routine that validates and performs a glTexSubImage/glTexImage upload into a texture level on behalf of a GLES client.
Cleared/`SafeToRenderFrom` state
per-level tracking (via SetLevelCleared/SetLevelClearedRect and Texture::SafeToRenderFrom) recording that a texture level’s pixels are fully defined, so it may be sampled/rendered without leaking uninitialized memory.
`ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER` / `ERRORSTATE_PEEK_GL_ERROR`
macros that drain any pre-existing driver errors and then read back whether the just-issued GL call produced an error.

Root Cause Analysis

ValidateAndDoTexSubImage marked the destination level cleared before it issued the actual driver glTex(Sub)Image{2,3}D call — calling SetLevelCleared(...) (full image) or SetLevelClearedRect(...) (partial) — and never checked whether the upload succeeded. If the driver rejected the upload (e.g. returned GL_OUT_OF_MEMORY), no pixels were written, yet the level was already recorded as cleared, so Texture::SafeToRenderFrom() returned true for a level whose GPU memory was never initialized. Subsequent sampling or rendering then read uninitialized driver memory.

The fix defers committing the cleared state: it records intent in set_cleared/set_cleared_rect/cleared_rect_to_set, snapshots existing GL errors with ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER, performs the upload, and only calls SetLevelCleared/SetLevelClearedRect afterward when ERRORSTATE_PEEK_GL_ERROR(...) == GL_NO_ERROR. The return statements in the workaround branches were also converted to a uploaded flag so the post-upload error check always runs.

Key insight
The core mistake was committing the “level is cleared / safe to render” bookkeeping before and unconditionally of the driver upload, so a failed upload left uninitialized memory flagged as initialized; the fix moves the commit after the call and gates it on the driver reporting GL_NO_ERROR.

Attack Path

  1. Create an uncleared texture level Attacker-controlled GPU content allocates a texture level (e.g. glTexImage2D with a null data pointer) so its backing memory is uninitialized and SafeToRenderFrom() is false.
  2. Issue an upload that the driver will fail A TexSubImage2D/TexImage2D is issued under conditions that make the driver return an error such as GL_OUT_OF_MEMORY, so no pixels are actually written (modeled by the TexSubImage2DGLErrorDoesNotMarkLevelAsCleared regression test).
  3. Level wrongly marked cleared Pre-patch, ValidateAndDoTexSubImage had already called SetLevelCleared/SetLevelClearedRect, so the level is now considered fully (or partially) initialized despite the failed upload.
  4. Read uninitialized memory The attacker samples or renders from the level; because SafeToRenderFrom() reports safe, ANGLE skips its own clear, exposing leftover uninitialized GPU memory contents.

Impact Assessment

An attacker executing GLES commands from the renderer/GPU process can, by forcing a texture upload to fail at the driver, cause a texture level to be treated as initialized while its memory was never written, disclosing uninitialized GPU memory when the level is sampled. The advisory classifies this as an uninitialized-resource issue in GPU; exploited-in-the-wild status is not stated and any escalation beyond information disclosure is (inferred). Preconditions are the ability to submit texture uploads and to induce a driver-side error (e.g. out-of-memory) on the upload.

Changed Functions

FunctionChangeNotes
if
gpu/command_buffer/service/texture_manager.cc
modified
TEST_P
gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
modified

Files Changed

  • gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
  • gpu/command_buffer/service/texture_manager.cc

Audit Directions

  • Optimistic state commits before I/O
    Search for code that updates “initialized/cleared/valid” bookkeeping before the operation that actually produces the data, and confirm the commit is gated on success.
  • Unchecked driver call results
    Audit command-buffer paths that issue driver glTex*, glBufferData, glCopyTex* etc. without peeking the GL error afterward, especially where success implies a security-relevant state change (SafeToRenderFrom).
  • Early returns bypassing post-conditions
    Review functions with multiple return exits (workaround branches) to ensure they do not skip a mandatory post-operation validation or cleanup step.
From 5300747616b2910e05deb6fd0b936b51697eee63 Mon Sep 17 00:00:00 2001
From: Tzarial <[email protected]>
Date: Tue, 21 Jul 2026 06:15:38 -0700
Subject: [PATCH] [agy][gpu] Defer cleared state in TexSubImage

ValidateAndDoTexSubImage marked the destination level as cleared
before issuing the driver glTex(Sub)Image{2,3}D call and never
checked whether the upload succeeded. If the driver returned an
error, the level was left marked SafeToRenderFrom() even though no
pixels were written.

This CL defers the commit of the cleared state until after the
GL call succeeds, using ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER
and PEEK_GL_ERROR.

Fixed: 516864349
Test: gpu_unittests
Change-Id: I90dbaf1b04a44b1340b64d5cc20831f8b7e920a7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8108701
Commit-Queue: Tzarial <[email protected]>
Reviewed-by: Geoff Lang <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1665413}
---
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 5565b575..c8a45997 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -2876,6 +2876,9 @@
                                   &tex_height, &tex_depth);
   DCHECK(ok);
   bool full_image;
+  bool set_cleared = false;
+  bool set_cleared_rect = false;
+  gfx::Rect cleared_rect_to_set;
   if (args.xoffset != 0 || args.yoffset != 0 || args.zoffset != 0 ||
       args.width != tex_width || args.height != tex_height ||
       args.depth != tex_depth) {
@@ -2890,7 +2893,8 @@
                 texture->GetLevelClearedRect(args.target, args.level)
                     .size()
                     .GetArea());
-      SetLevelClearedRect(texture_ref, args.target, args.level, cleared_rect);
+      cleared_rect_to_set = cleared_rect;
+      set_cleared_rect = !texture->IsLevelCleared(args.target, args.level);
     } else {
       // Otherwise clear part of texture level that is not already cleared.
       if (!ClearTextureLevel(decoder, texture_ref, args.target, args.level)) {
@@ -2901,11 +2905,19 @@
     }
     full_image = false;
   } else {
-    SetLevelCleared(texture_ref, args.target, args.level, true);
+    set_cleared = !texture->IsLevelCleared(args.target, args.level);
     full_image = true;
   }
 
+  // Defer committing the cleared state until the driver upload succeeds.
+  // See https://crbug.com/516864349
+  const bool update_cleared_state = set_cleared || set_cleared_rect;
+  if (update_cleared_state) {
+    ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, function_name);
+  }
+
   Buffer* buffer = state->bound_pixel_unpack_buffer.get();
+  bool uploaded = false;
 
   if (texture_state->unpack_overlapping_rows_separately_unpack_buffer &&
       buffer) {
@@ -2922,31 +2934,34 @@
       // work around driver bug.
       DoTexSubImageRowByRowWorkaround(texture_state, state, args,
                                       unpack_params);
-      return;
+      uploaded = true;
     }
   }
 
-  if (texture_state->unpack_alignment_workaround_with_unpack_buffer && buffer &&
+  if (!uploaded &&
+      texture_state->unpack_alignment_workaround_with_unpack_buffer && buffer &&
       args.width && args.height && args.depth) {
     uint32_t buffer_size = static_cast<uint32_t>(buffer->size());
     if (buffer_size - args.pixels_size - ToGLuint(args.pixels) < args.padding) {
       TRACE_EVENT0("gpu", "WithAlignmentWorkaround");
       DoTexSubImageWithAlignmentWorkaround(texture_state, state, args);
-      return;
+      uploaded = true;
     }
   }
 
-  if (texture_state->split_level_0_pbo_full_sub_image_2d && args.level == 0 &&
-      buffer &&
+  if (!uploaded && texture_state->split_level_0_pbo_full_sub_image_2d &&
+      args.level == 0 && buffer &&
       args.command_type ==
           DoTexSubImageArguments::CommandType::kTexSubImage2D &&
       full_image && args.width > 0 && args.height > 0) {
     TRACE_EVENT0("gpu", "SplitLevel0PboFullSubImage2dWorkaround");
     DoTexSubImageSplitLevel0PboWorkaround(texture_state, state, args);
-    return;
+    uploaded = true;
   }
 
-  if (full_image && !texture->IsImmutable()) {
+  if (uploaded) {
+    // Upload was performed by one of the workarounds above.
+  } else if (full_image && !texture->IsImmutable()) {
     TRACE_EVENT0("gpu", "FullImage");
     GLenum internal_format;
     GLenum tex_type;
@@ -2984,6 +2999,16 @@
                       args.type, args.pixels);
     }
   }
+
+  if (update_cleared_state &&
+      ERRORSTATE_PEEK_GL_ERROR(error_state, function_name) == GL_NO_ERROR) {
+    if (set_cleared) {
+      SetLevelCleared(texture_ref, args.target, args.level, true);
+    } else if (set_cleared_rect) {
+      SetLevelClearedRect(texture_ref, args.target, args.level,
+                          cleared_rect_to_set);
+    }
+  }
 }
 
 void TextureManager::DoTexSubImageWithAlignmentWorkaround(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index 407f6b9f..aab63f97 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -594,6 +594,62 @@
       texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height, nullptr));
 }
 
+TEST_P(GLES2DecoderTest, TexSubImage2DGLErrorDoesNotMarkLevelAsCleared) {
+  DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+  DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0,
+               0);
+
+  TextureManager* manager = group().texture_manager();
+  TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+  ASSERT_TRUE(texture_ref != nullptr);
+  Texture* texture = texture_ref->texture();
+  EXPECT_FALSE(texture->SafeToRenderFrom());
+
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_OUT_OF_MEMORY))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA,
+                               GL_UNSIGNED_BYTE, shared_memory_address_.get()))
+      .Times(1)
+      .RetiresOnSaturation();
+  cmds::TexSubImage2D cmd;
+  cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE,
+           shared_memory_id_, kSharedMemoryOffset, GL_FALSE);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+  EXPECT_FALSE(texture->SafeToRenderFrom());
+}
+
+TEST_P(GLES2DecoderTest, TexSubImage2DGLErrorDoesNotExpandClearedRect) {
+  DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+  DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0,
+               0);
+
+  TextureManager* manager = group().texture_manager();
+  TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+  ASSERT_TRUE(texture_ref != nullptr);
+  Texture* texture = texture_ref->texture();
+  EXPECT_EQ(gfx::Rect(), texture->GetLevelClearedRect(GL_TEXTURE_2D, 0));
+
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_OUT_OF_MEMORY))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_,
+              TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA,
+                            GL_UNSIGNED_BYTE, shared_memory_address_.get()))
+      .Times(1)
+      .RetiresOnSaturation();
+  cmds::TexSubImage2D cmd;
+  cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+           shared_memory_id_, kSharedMemoryOffset, GL_FALSE);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+  EXPECT_EQ(gfx::Rect(), texture->GetLevelClearedRect(GL_TEXTURE_2D, 0));
+  EXPECT_FALSE(texture->SafeToRenderFrom());
+}
+
 TEST_P(GLES2DecoderTest, CopyTexImage2DGLError) {
   GLenum target = GL_TEXTURE_2D;
   GLint level = 0;
@@ -2634,6 +2690,10 @@
   SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
                                 GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
                                 GL_UNSIGNED_BYTE, 0, 1, 2, 1, 0);
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_,
               TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, 1, GL_RGBA,
                             GL_UNSIGNED_BYTE, shared_memory_address_.get()))
@@ -2694,6 +2754,10 @@
   SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
                                 GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
                                 GL_UNSIGNED_BYTE, 0, 1, 2, 1, 0);
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_,
               TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, 1, GL_RGBA,
                             GL_UNSIGNED_BYTE, shared_memory_address_.get()))
@@ -2722,6 +2786,10 @@
   DoBindBuffer(GL_PIXEL_UNPACK_BUFFER, client_buffer_id_, kServiceBufferId);
   DoBufferData(GL_PIXEL_UNPACK_BUFFER, 8);
 
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA,
                                   GL_UNSIGNED_BYTE, 0))
       .Times(1)
@@ -3478,6 +3546,10 @@
                GL_FLOAT,
                0,
                0);
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_, TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0,
                                GL_RGBA, GL_FLOAT, shared_memory_address_.get()))
       .Times(1)
@@ -3510,6 +3582,10 @@
   SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
                                 GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
                                 GL_FLOAT, 0, kHeight - 1, kWidth, 1, 0);
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, _, GL_RGBA,
                                   GL_FLOAT, shared_memory_address_.get()))
       .Times(2)
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index 407f6b9f..aab63f97 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -594,6 +594,62 @@
       texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height, nullptr));
 }
 
+TEST_P(GLES2DecoderTest, TexSubImage2DGLErrorDoesNotMarkLevelAsCleared) {
+  DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+  DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0,
+               0);
+
+  TextureManager* manager = group().texture_manager();
+  TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+  ASSERT_TRUE(texture_ref != nullptr);
+  Texture* texture = texture_ref->texture();
+  EXPECT_FALSE(texture->SafeToRenderFrom());
+
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_OUT_OF_MEMORY))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA,
+                               GL_UNSIGNED_BYTE, shared_memory_address_.get()))
+      .Times(1)
+      .RetiresOnSaturation();
+  cmds::TexSubImage2D cmd;
+  cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE,
+           shared_memory_id_, kSharedMemoryOffset, GL_FALSE);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+  EXPECT_FALSE(texture->SafeToRenderFrom());
+}
+
+TEST_P(GLES2DecoderTest, TexSubImage2DGLErrorDoesNotExpandClearedRect) {
+  DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+  DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0,
+               0);
+
+  TextureManager* manager = group().texture_manager();
+  TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+  ASSERT_TRUE(texture_ref != nullptr);
+  Texture* texture = texture_ref->texture();
+  EXPECT_EQ(gfx::Rect(), texture->GetLevelClearedRect(GL_TEXTURE_2D, 0));
+
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_OUT_OF_MEMORY))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_,
+              TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA,
+                            GL_UNSIGNED_BYTE, shared_memory_address_.get()))
+      .Times(1)
+      .RetiresOnSaturation();
+  cmds::TexSubImage2D cmd;
+  cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+           shared_memory_id_, kSharedMemoryOffset, GL_FALSE);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+  EXPECT_EQ(gfx::Rect(), texture->GetLevelClearedRect(GL_TEXTURE_2D, 0));
+  EXPECT_FALSE(texture->SafeToRenderFrom());
+}
+
 TEST_P(GLES2DecoderTest, CopyTexImage2DGLError) {
   GLenum target = GL_TEXTURE_2D;
   GLint level = 0;
@@ -2634,6 +2690,10 @@
   SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
                                 GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
                                 GL_UNSIGNED_BYTE, 0, 1, 2, 1, 0);
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_,
               TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, 1, GL_RGBA,
                             GL_UNSIGNED_BYTE, shared_memory_address_.get()))
@@ -2694,6 +2754,10 @@
   SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
                                 GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
                                 GL_UNSIGNED_BYTE, 0, 1, 2, 1, 0);
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_,
               TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, 1, GL_RGBA,
                             GL_UNSIGNED_BYTE, shared_memory_address_.get()))
@@ -2722,6 +2786,10 @@
   DoBindBuffer(GL_PIXEL_UNPACK_BUFFER, client_buffer_id_, kServiceBufferId);
   DoBufferData(GL_PIXEL_UNPACK_BUFFER, 8);
 
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA,
                                   GL_UNSIGNED_BYTE, 0))
       .Times(1)
@@ -3478,6 +3546,10 @@
                GL_FLOAT,
                0,
                0);
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_, TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0,
                                GL_RGBA, GL_FLOAT, shared_memory_address_.get()))
       .Times(1)
@@ -3510,6 +3582,10 @@
   SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
                                 GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
                                 GL_FLOAT, 0, kHeight - 1, kWidth, 1, 0);
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
   EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, _, GL_RGBA,
                                   GL_FLOAT, shared_memory_address_.get()))
       .Times(2)
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.