11#include <stdlib.h>
22#include <string.h>
3+ #include <limits.h>
34
45#include "cgif_raw.h"
56
@@ -45,6 +46,7 @@ typedef struct {
4546 uint16_t * pTreeList ; // LZW dictionary tree as list (max. number of children per node = 1)
4647 uint16_t * pTreeMap ; // LZW dictionary tree as map (backup to pTreeList in case more than 1 child is present)
4748 uint16_t * pLZWData ; // pointer to LZW data
49+ size_t lzwCapacity ; // number of entries allocated in pLZWData
4850 const uint8_t * pImageData ; // pointer to image data
4951 uint32_t numPixel ; // number of pixels per frame
5052 uint32_t LZWPos ; // position of the current LZW code
@@ -85,14 +87,18 @@ static uint8_t calcInitCodeLen(uint16_t numEntries) {
8587}
8688
8789/* reset the dictionary of known LZW codes -- will reset the current code length as well */
88- static void resetDict (LZWGenState * pContext , const uint16_t initDictLen ) {
90+ static int resetDict (LZWGenState * pContext , const uint16_t initDictLen ) {
8991 pContext -> dictPos = initDictLen + 2 ; // reset current position in dictionary (number of colors + 2 for start and end code)
9092 pContext -> mapPos = 1 ;
93+ if (pContext -> LZWPos >= pContext -> lzwCapacity ) {
94+ return CGIF_EALLOC ;
95+ }
9196 pContext -> pLZWData [pContext -> LZWPos ] = initDictLen ; // issue clear-code
9297 ++ (pContext -> LZWPos ); // increment position in LZW data
9398 // reset LZW list
9499 memset (pContext -> pTreeInit , 0 , initDictLen * sizeof (uint16_t ) * initDictLen );
95100 memset (pContext -> pTreeList , 0 , ((sizeof (uint16_t ) * 2 ) + sizeof (uint16_t )) * MAX_DICT_LEN );
101+ return CGIF_OK ;
96102}
97103
98104/* add new child node */
@@ -146,13 +152,19 @@ static int lzw_crawl_tree(LZWGenState* pContext, uint32_t* pStrPos, uint16_t par
146152 parentIndex = nextParent ;
147153 ++ strPos ;
148154 } else {
155+ if (pContext -> LZWPos >= pContext -> lzwCapacity ) {
156+ return CGIF_EALLOC ;
157+ }
149158 pContext -> pLZWData [pContext -> LZWPos ] = parentIndex ; // write last LZW code in LZW data
150159 ++ (pContext -> LZWPos );
151160 if (pContext -> dictPos < MAX_DICT_LEN ) {
152161 pTreeInit [parentIndex * initDictLen + pContext -> pImageData [strPos + 1 ]] = pContext -> dictPos ;
153162 ++ (pContext -> dictPos );
154163 } else {
155- resetDict (pContext , initDictLen );
164+ const int rReset = resetDict (pContext , initDictLen );
165+ if (rReset != CGIF_OK ) {
166+ return rReset ;
167+ }
156168 }
157169 ++ strPos ;
158170 * pStrPos = strPos ;
@@ -181,18 +193,27 @@ static int lzw_crawl_tree(LZWGenState* pContext, uint32_t* pStrPos, uint16_t par
181193 }
182194 }
183195 // still not found child? add current parentIndex to LZW data and add new child
196+ if (pContext -> LZWPos >= pContext -> lzwCapacity ) {
197+ return CGIF_EALLOC ;
198+ }
184199 pContext -> pLZWData [pContext -> LZWPos ] = parentIndex ; // write last LZW code in LZW data
185200 ++ (pContext -> LZWPos );
186201 if (pContext -> dictPos < MAX_DICT_LEN ) { // if LZW-dictionary is not full yet
187202 add_child (pContext , parentIndex , pContext -> dictPos , initDictLen , pContext -> pImageData [strPos + 1 ]); // add new LZW code to dictionary
188203 } else {
189204 // the dictionary reached its maximum code => reset it (not required by GIF-standard but mostly done like this)
190- resetDict (pContext , initDictLen );
205+ const int rReset = resetDict (pContext , initDictLen );
206+ if (rReset != CGIF_OK ) {
207+ return rReset ;
208+ }
191209 }
192210 ++ strPos ;
193211 * pStrPos = strPos ;
194212 return CGIF_OK ;
195213 }
214+ if (pContext -> LZWPos >= pContext -> lzwCapacity ) {
215+ return CGIF_EALLOC ;
216+ }
196217 pContext -> pLZWData [pContext -> LZWPos ] = parentIndex ; // if the end of the image is reached, write last LZW code
197218 ++ (pContext -> LZWPos );
198219 ++ strPos ;
@@ -207,7 +228,10 @@ static int lzw_generate(LZWGenState* pContext, uint16_t initDictLen) {
207228 uint8_t parentIndex ;
208229
209230 strPos = 0 ; // start at beginning of the image data
210- resetDict (pContext , initDictLen ); // reset dictionary and issue clear-code at first
231+ r = resetDict (pContext , initDictLen ); // reset dictionary and issue clear-code at first
232+ if (r != CGIF_OK ) {
233+ return r ;
234+ }
211235 while (strPos < pContext -> numPixel ) { // while there are still image data to be encoded
212236 parentIndex = pContext -> pImageData [strPos ]; // start at root node
213237 // get longest sequence that is still in dictionary, return new position in image data
@@ -216,6 +240,9 @@ static int lzw_generate(LZWGenState* pContext, uint16_t initDictLen) {
216240 return r ; // error: return error code to callee
217241 }
218242 }
243+ if (pContext -> LZWPos >= pContext -> lzwCapacity ) {
244+ return CGIF_EALLOC ;
245+ }
219246 pContext -> pLZWData [pContext -> LZWPos ] = initDictLen + 1 ; // termination code
220247 ++ (pContext -> LZWPos );
221248 return CGIF_OK ;
@@ -330,11 +357,26 @@ static int LZW_GenerateStream(LZWResult* pResult, const uint32_t numPixel, const
330357 // where N = max dictionary resets = numPixel / (MAX_DICT_LEN - initDictLen - 2)
331358 entriesPerCycle = MAX_DICT_LEN - initDictLen - 2 ; // maximum added number of dictionary entries per cycle: -2 to account for start and end code
332359 maxResets = numPixel / entriesPerCycle ;
333- pContext -> pLZWData = malloc (sizeof (uint16_t ) * (numPixel + 2 + maxResets ));
360+ size_t neededEntries = (size_t )numPixel + 2u ;
361+ if (neededEntries < (size_t )numPixel ) {
362+ r = CGIF_EALLOC ;
363+ goto LZWGENERATE_Cleanup ;
364+ }
365+ neededEntries += (size_t )maxResets ;
366+ if (neededEntries < (size_t )maxResets ) {
367+ r = CGIF_EALLOC ;
368+ goto LZWGENERATE_Cleanup ;
369+ }
370+ if (neededEntries > (SIZE_MAX / sizeof (uint16_t ))) {
371+ r = CGIF_EALLOC ;
372+ goto LZWGENERATE_Cleanup ;
373+ }
374+ pContext -> pLZWData = malloc (neededEntries * sizeof (uint16_t ));
334375 if (pContext -> pLZWData == NULL ) {
335376 r = CGIF_EALLOC ;
336377 goto LZWGENERATE_Cleanup ;
337378 }
379+ pContext -> lzwCapacity = neededEntries ;
338380 pContext -> LZWPos = 0 ;
339381
340382 // actually generate the LZW sequence.
0 commit comments