ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

commit bdb13798b72846946da8baa6ef6a0b67944e8c02
parent 43eec25b1bef0a0257086e4de55e1edb073fa36c
Author: Olav Sørensen <olav.sorensen@live.no>
Date:   Sun, 22 Nov 2020 18:48:49 +0100

Added boundary sanity checking to BMP loaders

Diffstat:
Msrc/ft2_bmp.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 115 insertions(+), 13 deletions(-)

diff --git 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 @@ void freeBMPs(void) ** 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 @@ static uint32_t *loadBMPTo32Bit(const uint8_t *src) 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,15 +184,20 @@ static uint32_t *loadBMPTo32Bit(const uint8_t *src) 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; 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 @@ static uint32_t *loadBMPTo32Bit(const uint8_t *src) } 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 @@ static uint32_t *loadBMPTo32Bit(const uint8_t *src) { 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 @@ static uint32_t *loadBMPTo32Bit(const uint8_t *src) 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 @@ static uint32_t *loadBMPTo32Bit(const uint8_t *src) } else { + CHECK_SRC_BOUNDARY palIdx = *src8++; if (hdr->biCompression == COMP_RLE8) @@ -226,7 +267,10 @@ static uint32_t *loadBMPTo32Bit(const uint8_t *src) 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 @@ static uint32_t *loadBMPTo32Bit(const uint8_t *src) 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,25 +316,34 @@ static uint8_t *loadBMPTo1Bit(const uint8_t *src) // supports 4-bit RLE only 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; 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 @@ static uint8_t *loadBMPTo1Bit(const uint8_t *src) // supports 4-bit RLE only } 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 @@ static uint8_t *loadBMPTo1Bit(const uint8_t *src) // supports 4-bit RLE only 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 @@ static uint8_t *loadBMPTo1Bit(const uint8_t *src) // supports 4-bit RLE only } 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 @@ static uint8_t *loadBMPTo4BitPal(const uint8_t *src) // supports 4-bit RLE only 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,15 +442,20 @@ static uint8_t *loadBMPTo4BitPal(const uint8_t *src) // supports 4-bit RLE only 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; 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 @@ static uint8_t *loadBMPTo4BitPal(const uint8_t *src) // supports 4-bit RLE only } 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 @@ static uint8_t *loadBMPTo4BitPal(const uint8_t *src) // supports 4-bit RLE only 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 @@ static uint8_t *loadBMPTo4BitPal(const uint8_t *src) // supports 4-bit RLE only } else { + CHECK_SRC_BOUNDARY palIdx = *src8++; pal1 = getFT2PalNrFromPixel(pal[palIdx >> 4]); @@ -412,8 +508,14 @@ static uint8_t *loadBMPTo4BitPal(const uint8_t *src) // supports 4-bit RLE only 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; + } } } }