Add base::numerics for safe math and conversions.
This replaces are "IsUnsignedXXXSafe" family of methods.
Also add overflow checks to unpack block sizes.
BUG=angleproject:1397
Change-Id: Ib47be149b0486c70f795b0d0f8899441faac9340
Reviewed-on: https://chromium-review.googlesource.com/348062
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index 2efebcd..d2e4e21 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -7,6 +7,7 @@
// validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters
#include "libANGLE/validationES3.h"
+
#include "libANGLE/validationES.h"
#include "libANGLE/Context.h"
#include "libANGLE/Texture.h"
@@ -18,6 +19,8 @@
#include "common/mathutil.h"
#include "common/utilities.h"
+using namespace angle;
+
namespace gl
{
@@ -474,23 +477,31 @@
size_t depthSize = static_cast<size_t>(depth);
GLenum sizedFormat = GetSizedInternalFormat(actualInternalFormat, type);
- size_t pixelBytes = static_cast<size_t>(gl::GetInternalFormatInfo(sizedFormat).pixelBytes);
+ CheckedNumeric<size_t> checkedBytes(gl::GetInternalFormatInfo(sizedFormat).pixelBytes);
+ checkedBytes *= widthSize;
+ checkedBytes *= heightSize;
+ checkedBytes *= depthSize;
- if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
- !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
- !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes))
+ if (!checkedBytes.IsValid())
{
// Overflow past the end of the buffer
- context->handleError(Error(GL_INVALID_OPERATION));
+ context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow"));
return false;
}
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat);
- size_t copyBytes = formatInfo.computeBlockSize(type, width, height);
- size_t offset = reinterpret_cast<size_t>(pixels);
+ auto copyBytesOrErr = formatInfo.computeBlockSize(type, width, height);
+ if (copyBytesOrErr.isError())
+ {
+ context->handleError(copyBytesOrErr.getError());
+ return false;
+ }
+ CheckedNumeric<size_t> checkedCopyBytes(copyBytesOrErr.getResult());
+ CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
+ checkedCopyBytes += checkedOffset;
- if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) ||
- ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->getSize())))
+ if (!checkedCopyBytes.IsValid() ||
+ (checkedCopyBytes.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
{
// Overflow past the end of the buffer
context->handleError(Error(GL_INVALID_OPERATION));
@@ -503,7 +514,7 @@
{
size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeInfo(type).bytes);
- if ((offset % dataBytesPerPixel) != 0)
+ if ((checkedOffset.ValueOrDie() % dataBytesPerPixel) != 0)
{
context->handleError(Error(GL_INVALID_OPERATION));
return false;
@@ -1538,10 +1549,21 @@
return false;
}
+ // Validate image size
+ if (!ValidImageSizeParameters(context, target, level, width, height, depth, false))
+ {
+ context->handleError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
- if (imageSize < 0 ||
- static_cast<GLuint>(imageSize) !=
- formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
+ auto blockSizeOrErr = formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height);
+ if (blockSizeOrErr.isError())
+ {
+ context->handleError(blockSizeOrErr.getError());
+ return false;
+ }
+ if (imageSize < 0 || static_cast<GLuint>(imageSize) != blockSizeOrErr.getResult())
{
context->handleError(Error(GL_INVALID_VALUE));
return false;
@@ -1883,9 +1905,13 @@
}
const InternalFormat &formatInfo = GetInternalFormatInfo(format);
- if (imageSize < 0 ||
- static_cast<GLuint>(imageSize) !=
- formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
+ auto blockSizeOrErr = formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height);
+ if (blockSizeOrErr.isError())
+ {
+ context->handleError(blockSizeOrErr.getError());
+ return false;
+ }
+ if (imageSize < 0 || static_cast<GLuint>(imageSize) != blockSizeOrErr.getResult())
{
context->handleError(Error(GL_INVALID_VALUE));
return false;