CVE-2026-79282
Overview
Background
- ANGLE
- Almost Native Graphics Layer Engine, Chrome’s translation layer that maps
WebGL/OpenGL EScalls onto native drivers (here, the GL backend insrc/libANGLE/renderer/gl). - PBO
- Pixel Buffer Object, a GPU-side buffer bound to
GL_PIXEL_UNPACK_BUFFER; when bound, thepixelsargument toglTexSubImage2Dis a byte offset into that buffer instead of a client pointer. - `TextureGL::setSubImage`
- the GL-backend path that services
glTexSubImage2D-style uploads, including the fast path that hands the entire region to the native driver in one call. - `splitLevel0PboFullSubImage2D`
- a newly added
PowerVR-only ANGLE feature flag that, when enabled, forces full-level-0 PBO uploads to a 2D texture to be split into two smaller driver calls.
Root Cause Analysis
On Imagination (PowerVR) drivers, a single glTexSubImage2D that uploads the entire level 0 of a 2D texture sourced from a bound PBO takes a driver-internal fast path that miscomputes the bounds of the transfer, reading or writing past the intended region of the mapped PBO or texture storage. Because the source of the copy is a PBO that ANGLE manages, the driver’s out-of-bounds access lands against the transfer buffer, producing a use-after-free / OOB condition inside driver-controlled memory. ANGLE previously issued exactly this full-image PBO upload as one call whenever the region matched the full mip level, directly triggering the buggy path.
The fix detects the full-image, level-0, PBO-backed, UseTexImage2D case and, when features.splitLevel0PboFullSubImage2D.enabled, reroutes it through setSubImageRowByRowWorkaround, which uploads everything except the final line/pixel and then the final line/pixel as a separate call. Splitting the upload keeps the driver off its buggy monolithic fast path, so no access exceeds the intended bounds. The reused helper was enhanced to handle height-1 uploads so that the trailing-remainder call is well-formed even for single-row images.
Attack Path
- Reach ANGLE from the web
A page uses
WebGLon a device with an Imagination/PowerVRGPU, so texture uploads route through ANGLE’s GL backend. - Bind a PBO
Script binds a pixel unpack buffer and issues
texSubImage2D/texImage2Dfor level 0 of a 2D texture with the region covering the entire mip level. - Trigger the fast path
ANGLE forwards the full-image PBO upload as a single
glTexSubImage2D, and the driver enters the buggy path that reads/writes past the transfer buffer. - Corrupt driver memory The out-of-bounds access against the freed/mapped PBO-backed storage yields a use-after-free, which a crafted sequence of allocations can shape.
- Escalate Controlled corruption of driver/GPU-process memory is leveraged toward information disclosure or code execution in the GPU process.
Impact Assessment
PowerVR/Imagination drivers, matching the PowerVR-scoped feature flag.Changed Functions
| Function | Change | Notes |
|---|---|---|
Texture2DTestES3PBOsrc/tests/gl_tests/TextureTest.cpp |
modified | |
Texture2DTestES3Foveationsrc/tests/gl_tests/TextureTest.cpp |
modified |
Files Changed
src/tests/gl_tests/TextureTest.cppsrc/libANGLE/renderer/gl/renderergl_utils_unittest.cpputil/autogen/angle_features_autogen.hsrc/libANGLE/renderer/gl/renderergl_utils.cppinclude/platform/autogen/FeaturesGL_autogen.hutil/autogen/angle_features_autogen.cppsrc/libANGLE/renderer/gl/TextureGL.cppsrc/libANGLE/renderer/gl/renderergl_utils.hsrc/tests/angle_unittests.gniinclude/platform/gl_features.json
Audit Directions
- Driver fast-path avoidanceAudit other ANGLE upload/download paths (
texImage,copyTexSubImage, compressed uploads, 3D/array textures) where a single full-region PBO transfer is handed to the native driver, since analogous monolithic fast paths onPowerVRmay miscompute bounds. - Boundary sizes in split helpersReview
setSubImageRowByRowWorkaroundand similar chunking helpers for correctness at edge dimensions (height-1, width-1, single-pixel), where remainder/last-line arithmetic androwBytescomputation are easiest to get wrong. - Feature-gate coverageVerify the
isFullImage,level == 0,unpackBuffer, andnativegl::UseTexImage2D(getType())conditions actually cover every way a full-level-0 2D PBO upload can reach the driver, so no aliasing entry point bypassessplitLevel0PboFullSubImage2D.
Patch
From 311c502e88d95d982295789f9d3cdc30e3d9bcf4 Mon Sep 17 00:00:00 2001
From: Ken Russell <kbr@chromium.org>
Date: Wed, 08 Jul 2026 14:08:48 -0700
Subject: [PATCH] GL: workaround: split PBO uploads to 2D textures' level 0.
To work around a bug in Imagination's drivers, if uploading the entire
level 0 of a 2D texture from a PBO, split the upload into two:
everything except the last line/pixel, and the last line/pixel. Reuse
setSubImageRowByRowWorkaround, and enhance it to support uploads of
height 1. Add PowerVR driver version support to workarounds, and add
unit test for parsing it. Add a new gl_test verifying the workaround.
Co-authored with Gemini with feedback from Imagination, Shahbaz
Youssefi and Amirali Abdolrashidi.
Bug: chromium:496807874
Change-Id: I598aeeb14fdaeaef2f0d96e566235e57582ee15f
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/8027554
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Amirali Abdolrashidi <abdolrashidi@google.com>
---
diff --git a/include/platform/gl_features.json b/include/platform/gl_features.json
index 49890e1..73fdf1d 100644
--- a/include/platform/gl_features.json
+++ b/include/platform/gl_features.json
@@ -925,6 +925,14 @@
"Disable the EXT_clear_texture extension due to driver bugs."
],
"issue": "http://crbug.com/475877320"
+ },
+ {
+ "name": "split_level_0_pbo_full_sub_image_2D",
+ "category": "Workarounds",
+ "description": [
+ "Split full-image level 0 PBO uploads via TexSubImage2D into two calls to work around driver bugs."
+ ],
+ "issue": "http://crbug.com/496807874"
}
]
}
diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp
index 47ebe88..b4fd17d 100644
--- a/src/libANGLE/renderer/gl/TextureGL.cpp
+++ b/src/libANGLE/renderer/gl/TextureGL.cpp
@@ -381,6 +381,38 @@
.lumaWorkaround.enabled);
stateManager->bindTexture(getType(), mTextureID);
+ const gl::ImageDesc &desc = mState.getImageDesc(index);
+ const bool isFullImage = area.x == 0 && area.y == 0 && area.width == desc.size.width &&
+ area.height == desc.size.height;
+
+ if (features.splitLevel0PboFullSubImage2D.enabled && level == 0 && unpackBuffer &&
+ nativegl::UseTexImage2D(getType()) && isFullImage && (area.width > 1 || area.height > 1))
+ {
+ GLuint rowBytes = 0;
+ GLuint imageBytes = 0;
+ GLuint skipBytes = 0;
+ ANGLE_CHECK_GL_MATH(contextGL, originalInternalFormatInfo.computeRowDepthSkipBytes(
+ type, area.width, area.height, unpack, /*is3D=*/false,
+ &rowBytes, &imageBytes, &skipBytes));
+
+ size_t maxBytesUploadedPerChunk = 0;
+ if (area.height > 1)
+ {
+ maxBytesUploadedPerChunk = static_cast<size_t>(area.height - 1) * rowBytes;
+ }
+ else
+ {
+ ASSERT(area.height == 1 && area.width > 1);
+ GLuint pixelBytes = originalInternalFormatInfo.computePixelBytes(type);
+ maxBytesUploadedPerChunk = static_cast<size_t>(area.width - 1) * pixelBytes;
+ }
+
+ ANGLE_TRY(setSubImageRowByRowWorkaround(context, target, level, area, format, type, unpack,
+ unpackBuffer, maxBytesUploadedPerChunk, pixels));
+ contextGL->markWorkSubmitted();
+ return angle::Result::Continue;
+ }
+
if (features.unpackOverlappingRowsSeparatelyUnpackBuffer.enabled && unpackBuffer &&
unpack.rowLength != 0 && unpack.rowLength < area.width)
{
@@ -508,15 +540,35 @@
else
{
ASSERT(nativegl::UseTexImage2D(getType()));
- for (GLint row = 0; row < area.height; row += rowsPerChunk)
+ if (area.height == 1 && maxBytesUploadedPerChunk > 0 && maxBytesUploadedPerChunk < rowBytes)
{
- GLint height = std::min(rowsPerChunk, area.height - row);
- GLint byteOffset = row * rowBytes;
- const GLubyte *rowPixels = ANGLE_UNSAFE_TODO(pixelsWithSkip + byteOffset);
- ANGLE_GL_TRY(context, functions->texSubImage2D(
- ToGLenum(target), static_cast<GLint>(level), area.x,
- row + area.y, area.width, height, texSubImageFormat.format,
- texSubImageFormat.type, rowPixels));
+ GLuint pixelBytes = glFormat.computePixelBytes(type);
+ GLint pixelsPerChunk = std::min(
+ std::max(static_cast<GLint>(maxBytesUploadedPerChunk / pixelBytes), 1), area.width);
+ for (GLint col = 0; col < area.width; col += pixelsPerChunk)
+ {
+ GLint width = std::min(pixelsPerChunk, area.width - col);
+ GLint byteOffset = col * pixelBytes;
+ const GLubyte *colPixels = ANGLE_UNSAFE_TODO(pixelsWithSkip + byteOffset);
+ ANGLE_GL_TRY(context, functions->texSubImage2D(
+ ToGLenum(target), static_cast<GLint>(level), area.x + col,
+ area.y, width, 1, texSubImageFormat.format,
+ texSubImageFormat.type, colPixels));
+ }
+ }
+ else
+ {
+ for (GLint row = 0; row < area.height; row += rowsPerChunk)
+ {
+ GLint height = std::min(rowsPerChunk, area.height - row);
+ GLint byteOffset = row * rowBytes;
+ const GLubyte *rowPixels = ANGLE_UNSAFE_TODO(pixelsWithSkip + byteOffset);
+ ANGLE_GL_TRY(context,
+ functions->texSubImage2D(ToGLenum(target), static_cast<GLint>(level),
+ area.x, row + area.y, area.width, height,
+ texSubImageFormat.format,
+ texSubImageFormat.type, rowPixels));
+ }
}
}
return angle::Result::Continue;
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index c527432..ef2fc80 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -35,6 +35,7 @@
#include <EGL/eglext.h>
#include <algorithm>
+#include <cctype>
#include <sstream>
using angle::CheckedNumeric;
@@ -222,6 +223,59 @@
}
} // namespace
+// Example GL_VENDOR, GL_RENDERER and GL_VERSION strings:
+// GL_VENDOR: "Imagination Technologies"
+// GL_RENDERER: "PowerVR D-Series DXT-48-1536"
+// GL_VERSION: "OpenGL ES 3.2 build 25.3@6908880"
+// GL_VENDOR: "Imagination Technologies"
+// GL_RENDERER: "PowerVR D-Series DXT-48-1536"
+// GL_VERSION: "OpenGL ES 3.2 build 26.1@7000000"
+bool GetPowerVRDriverVersion(const std::string &vendorString,
+ const std::string &rendererString,
+ const std::string &versionString,
+ std::array<int, 2> *versionOut)
+{
+ ASSERT(versionOut);
+ (*versionOut)[0] = 0;
+ (*versionOut)[1] = 0;
+
+ if (vendorString.find("Imagination") == std::string::npos)
+ {
+ return false;
+ }
+
+ if (rendererString.find("PowerVR") == std::string::npos)
+ {
+ return false;
+ }
+
+ size_t atPos = versionString.find('@');
+ if (atPos == std::string::npos)
+ {
+ return false;
+ }
+
+ size_t startPos = atPos;
+ while (startPos > 0 && !std::isspace(static_cast<unsigned char>(versionString[startPos - 1])))
+ {
+ --startPos;
+ }
+
+ // SAFETY: this offset is computed safely above.
+ std::istringstream stream(ANGLE_UNSAFE_BUFFERS(&versionString[startPos]));
+ int major = 0;
+ int minor = 0;
+ char dot = 0;
+ if (!(stream >> major >> dot >> minor) || dot != '.')
+ {
+ return false;
+ }
+
+ (*versionOut)[0] = major;
+ (*versionOut)[1] = minor;
+ return true;
+}
+
SwapControlData::SwapControlData()
: targetSwapInterval(0), maxSwapInterval(-1), currentSwapInterval(-1)
{}
@@ -2350,6 +2404,13 @@
ANGLE_FEATURE_CONDITION(features, unpackOverlappingRowsSeparatelyUnpackBuffer, isNvidia);
ANGLE_FEATURE_CONDITION(features, packOverlappingRowsSeparatelyPackBuffer, isNvidia);
+ std::array<int, 2> powerVRVersion = {0, 0};
+ bool isPowerVRDriver =
+ GetPowerVRDriverVersion(GetVendorString(functions), GetRendererString(functions),
+ GetVersionString(functions), &powerVRVersion);
+ ANGLE_FEATURE_CONDITION(features, splitLevel0PboFullSubImage2D,
+ isPowerVRDriver && powerVRVersion < (std::array<int, 2>{26, 2}));
+
ANGLE_FEATURE_CONDITION(features, initializeCurrentVertexAttributes, isNvidia);
ANGLE_FEATURE_CONDITION(features, unpackLastRowSeparatelyForPaddingInclusion,
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.h b/src/libANGLE/renderer/gl/renderergl_utils.h
index c01151c..4b37e2d 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.h
+++ b/src/libANGLE/renderer/gl/renderergl_utils.h
@@ -19,6 +19,7 @@
#include "libANGLE/renderer/driver_utils.h"
#include "libANGLE/renderer/gl/functionsgl_typedefs.h"
+#include <array>
#include <string>
#include <vector>
@@ -188,6 +189,11 @@
std::string GetVendorString(const FunctionsGL *functions);
std::string GetVersionString(const FunctionsGL *functions);
+bool GetPowerVRDriverVersion(const std::string &vendorString,
+ const std::string &rendererString,
+ const std::string &versionString,
+ std::array<int, 2> *versionOut);
+
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_RENDERERGLUTILS_H_
diff --git a/src/libANGLE/renderer/gl/renderergl_utils_unittest.cpp b/src/libANGLE/renderer/gl/renderergl_utils_unittest.cpp
new file mode 100644
index 0000000..27ab6e4
--- /dev/null
+++ b/src/libANGLE/renderer/gl/renderergl_utils_unittest.cpp
@@ -0,0 +1,55 @@
+//
+// Copyright 2026 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.
+//
+
+#include "gtest/gtest.h"
+
+#include "libANGLE/renderer/gl/renderergl_utils.h"
+
+#include <array>
+
+namespace rx
+{
+namespace
+{
+
+// Test parsing of PowerVR driver version strings.
+TEST(RendererGLUtilsTest, GetPowerVRDriverVersion)
+{
+ std::array<int, 2> version = {0, 0};
+
+ // Valid PowerVR driver version strings
+ EXPECT_TRUE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_EQ(version[0], 25);
+ EXPECT_EQ(version[1], 3);
+
+ EXPECT_TRUE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "OpenGL ES 3.2 build 26.1@7000000", &version));
+ EXPECT_EQ(version[0], 26);
+ EXPECT_EQ(version[1], 1);
+
+ // Negative tests
+ EXPECT_FALSE(GetPowerVRDriverVersion("", "", "", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("", "PowerVR D-Series DXT-48-1536",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "Some Other Renderer",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Intel", "Mesa DRI Intel(R) HD Graphics 4000 (IVB GT2)",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "without build version", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "build invalid@version", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "build 26@7000000", &version));
+}
+
+} // namespace
+} // namespace rx
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 06bad2d..139728f 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -534,6 +534,9 @@
Texture2DTestES3RobustInit() : Texture2DTestES3() { setRobustResourceInit(true); }
};
+class Texture2DTestES3PBO : public Texture2DTestES3
+{};
+
class Texture2DTestES3Foveation : public Texture2DTestES3
{
protected:
@@ -10789,6 +10792,79 @@
EXPECT_PIXEL_ALPHA_EQ(0, 0, 255);
}
+// Test that full level 0 PBO uploads with height > 1 correctly upload the last line when split.
+TEST_P(Texture2DTestES3PBO, SplitUploadLastLine)
+{
+ constexpr GLuint kWidth = 8;
+ constexpr GLuint kHeight = 8;
+
+ std::vector<GLColor> pixelData(kWidth * kHeight, GLColor::green);
+ for (GLuint x = 0; x < kWidth; ++x)
+ {
+ pixelData[(kHeight - 1) * kWidth + x] = GLColor::red;
+ }
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ EXPECT_GL_NO_ERROR();
+
+ GLBuffer pbo;
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, pixelData.size() * sizeof(GLColor), pixelData.data(),
+ GL_STATIC_DRAW);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ EXPECT_GL_NO_ERROR();
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight - 1, GLColor::green);
+ EXPECT_PIXEL_RECT_EQ(0, kHeight - 1, kWidth, 1, GLColor::red);
+}
+
+// Test that full level 0 PBO uploads with height == 1 correctly upload the last pixel when split.
+TEST_P(Texture2DTestES3PBO, SplitUploadLastPixel)
+{
+ constexpr GLuint kWidth = 8;
+ constexpr GLuint kHeight = 1;
+
+ std::vector<GLColor> pixelData(kWidth * kHeight, GLColor::blue);
+ pixelData[kWidth - 1] = GLColor::yellow;
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ EXPECT_GL_NO_ERROR();
+
+ GLBuffer pbo;
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, pixelData.size() * sizeof(GLColor), pixelData.data(),
+ GL_STATIC_DRAW);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ EXPECT_GL_NO_ERROR();
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth - 1, 1, GLColor::blue);
+ EXPECT_PIXEL_RECT_EQ(kWidth - 1, 0, 1, 1, GLColor::yellow);
+}
+
// Test that compressed textures ignore the pixel unpack state.
// (https://crbug.com/40057837)
TEST_P(Texture2DTestES3, PixelUnpackStateTexImage)
@@ -21363,6 +21439,11 @@
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DTestES3RobustInit);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DTestES3RobustInit);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DTestES3PBO);
+ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DTestES3PBO,
+ ES3_OPENGL().enable(Feature::SplitLevel0PboFullSubImage2D),
... (file diff truncated)
Regression Test / PoC
diff --git a/src/libANGLE/renderer/gl/renderergl_utils_unittest.cpp b/src/libANGLE/renderer/gl/renderergl_utils_unittest.cpp
new file mode 100644
index 0000000..27ab6e4
--- /dev/null
+++ b/src/libANGLE/renderer/gl/renderergl_utils_unittest.cpp
@@ -0,0 +1,55 @@
+//
+// Copyright 2026 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.
+//
+
+#include "gtest/gtest.h"
+
+#include "libANGLE/renderer/gl/renderergl_utils.h"
+
+#include <array>
+
+namespace rx
+{
+namespace
+{
+
+// Test parsing of PowerVR driver version strings.
+TEST(RendererGLUtilsTest, GetPowerVRDriverVersion)
+{
+ std::array<int, 2> version = {0, 0};
+
+ // Valid PowerVR driver version strings
+ EXPECT_TRUE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_EQ(version[0], 25);
+ EXPECT_EQ(version[1], 3);
+
+ EXPECT_TRUE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "OpenGL ES 3.2 build 26.1@7000000", &version));
+ EXPECT_EQ(version[0], 26);
+ EXPECT_EQ(version[1], 1);
+
+ // Negative tests
+ EXPECT_FALSE(GetPowerVRDriverVersion("", "", "", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("", "PowerVR D-Series DXT-48-1536",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "Some Other Renderer",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Intel", "Mesa DRI Intel(R) HD Graphics 4000 (IVB GT2)",
+ "OpenGL ES 3.2 build 25.3@6908880", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "without build version", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "build invalid@version", &version));
+ EXPECT_FALSE(GetPowerVRDriverVersion("Imagination Technologies", "PowerVR D-Series DXT-48-1536",
+ "build 26@7000000", &version));
+}
+
+} // namespace
+} // namespace rx
diff --git a/src/tests/angle_unittests.gni b/src/tests/angle_unittests.gni
index 2020854..124657c 100644
--- a/src/tests/angle_unittests.gni
+++ b/src/tests/angle_unittests.gni
@@ -133,8 +133,10 @@
"compiler_tests/UnrollFlatten_test.cpp",
]
-angle_unittests_gl_sources =
- [ "../libANGLE/renderer/gl/DisplayGL_unittest.cpp" ]
+angle_unittests_gl_sources = [
+ "../libANGLE/renderer/gl/DisplayGL_unittest.cpp",
+ "../libANGLE/renderer/gl/renderergl_utils_unittest.cpp",
+]
angle_unittests_msl_sources = [
"../common/apple/ObjCPtr_test.mm",
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 06bad2d..139728f 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -534,6 +534,9 @@
Texture2DTestES3RobustInit() : Texture2DTestES3() { setRobustResourceInit(true); }
};
+class Texture2DTestES3PBO : public Texture2DTestES3
+{};
+
class Texture2DTestES3Foveation : public Texture2DTestES3
{
protected:
@@ -10789,6 +10792,79 @@
EXPECT_PIXEL_ALPHA_EQ(0, 0, 255);
}
+// Test that full level 0 PBO uploads with height > 1 correctly upload the last line when split.
+TEST_P(Texture2DTestES3PBO, SplitUploadLastLine)
+{
+ constexpr GLuint kWidth = 8;
+ constexpr GLuint kHeight = 8;
+
+ std::vector<GLColor> pixelData(kWidth * kHeight, GLColor::green);
+ for (GLuint x = 0; x < kWidth; ++x)
+ {
+ pixelData[(kHeight - 1) * kWidth + x] = GLColor::red;
+ }
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ EXPECT_GL_NO_ERROR();
+
+ GLBuffer pbo;
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, pixelData.size() * sizeof(GLColor), pixelData.data(),
+ GL_STATIC_DRAW);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ EXPECT_GL_NO_ERROR();
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight - 1, GLColor::green);
+ EXPECT_PIXEL_RECT_EQ(0, kHeight - 1, kWidth, 1, GLColor::red);
+}
+
+// Test that full level 0 PBO uploads with height == 1 correctly upload the last pixel when split.
+TEST_P(Texture2DTestES3PBO, SplitUploadLastPixel)
+{
+ constexpr GLuint kWidth = 8;
+ constexpr GLuint kHeight = 1;
+
+ std::vector<GLColor> pixelData(kWidth * kHeight, GLColor::blue);
+ pixelData[kWidth - 1] = GLColor::yellow;
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ EXPECT_GL_NO_ERROR();
+
+ GLBuffer pbo;
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, pixelData.size() * sizeof(GLColor), pixelData.data(),
+ GL_STATIC_DRAW);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ EXPECT_GL_NO_ERROR();
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth - 1, 1, GLColor::blue);
+ EXPECT_PIXEL_RECT_EQ(kWidth - 1, 0, 1, 1, GLColor::yellow);
+}
+
// Test that compressed textures ignore the pixel unpack state.
// (https://crbug.com/40057837)
TEST_P(Texture2DTestES3, PixelUnpackStateTexImage)
@@ -21363,6 +21439,11 @@
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DTestES3RobustInit);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DTestES3RobustInit);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DTestES3PBO);
+ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DTestES3PBO,
+ ES3_OPENGL().enable(Feature::SplitLevel0PboFullSubImage2D),
+ ES3_OPENGLES().enable(Feature::SplitLevel0PboFullSubImage2D));
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Texture2DTestES3Foveation);
ANGLE_INSTANTIATE_TEST_ES3_AND(
Texture2DTestES3Foveation,
Original Bug Report
Use After Free in TQMQueueTransfer
Security Bug
Important: Please do not change the component of this bug manually.
Please READ THIS FAQ before filing a bug: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md
Please see the following link for instructions on filing security bugs: https://www.chromium.org/Home/chromium-security/reporting-security-bugs
Reports may be eligible for reward payments under the Chrome VRP: https://g.co/chrome/vrp
NOTE: Security bugs are normally made public once a fix has been widely deployed.
VULNERABILITY DETAILS
his indicates that the TQ context object internally holds a stale mapping pointer. When the texture is respec (redefined in size/format),
the surface mapping inside TQ is not updated correctly, and subsequent texture data operations using the stale mapping result in SEGV.
Chrome Version: [146.0.7680.119] + [stable]
Operating System: [Android pixel 10 latest patch]
REPRODUCTION CASE
open poc.html and locat | grep DEBUG
FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION
Type of crash: [gpu.]
Crash State:
Symbolizing stack using ABI=arm64
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7b9bb61108 in tid 15173 (CrGpuMain), pid 15147 (ileged_process0)
Build fingerprint: 'google/frankel/frankel:16/CP1A.260305.018/14887507:user/release-keys'
Revision: 'MP1.0'
pid: 15147, tid: 15173, name: CrGpuMain >>> org.chromium.chrome:privileged_process0 <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000007b9bb61108 (read)
Stack Trace:
RELADDR FUNCTION FILE:LINE
000000000004060c TQMQueueTransfer+2620) (BuildId: 17a0557644ca324bb2113edbfbfbd1e6 /vendor/lib64/libIMGegl.so
0000000000120590 TQCopyDataFromSurface+768) (BuildId: cefd59f52838946b0e646aaf2bb04c76 /vendor/lib64/egl/libGLESv2_powervr.so
00000000001589f8 glCopyTexSubImage2D+1256) (BuildId: cefd59f52838946b0e646aaf2bb04c76 /vendor/lib64/egl/libGLESv2_powervr.so
0000000003677128 rx::TextureGL::copySubImage(gl::Context const*, gl::ImageIndex const&, angle::Offset<int> const&, gl::RectangleImpl<int> const&, gl::Framebuffer*) ../../third_party/angle/src/libANGLE/renderer/gl/TextureGL.cpp:0:0
00000000035aa8ac gl::Texture::copySubImage(gl::Context*, gl::ImageIndex const&, angle::Offset<int> const&, gl::RectangleImpl<int> const&, gl::Framebuffer*) ../../third_party/angle/src/libANGLE/Texture.cpp:1613:25
000000000352aea4 gl::Context::copyTexSubImage2D(gl::TextureTarget, int, int, int, int, int, int, int) ../../third_party/angle/src/libANGLE/Context.cpp:5192:32
0000000008399250 GL_CopyTexSubImage2D ../../third_party/angle/src/libGLESv2/entry_points_gles_2_0_autogen.cpp:1142:22
0000000009a05278 gpu::gles2::GLES2DecoderPassthroughImpl::DoCopyTexSubImage2D(unsigned int, int, int, int, int, int, int, int) ../../gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc:882:10
0000000009a1c87c gpu::gles2::GLES2DecoderPassthroughImpl::HandleCopyTexSubImage2D(unsigned int, void const volatile*) ../../gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc:533:7
00000000099fb52c gpu::error::Error gpu::gles2::GLES2DecoderPassthroughImpl::DoCommandsImpl<false>(unsigned int, void const volatile*, int, int*) ../../gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc:742:20
00000000042bd920 gpu::CommandBufferService::Flush(int, gpu::AsyncAPIInterface*) ../../gpu/command_buffer/service/command_buffer_service.cc:267:35
0000000009aca028 gpu::CommandBufferStub::OnAsyncFlush(int, unsigned int, std::__Cr::vector<gpu::SyncToken, std::__Cr::allocator<gpu::SyncToken>> const&) ../../gpu/ipc/service/command_buffer_stub.cc:504:22
0000000009ac9cc0 gpu::CommandBufferStub::ExecuteDeferredRequest(gpu::mojom::DeferredCommandBufferRequestParams&, gpu::FenceSyncReleaseDelegate*) ../../gpu/ipc/service/command_buffer_stub.cc:173:7
0000000009acfb50 gpu::GpuChannel::ExecuteDeferredRequest(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*) ../../gpu/ipc/service/gpu_channel.cc:833:13
0000000009ad29e0 void base::internal::DecayedFunctorTraits<void (gpu::GpuChannel::*)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), base::WeakPtr<gpu::GpuChannel>&&, mojo::StructPtr<gpu::mojom::DeferredRequestParams>&&>::Invoke<void (gpu::GpuChannel::*)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), base::WeakPtr<gpu::GpuChannel> const&, mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*>(void (gpu::GpuChannel::*)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), base::WeakPtr<gpu::GpuChannel> const&, mojo::StructPtr<gpu::mojom::DeferredRequestParams>&&, gpu::FenceSyncReleaseDelegate*&&) ../../base/functional/bind_internal.h:740:12
v------> void base::internal::InvokeHelper<true, base::internal::FunctorTraits<void (gpu::GpuChannel::*&&)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), base::WeakPtr<gpu::GpuChannel>&&, mojo::StructPtr<gpu::mojom::DeferredRequestParams>&&>, void, 0ul, 1ul>::MakeItSo<void (gpu::GpuChannel::*)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), std::__Cr::tuple<base::WeakPtr<gpu::GpuChannel>, mojo::StructPtr<gpu::mojom::DeferredRequestParams>>, gpu::FenceSyncReleaseDelegate*>(void (gpu::GpuChannel::*&&)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), std::__Cr::tuple<base::WeakPtr<gpu::GpuChannel>, mojo::StructPtr<gpu::mojom::DeferredRequestParams>>&&, gpu::FenceSyncReleaseDelegate*&&) ../../base/functional/bind_internal.h:956:5
v------> void base::internal::Invoker<base::internal::FunctorTraits<void (gpu::GpuChannel::*&&)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), base::WeakPtr<gpu::GpuChannel>&&, mojo::StructPtr<gpu::mojom::DeferredRequestParams>&&>, base::internal::BindState<true, true, false, void (gpu::GpuChannel::*)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), base::WeakPtr<gpu::GpuChannel>, mojo::StructPtr<gpu::mojom::DeferredRequestParams>>, void (gpu::FenceSyncReleaseDelegate*)>::RunImpl<void (gpu::GpuChannel::*)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), std::__Cr::tuple<base::WeakPtr<gpu::GpuChannel>, mojo::StructPtr<gpu::mojom::DeferredRequestParams>>, 0ul, 1ul>(void (gpu::GpuChannel::*&&)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), std::__Cr::tuple<base::WeakPtr<gpu::GpuChannel>, mojo::StructPtr<gpu::mojom::DeferredRequestParams>>&&, std::__Cr::integer_sequence<unsigned long, 0ul, 1ul>, gpu::FenceSyncReleaseDelegate*&&) ../../base/functional/bind_internal.h:1069:14
0000000009ad2964 base::internal::Invoker<base::internal::FunctorTraits<void (gpu::GpuChannel::*&&)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), base::WeakPtr<gpu::GpuChannel>&&, mojo::StructPtr<gpu::mojom::DeferredRequestParams>&&>, base::internal::BindState<true, true, false, void (gpu::GpuChannel::*)(mojo::StructPtr<gpu::mojom::DeferredRequestParams>, gpu::FenceSyncReleaseDelegate*), base::WeakPtr<gpu::GpuChannel>, mojo::StructPtr<gpu::mojom::DeferredRequestParams>>, void (gpu::FenceSyncReleaseDelegate*)>::RunOnce(base::internal::BindStateBase*, gpu::FenceSyncReleaseDelegate*) ../../base/functional/bind_internal.h:982:12
v------> base::OnceCallback<void (media::DemuxerStream*)>::Run(media::DemuxerStream*) && ../../base/functional/callback.h:155:12
v------> void base::internal::DecayedFunctorTraits<base::OnceCallback<void (media::DemuxerStream*)>, media::DemuxerStream*&&>::Invoke<base::OnceCallback<void (media::DemuxerStream*)>, media::DemuxerStream*>(base::OnceCallback<void (media::DemuxerStream*)>&&, media::DemuxerStream*&&) ../../base/functional/bind_internal.h:815:49
v------> void base::internal::InvokeHelper<false, base::internal::FunctorTraits<base::OnceCallback<void (media::DemuxerStream*)>&&, media::DemuxerStream*&&>, void, 0ul>::MakeItSo<base::OnceCallback<void (media::DemuxerStream*)>, std::__Cr::tuple<base::internal::UnretainedWrapper<media::DemuxerStream, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>>(base::OnceCallback<void (media::DemuxerStream*)>&&, std::__Cr::tuple<base::internal::UnretainedWrapper<media::DemuxerStream, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>&&) ../../base/functional/bind_internal.h:932:12
v------> void base::internal::Invoker<base::internal::FunctorTraits<base::OnceCallback<void (media::DemuxerStream*)>&&, media::DemuxerStream*&&>, base::internal::BindState<false, true, true, base::OnceCallback<void (media::DemuxerStream*)>, base::internal::UnretainedWrapper<media::DemuxerStream, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, void ()>::RunImpl<base::OnceCallback<void (media::DemuxerStream*)>, std::__Cr::tuple<base::internal::UnretainedWrapper<media::DemuxerStream, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, 0ul>(base::OnceCallback<void (media::DemuxerStream*)>&&, std::__Cr::tuple<base::internal::UnretainedWrapper<media::DemuxerStream, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>&&, std::__Cr::integer_sequence<unsigned long, 0ul>) ../../base/functional/bind_internal.h:1069:14
0000000003bb79a4 base::internal::Invoker<base::internal::FunctorTraits<base::OnceCallback<void (BrowserWindowInterface*)>&&, base::raw_ptr<BrowserWindowInterface, (partition_alloc::internal::RawPtrTraits)1>&&>, base::internal::BindState<false, true, true, base::OnceCallback<void (BrowserWindowInterface*)>, base::internal::UnretainedWrapper<BrowserWindowInterface, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)1>>, void ()>::RunOnce(base::internal::BindStateBase*) ../../base/functional/bind_internal.h:982:12
v------> base::OnceCallback<void ()>::Run() && ../../base/functional/callback.h:155:12
00000000042c3384 gpu::Scheduler::ExecuteSequence(base::IdType<gpu::SyncPointOrderData, unsigned int, 0u, 1u>) ../../gpu/command_buffer/service/scheduler.cc:707:29
00000000042c2a7c gpu::Scheduler::RunNextTask() ../../gpu/command_buffer/service/scheduler.cc:625:3
v------> base::OnceCallback<void ()>::Run() && ../../base/functional/callback.h:155:12
000000000703a1fc base::TaskAnnotator::RunTaskImpl(base::PendingTask&) ../../base/task/common/task_annotator.cc:229:34
v------> void base::TaskAnnotator::RunTask<base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*)::$_3>(perfetto::StaticString, base::PendingTask&, base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*)::$_3&&) ../../base/task/common/task_annotator.h:112:5
0000000007056a3c base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*) ../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:475:23
0000000007056640 base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() ../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:346:40
0000000006fead28 base::MessagePumpDefault::Run(base::MessagePump::Delegate*) ../../base/message_loop/message_pump_default.cc:42:55
0000000007057100 base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta) ../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:650:12
00000000070182cc base::RunLoop::Run(base::Location const&) ../../base/run_loop.cc:135:14
000000000ce4b014 content::GpuMain(content::MainFunctionParams) ../../content/gpu/gpu_main.cc:485:14
0000000006fc2288 content::RunOtherNamedProcessTypeMain(std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, content::MainFunctionParams, content::ContentMainDelegate*) ../../content/app/content_main_runner_impl.cc:762:14
0000000006fc30d8 content::ContentMainRunnerImpl::Run() ../../content/app/content_main_runner_impl.cc:1152:10
0000000006fc0acc content::RunContentProcess(content::ContentMainParams, content::ContentMainRunner*) ../../content/app/content_main.cc:358:36
0000000006fc1ac8 content::StartContentMain(bool) ../../content/app/android/content_main_android.cc:54:10
00000000002c2300 art_quick_generic_jni_trampoline+144) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
00000000002ab260 art_quick_invoke_static_stub+640) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
0000000000585c88 bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+1984) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
000000000048ff6c void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+468) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
00000000003d1718 ExecuteSwitchImplAsm+8) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
000000000029005c offset 0x4085000) (xi1.run+0 /data/app/~~ayCs0G1cEE9vDupqqYSiOA==/org.chromium.chrome-OG-qSl8JAd4v0pHWHiahqA==/base.apk/libmonochrome.so
00000000003d136c art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.__uniq.112435418011751916792819755956732575238.llvm.15381326084910962254)+364) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
00000000003d0aa0 artQuickToInterpreterBridge+1020) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
00000000002c2438 art_quick_to_interpreter_bridge+88) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
00000000000049a8 offset 0x2000000) (java.lang.Thread.run+136 [anon_shmem:dalvik-jit-code-cache]
00000000002aaf94 art_quick_invoke_stub+612) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
00000000002709b0 art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+220) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
00000000004bdfc8 art::Thread::CreateCallback(void*)+1184) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
00000000004bdb18 art::Thread::CreateCallbackWithUffdGc(void*)+8) (BuildId: 61c7a211c01ef3c0068b4fbe31051050 /apex/com.android.art/lib64/libart.so
000000000008a914 __pthread_start(void*) (.__uniq.67847048707805468364044055584648682506)+180) (BuildId: 8d65ea529c21c79c019713e50adb6675 /apex/com.android.runtime/lib64/bionic/libc.so
000000000007b5a4 __start_thread+68) (BuildId: 8d65ea529c21c79c019713e50adb6675 /apex/com.android.runtime/lib64/bionic/libc.so
CREDIT INFORMATION
Reporter credit: Goodluck
Please categorize manually; bot-based categorization is inaccurate.