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;
+ }
}
}
}