shithub: ft²

Download patch

ref: bdb13798b72846946da8baa6ef6a0b67944e8c02
parent: 43eec25b1bef0a0257086e4de55e1edb073fa36c
author: Olav Sørensen <[email protected]>
date: Sun Nov 22 13:49:16 EST 2020

Added boundary sanity checking to BMP loaders

--- a/src/ft2_bmp.c
+++ b/src/ft2_bmp.c
@@ -3,6 +3,7 @@
 #include <crtdbg.h>
 #endif
 
+#include <assert.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdlib.h>
@@ -138,6 +139,22 @@
 ** This is only meant to be used for BMPs that are carefully crafted for this program!
 */
 
+#ifdef _DEBUG
+
+#define CHECK_SRC_BOUNDARY     assert(src8      < src8End);
+#define CHECK_DST8_BOUNDARY    assert(tmp8      < allocEnd);
+#define CHECK_DST8_BOUNDARY_X  assert(&tmp8[x]  < allocEnd);
+#define CHECK_DST32_BOUNDARY   assert(tmp32     < allocEnd);
+#define CHECK_DST32_BOUNDARY_X assert(&tmp32[x] < allocEnd);
+
+#else
+#define CHECK_SRC_BOUNDARY
+#define CHECK_DST8_BOUNDARY
+#define CHECK_DST8_BOUNDARY_X
+#define CHECK_DST32_BOUNDARY
+#define CHECK_DST32_BOUNDARY_X
+#endif
+
 static uint32_t *loadBMPTo32Bit(const uint8_t *src)
 {
 	int32_t len, byte, palIdx;
@@ -154,8 +171,12 @@
 	if (outData == NULL)
 		return NULL;
 
+#ifdef _DEBUG
+	const uint32_t *allocEnd = outData + (hdr->biWidth * hdr->biHeight);
+#endif
+
 	// pre-fill image with first palette color
-	const int32_t palEntries = hdr->biClrUsed == 0 ? colorsInBitmap : hdr->biClrUsed;
+	const int32_t palEntries = (hdr->biClrUsed == 0) ? colorsInBitmap : hdr->biClrUsed;
 	memcpy(pal, &src[0x36], palEntries * sizeof (uint32_t));
 
 	for (int32_t i = 0; i < hdr->biWidth * hdr->biHeight; i++)
@@ -163,6 +184,9 @@
 
 	const int32_t lineEnd = hdr->biWidth;
 	const uint8_t *src8 = pData;
+#ifdef _DEBUG
+	const uint8_t *src8End = src8 + hdr->biSizeImage;
+#endif
 	uint32_t *dst32 = outData;
 	int32_t x = 0;
 	int32_t y = hdr->biHeight - 1;
@@ -169,9 +193,11 @@
 
 	while (true)
 	{
+		CHECK_SRC_BOUNDARY
 		byte = *src8++;
 		if (byte == 0) // escape control
 		{
+			CHECK_SRC_BOUNDARY
 			byte = *src8++;
 			if (byte == 0) // end of line
 			{
@@ -184,7 +210,9 @@
 			}
 			else if (byte == 2) // add to x/y position
 			{
+				CHECK_SRC_BOUNDARY
 				x += *src8++;
+				CHECK_SRC_BOUNDARY
 				y -= *src8++;
 			}
 			else // absolute bytes
@@ -193,7 +221,11 @@
 				{
 					tmp32 = &dst32[(y * hdr->biWidth) + x];
 					for (int32_t i = 0; i < byte; i++)
+					{
+						CHECK_DST32_BOUNDARY
+						CHECK_SRC_BOUNDARY
 						*tmp32++ = pal[*src8++];
+					}
 
 					if (byte & 1)
 						src8++;
@@ -207,9 +239,17 @@
 					tmp32 = &dst32[y * hdr->biWidth];
 					for (int32_t i = 0; i < len; i++)
 					{
+						CHECK_SRC_BOUNDARY
 						palIdx = *src8++;
+
+						CHECK_DST32_BOUNDARY_X
 						tmp32[x++] = pal[palIdx >> 4];
-						if (x < lineEnd) tmp32[x++] = pal[palIdx & 0xF];
+
+						if (x < lineEnd)
+						{
+							CHECK_DST32_BOUNDARY_X
+							tmp32[x++] = pal[palIdx & 0xF];
+						}
 					}
 
 					if (((byte + 1) >> 1) & 1)
@@ -219,6 +259,7 @@
 		}
 		else
 		{
+			CHECK_SRC_BOUNDARY
 			palIdx = *src8++;
 
 			if (hdr->biCompression == COMP_RLE8)
@@ -226,7 +267,10 @@
 				color = pal[palIdx];
 				tmp32 = &dst32[(y * hdr->biWidth) + x];
 				for (int32_t i = 0; i < byte; i++)
+				{
+					CHECK_DST32_BOUNDARY
 					*tmp32++ = color;
+				}
 
 				x += byte;
 			}
@@ -239,8 +283,14 @@
 				tmp32 = &dst32[y * hdr->biWidth];
 				for (int32_t i = 0; i < len; i++)
 				{
+					CHECK_DST32_BOUNDARY_X
 					tmp32[x++] = color;
-					if (x < lineEnd) tmp32[x++] = color2;
+
+					if (x < lineEnd)
+					{
+						CHECK_DST32_BOUNDARY_X
+						tmp32[x++] = color2;
+					}
 				}
 			}
 		}
@@ -266,16 +316,23 @@
 	if (outData == NULL)
 		return NULL;
 
-	const int32_t palEntries = hdr->biClrUsed == 0 ? colorsInBitmap : hdr->biClrUsed;
+#ifdef _DEBUG
+	const uint8_t *allocEnd = outData + (hdr->biWidth * hdr->biHeight);
+#endif
+
+	const int32_t palEntries = (hdr->biClrUsed == 0) ? colorsInBitmap : hdr->biClrUsed;
 	memcpy(pal, &src[0x36], palEntries * sizeof (uint32_t));
 
 	// pre-fill image with first palette color
-	color = pal[0] ? 1 : 0;
+	color = !!pal[0];
 	for (i = 0; i < hdr->biWidth * hdr->biHeight; i++)
 		outData[i] = color;
 
 	const int32_t lineEnd = hdr->biWidth;
 	const uint8_t *src8 = pData;
+#ifdef _DEBUG
+	const uint8_t *src8End = src8 + hdr->biSizeImage;
+#endif
 	uint8_t *dst8 = outData;
 	int32_t x = 0;
 	int32_t y = hdr->biHeight - 1;
@@ -282,9 +339,11 @@
 
 	while (true)
 	{
+		CHECK_SRC_BOUNDARY
 		byte = *src8++;
 		if (byte == 0) // escape control
 		{
+			CHECK_SRC_BOUNDARY
 			byte = *src8++;
 			if (byte == 0) // end of line
 			{
@@ -297,7 +356,9 @@
 			}
 			else if (byte == 2) // add to x/y position
 			{
+				CHECK_SRC_BOUNDARY
 				x += *src8++;
+				CHECK_SRC_BOUNDARY
 				y -= *src8++;
 			}
 			else // absolute bytes
@@ -306,9 +367,17 @@
 				tmp8 = &dst8[y * hdr->biWidth];
 				for (i = 0; i < len; i++)
 				{
+					CHECK_SRC_BOUNDARY
 					palIdx = *src8++;
-					tmp8[x++] = pal[palIdx >> 4] ? 1 : 0;
-					if (x < lineEnd) tmp8[x++] = pal[palIdx & 0xF] ? 1 : 0;
+
+					CHECK_DST8_BOUNDARY_X
+					tmp8[x++] = !!pal[palIdx >> 4];
+					
+					if (x < lineEnd)
+					{
+						CHECK_DST8_BOUNDARY_X
+						tmp8[x++] = !!pal[palIdx & 0xF];
+					}
 				}
 
 				if (((byte + 1) >> 1) & 1)
@@ -317,17 +386,24 @@
 		}
 		else
 		{
+			CHECK_SRC_BOUNDARY
 			palIdx = *src8++;
 
-			color = pal[palIdx >> 4] ? 1 : 0;
-			color2 = pal[palIdx & 0x0F] ? 1 : 0;
+			color = !!pal[palIdx >> 4];
+			color2 = !!pal[palIdx & 0x0F];
 
 			len = byte >> 1;
 			tmp8 = &dst8[y * hdr->biWidth];
 			for (i = 0; i < len; i++)
 			{
+				CHECK_DST8_BOUNDARY_X
 				tmp8[x++] = color;
-				if (x < lineEnd) tmp8[x++] = color2;
+
+				if (x < lineEnd)
+				{
+					CHECK_DST8_BOUNDARY_X
+					tmp8[x++] = color2;
+				}
 			}
 		}
 	}
@@ -352,7 +428,11 @@
 	if (outData == NULL)
 		return NULL;
 
-	const int32_t palEntries = hdr->biClrUsed == 0 ? colorsInBitmap : hdr->biClrUsed;
+#ifdef _DEBUG
+	const uint8_t *allocEnd = outData + (hdr->biWidth * hdr->biHeight);
+#endif
+
+	const int32_t palEntries = (hdr->biClrUsed == 0) ? colorsInBitmap : hdr->biClrUsed;
 	memcpy(pal, &src[0x36], palEntries * sizeof (uint32_t));
 
 	// pre-fill image with first palette color
@@ -362,6 +442,9 @@
 
 	const int32_t lineEnd = hdr->biWidth;
 	const uint8_t *src8 = pData;
+#ifdef _DEBUG
+	const uint8_t *src8End = src8 + hdr->biSizeImage;
+#endif
 	uint8_t *dst8 = outData;
 	int32_t x = 0;
 	int32_t y = hdr->biHeight - 1;
@@ -368,9 +451,11 @@
 
 	while (true)
 	{
+		CHECK_SRC_BOUNDARY
 		byte = *src8++;
 		if (byte == 0) // escape control
 		{
+			CHECK_SRC_BOUNDARY
 			byte = *src8++;
 			if (byte == 0) // end of line
 			{
@@ -383,7 +468,9 @@
 			}
 			else if (byte == 2) // add to x/y position
 			{
+				CHECK_SRC_BOUNDARY
 				x += *src8++;
+				CHECK_SRC_BOUNDARY
 				y -= *src8++;
 			}
 			else // absolute bytes
@@ -392,9 +479,17 @@
 				len = byte >> 1;
 				for (i = 0; i < len; i++)
 				{
+					CHECK_SRC_BOUNDARY
 					palIdx = *src8++;
+
+					CHECK_DST8_BOUNDARY_X
 					tmp8[x++] = getFT2PalNrFromPixel(pal[palIdx >> 4]);
-					if (x < lineEnd) tmp8[x++] = getFT2PalNrFromPixel(pal[palIdx & 0xF]);
+
+					if (x < lineEnd)
+					{
+						CHECK_DST8_BOUNDARY_X
+						tmp8[x++] = getFT2PalNrFromPixel(pal[palIdx & 0xF]);
+					}
 				}
 
 				if (((byte + 1) >> 1) & 1)
@@ -403,6 +498,7 @@
 		}
 		else
 		{
+			CHECK_SRC_BOUNDARY
 			palIdx = *src8++;
 
 			pal1 = getFT2PalNrFromPixel(pal[palIdx >> 4]);
@@ -412,8 +508,14 @@
 			len = byte >> 1;
 			for (i = 0; i < len; i++)
 			{
+				CHECK_DST8_BOUNDARY_X
 				tmp8[x++] = pal1;
-				if (x < lineEnd) tmp8[x++] = pal2;
+
+				if (x < lineEnd)
+				{
+					CHECK_DST8_BOUNDARY_X
+					tmp8[x++] = pal2;
+				}
 			}
 		}
 	}