Assert that casting memory sizes to 32-bit doesn't overflow

VkPhysicalDeviceMaintenance3Properties::maxMemoryAllocationSize is
currently 1 GiB. This ensures that the memory of all resources can be
addressed using 32-bit indices. We return VK_ERROR_OUT_OF_DEVICE_MEMORY
when this limit is exceeded, but it's still best to ensure we don't
inadvertently end up calculating sizes larger than 4 GiB that would
cause arithmetic overflow due to casting to 32-bit integers.

Bug: b/200806413
Change-Id: I10e828a93d6c24624f049a0809f0b962d473f44f
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/60068
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Sean Risser <srisser@google.com>
diff --git a/src/Device/Blitter.cpp b/src/Device/Blitter.cpp
index 0537db8..197b408 100644
--- a/src/Device/Blitter.cpp
+++ b/src/Device/Blitter.cpp
@@ -116,10 +116,10 @@
 		BlitData data = {
 			pixel, nullptr,  // source, dest
 
-			static_cast<uint32_t>(format.bytes()),                                  // sPitchB
-			static_cast<uint32_t>(dest->rowPitchBytes(aspect, subres.mipLevel)),    // dPitchB
+			assert_cast<uint32_t>(format.bytes()),                                  // sPitchB
+			assert_cast<uint32_t>(dest->rowPitchBytes(aspect, subres.mipLevel)),    // dPitchB
 			0,                                                                      // sSliceB (unused in clear operations)
-			static_cast<uint32_t>(dest->slicePitchBytes(aspect, subres.mipLevel)),  // dSliceB
+			assert_cast<uint32_t>(dest->slicePitchBytes(aspect, subres.mipLevel)),  // dSliceB
 
 			0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f,  // x0, y0, z0, w, h, d
 
@@ -1903,10 +1903,10 @@
 	BlitData data = {
 		nullptr,                                                                                 // source
 		nullptr,                                                                                 // dest
-		static_cast<uint32_t>(src->rowPitchBytes(srcAspect, region.srcSubresource.mipLevel)),    // sPitchB
-		static_cast<uint32_t>(dst->rowPitchBytes(dstAspect, region.dstSubresource.mipLevel)),    // dPitchB
-		static_cast<uint32_t>(src->slicePitchBytes(srcAspect, region.srcSubresource.mipLevel)),  // sSliceB
-		static_cast<uint32_t>(dst->slicePitchBytes(dstAspect, region.dstSubresource.mipLevel)),  // dSliceB
+		assert_cast<uint32_t>(src->rowPitchBytes(srcAspect, region.srcSubresource.mipLevel)),    // sPitchB
+		assert_cast<uint32_t>(dst->rowPitchBytes(dstAspect, region.dstSubresource.mipLevel)),    // dPitchB
+		assert_cast<uint32_t>(src->slicePitchBytes(srcAspect, region.srcSubresource.mipLevel)),  // sSliceB
+		assert_cast<uint32_t>(dst->slicePitchBytes(dstAspect, region.dstSubresource.mipLevel)),  // dSliceB
 
 		x0,
 		y0,
@@ -2354,8 +2354,8 @@
 	VkExtent3D extent = image->getMipLevelExtent(aspect, subresource.mipLevel);
 	CubeBorderData data = {
 		image->getTexelPointer({ 0, 0, 0 }, posX),
-		static_cast<uint32_t>(image->rowPitchBytes(aspect, subresource.mipLevel)),
-		static_cast<uint32_t>(image->getLayerSize(aspect)),
+		assert_cast<uint32_t>(image->rowPitchBytes(aspect, subresource.mipLevel)),
+		assert_cast<uint32_t>(image->getLayerSize(aspect)),
 		extent.width
 	};
 	cornerUpdateRoutine(&data);
diff --git a/src/System/Types.hpp b/src/System/Types.hpp
index f7d16ae..8266d7b 100644
--- a/src/System/Types.hpp
+++ b/src/System/Types.hpp
@@ -15,6 +15,7 @@
 #ifndef sw_Types_hpp
 #define sw_Types_hpp
 
+#include <cassert>
 #include <limits>
 #include <type_traits>
 
@@ -49,6 +50,16 @@
 
 namespace sw {
 
+// assert_cast<> is like a static_cast<> which asserts that no information was lost.
+template<typename To, typename From>
+To assert_cast(From x)
+{
+	To y = static_cast<To>(x);
+	assert(static_cast<From>(y) == x);
+
+	return y;
+}
+
 // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
 constexpr inline uint32_t bit_ceil(uint32_t i)
 {