Guard against out of bounds accesses caused by a large base level
A texture's base level can be any positive integer, but SwiftShader
stores texture levels in a array that has an implementation
dependent size (IMPLEMENTATION_MAX_TEXTURE_LEVELS). To avoid
accessing this array out of bounds, a class was added to make sure
all accesses to the array are done within its bounds.
Change-Id: I9b439018f209a47371bd2959ba847345326964dd
Reviewed-on: https://swiftshader-review.googlesource.com/20488
Tested-by: Alexis Hétu <sugoi@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp
index 4e63750..0cf4084 100644
--- a/src/OpenGL/libGLESv2/Texture.cpp
+++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -420,11 +420,6 @@
Texture2D::Texture2D(GLuint name) : Texture(name)
{
- for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
- {
- image[i] = nullptr;
- }
-
mSurface = nullptr;
mColorbufferProxy = nullptr;
@@ -433,14 +428,7 @@
Texture2D::~Texture2D()
{
- for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
- {
- if(image[i])
- {
- image[i]->unbind(this);
- image[i] = nullptr;
- }
- }
+ image.unbind(this);
if(mSurface)
{
@@ -562,14 +550,7 @@
void Texture2D::bindTexImage(gl::Surface *surface)
{
- for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
- {
- if(image[level])
- {
- image[level]->release();
- image[level] = nullptr;
- }
- }
+ image.release();
image[0] = surface->getRenderTarget();
@@ -579,14 +560,7 @@
void Texture2D::releaseTexImage()
{
- for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
- {
- if(image[level])
- {
- image[level]->release();
- image[level] = nullptr;
- }
- }
+ image.release();
if(mSurface)
{
@@ -904,14 +878,6 @@
{
for(int f = 0; f < 6; f++)
{
- for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
- {
- image[f][i] = nullptr;
- }
- }
-
- for(int f = 0; f < 6; f++)
- {
mFaceProxies[f] = nullptr;
mFaceProxyRefs[f] = 0;
}
@@ -919,20 +885,9 @@
TextureCubeMap::~TextureCubeMap()
{
- for(int f = 0; f < 6; f++)
- {
- for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
- {
- if(image[f][i])
- {
- image[f][i]->unbind(this);
- image[f][i] = nullptr;
- }
- }
- }
-
for(int i = 0; i < 6; i++)
{
+ image[i].unbind(this);
mFaceProxies[i] = nullptr;
}
}
@@ -1440,11 +1395,6 @@
Texture3D::Texture3D(GLuint name) : Texture(name)
{
- for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
- {
- image[i] = nullptr;
- }
-
mSurface = nullptr;
mColorbufferProxy = nullptr;
@@ -1453,14 +1403,7 @@
Texture3D::~Texture3D()
{
- for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
- {
- if(image[i])
- {
- image[i]->unbind(this);
- image[i] = nullptr;
- }
- }
+ image.unbind(this);
if(mSurface)
{
diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h
index 017acab..4f57d32 100644
--- a/src/OpenGL/libGLESv2/Texture.h
+++ b/src/OpenGL/libGLESv2/Texture.h
@@ -45,6 +45,54 @@
IMPLEMENTATION_MAX_RENDERBUFFER_SIZE = sw::OUTLINE_RESOLUTION,
};
+class ImageLevels
+{
+public:
+ inline const egl::Image* operator[](size_t index) const
+ {
+ return (index < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? image[index] : nullptr;
+ }
+
+ inline egl::Image*& operator[](size_t index)
+ {
+ if(index < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ {
+ return image[index];
+ }
+
+ static egl::Image* nullImage;
+ nullImage = nullptr;
+ return nullImage;
+ }
+
+ inline void release()
+ {
+ for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ if(image[i])
+ {
+ image[i]->release();
+ image[i] = nullptr;
+ }
+ }
+ }
+
+ inline void unbind(const egl::Texture* texture)
+ {
+ for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ if(image[i])
+ {
+ image[i]->unbind(texture);
+ image[i] = nullptr;
+ }
+ }
+ }
+
+private:
+ egl::Image *image[IMPLEMENTATION_MAX_TEXTURE_LEVELS] = {};
+};
+
class Texture : public egl::Texture
{
public:
@@ -192,7 +240,7 @@
bool isMipmapComplete() const;
- egl::Image *image[IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+ ImageLevels image;
gl::Surface *mSurface;
@@ -265,7 +313,7 @@
// face is one of the GL_TEXTURE_CUBE_MAP_* enumerants. Returns nullptr on failure.
egl::Image *getImage(GLenum face, unsigned int level);
- egl::Image *image[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+ ImageLevels image[6];
// A specific internal reference count is kept for colorbuffer proxy references,
// because, as the renderbuffer acting as proxy will maintain a binding pointer
@@ -321,7 +369,7 @@
bool isMipmapComplete() const;
- egl::Image *image[IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+ ImageLevels image;
gl::Surface *mSurface;