From acb67dad8c52743ab25bdbd868dad25fdd478ca2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 6 Nov 2023 14:50:10 +0900 Subject: [PATCH] saver/gif: up to date the gif encoder. this fixes the memory sanitizer report: ../src/savers/gif/gif.h:315:31: runtime error: index 255 out of bounds for type 'unsigned char [255]' ../src/savers/gif/gif.h:113:54: runtime error: index 255 out of bounds for type 'unsigned char [255]' Issue: https://github.com/thorvg/thorvg/issues/1758 --- src/savers/gif/gif.h | 93 ++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/src/savers/gif/gif.h b/src/savers/gif/gif.h index 72cc148c..d89ffc38 100644 --- a/src/savers/gif/gif.h +++ b/src/savers/gif/gif.h @@ -32,6 +32,7 @@ #include // for FILE* #include // for memcpy and bzero #include // for integer typedefs +#include // for bool macros // Define these macros to hook into a custom memory allocator. // TEMP_MALLOC and TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs @@ -61,7 +62,7 @@ const int kGifTransIndex = 0; -struct GifPalette +typedef struct { int bitDepth; @@ -72,9 +73,9 @@ struct GifPalette // k-d tree over RGB space, organized in heap fashion // i.e. left child of node i is node i*2, right child is node i*2+1 // nodes 256-511 are implicitly the leaves, containing a color - uint8_t treeSplitElt[255]; - uint8_t treeSplit[255]; -}; + uint8_t treeSplitElt[256]; + uint8_t treeSplit[256]; +} GifPalette; // max, min, and abs functions int GifIMax(int l, int r) { return l>r?l:r; } @@ -85,7 +86,7 @@ int GifIAbs(int i) { return i<0?-i:i; } // Takes as in/out parameters the current best color and its error - // only changes them if it finds a better color in its subtree. // this is the major hotspot in the code at the moment. -void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestInd, int& bestDiff, int treeRoot = 1) +void GifGetClosestPaletteColor( GifPalette* pPal, int r, int g, int b, int* bestInd, int* bestDiff, int treeRoot ) { // base case, reached the bottom of the tree if(treeRoot > (1<bitDepth)-1) @@ -99,10 +100,10 @@ void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestI int b_err = b - ((int32_t)pPal->b[ind]); int diff = GifIAbs(r_err)+GifIAbs(g_err)+GifIAbs(b_err); - if(diff < bestDiff) + if(diff < *bestDiff) { - bestInd = ind; - bestDiff = diff; + *bestInd = ind; + *bestDiff = diff; } return; @@ -117,7 +118,7 @@ void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestI { // check the left subtree GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2); - if( bestDiff > splitPos - splitComp ) + if( *bestDiff > splitPos - splitComp ) { // cannot prove there's not a better value in the right subtree, check that too GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1); @@ -126,7 +127,7 @@ void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestI else { GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1); - if( bestDiff > splitComp - splitPos ) + if( *bestDiff > splitComp - splitPos ) { GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2); } @@ -391,7 +392,7 @@ void GifDitherImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t for( int ii=0; iir[bestInd]) * 256; - int32_t g_err = nextPix[1] - int32_t(pPal->g[bestInd]) * 256; - int32_t b_err = nextPix[2] - int32_t(pPal->b[bestInd]) * 256; + int32_t r_err = nextPix[0] - (int32_t)(pPal->r[bestInd]) * 256; + int32_t g_err = nextPix[1] - (int32_t)(pPal->g[bestInd]) * 256; + int32_t b_err = nextPix[2] - (int32_t)(pPal->b[bestInd]) * 256; nextPix[0] = pPal->r[bestInd]; nextPix[1] = pPal->g[bestInd]; @@ -510,7 +511,7 @@ void GifThresholdImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint // palettize the pixel int32_t bestDiff = 1000000; int32_t bestInd = 1; - GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], bestInd, bestDiff); + GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], &bestInd, &bestDiff, 1); // Write the resulting color to the output buffer outFrame[0] = pPal->r[bestInd]; @@ -527,52 +528,52 @@ void GifThresholdImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint // Simple structure to write out the LZW-compressed portion of the image // one bit at a time -struct GifBitStatus +typedef struct { uint8_t bitIndex; // how many bits in the partial byte written so far uint8_t byte; // current partial byte uint32_t chunkIndex; uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file -}; +} GifBitStatus; // insert a single bit -void GifWriteBit( GifBitStatus& stat, uint32_t bit ) +void GifWriteBit( GifBitStatus* stat, uint32_t bit ) { bit = bit & 1; - bit = bit << stat.bitIndex; - stat.byte |= bit; + bit = bit << stat->bitIndex; + stat->byte |= bit; - ++stat.bitIndex; - if( stat.bitIndex > 7 ) + ++stat->bitIndex; + if( stat->bitIndex > 7 ) { // move the newly-finished byte to the chunk buffer - stat.chunk[stat.chunkIndex++] = stat.byte; + stat->chunk[stat->chunkIndex++] = stat->byte; // and start a new byte - stat.bitIndex = 0; - stat.byte = 0; + stat->bitIndex = 0; + stat->byte = 0; } } // write all bytes so far to the file -void GifWriteChunk( FILE* f, GifBitStatus& stat ) +void GifWriteChunk( FILE* f, GifBitStatus* stat ) { - fputc((int)stat.chunkIndex, f); - fwrite(stat.chunk, 1, stat.chunkIndex, f); + fputc((int)stat->chunkIndex, f); + fwrite(stat->chunk, 1, stat->chunkIndex, f); - stat.bitIndex = 0; - stat.byte = 0; - stat.chunkIndex = 0; + stat->bitIndex = 0; + stat->byte = 0; + stat->chunkIndex = 0; } -void GifWriteCode( FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length ) +void GifWriteCode( FILE* f, GifBitStatus* stat, uint32_t code, uint32_t length ) { for( uint32_t ii=0; ii> 1; - if( stat.chunkIndex == 255 ) + if( stat->chunkIndex == 255 ) { GifWriteChunk(f, stat); } @@ -581,10 +582,10 @@ void GifWriteCode( FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length ) // The LZW dictionary is a 256-ary tree constructed as the file is encoded, // this is one node -struct GifLzwNode +typedef struct { uint16_t m_next[256]; -}; +} GifLzwNode; // write a 256-color (8-bit) image palette to the file void GifWritePalette( const GifPalette* pPal, FILE* f ) @@ -653,7 +654,7 @@ void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uin stat.bitIndex = 0; stat.chunkIndex = 0; - GifWriteCode(f, stat, clearCode, codeSize); // start with a fresh LZW dictionary + GifWriteCode(f, &stat, clearCode, codeSize); // start with a fresh LZW dictionary for(uint32_t yy=0; yy