@@ -129,12 +129,20 @@ static int32_t col_hash_collision_count(const uint8_t* rgb, const uint8_t* hashT
129129/* initialize hash table storing colors and their frequency */
130130static colHashTable * init_col_hash_table (uint32_t tableSize ){
131131 colHashTable * colhash = malloc (sizeof (colHashTable ));
132+ if (colhash == NULL ) {
133+ return NULL ;
134+ }
132135 colhash -> tableSize = getNextPrimePower2 (tableSize ); // increase table size to next prime number
133136 colhash -> frequ = malloc (sizeof (uint32_t ) * colhash -> tableSize );
134137 colhash -> hashTable = malloc (3 * colhash -> tableSize );
135138 colhash -> indexUsed = malloc (colhash -> tableSize );
136139 colhash -> pPalette = malloc (3 * colhash -> tableSize );
137140 colhash -> colIdx = malloc (sizeof (uint32_t )* colhash -> tableSize );
141+ // check if any of the allocations failed
142+ if (colhash -> frequ == NULL || colhash -> hashTable == NULL || colhash -> indexUsed == NULL || colhash -> pPalette == NULL || colhash -> colIdx == NULL ) {
143+ free_col_hash_table (colhash );
144+ return NULL ;
145+ }
138146 colhash -> cnt = 0 ; // no colors initially
139147 memset (colhash -> pPalette , 0 , 3 * colhash -> tableSize ); // unused part of color table is uninitialized otheriwse
140148 memset (colhash -> indexUsed , 0 , colhash -> tableSize ); // initially no entry in hash-table is used
@@ -152,14 +160,30 @@ static void free_col_hash_table(colHashTable* colhash){
152160}
153161
154162/* increase the size of the color hash table */
155- static void resize_col_hash_table (colHashTable * colhash ){
163+ static int resize_col_hash_table (colHashTable * colhash ){
156164 uint32_t tableSizeNew ;
165+ uint8_t * pPalette_new ;
166+ uint32_t * colIdx_new ;
157167 tableSizeNew = getNextPrimePower2 (colhash -> tableSize ); // increase table size to the next prime number above the next power of two
158- colhash -> pPalette = realloc (colhash -> pPalette , 3 * tableSizeNew );
159- colhash -> colIdx = realloc (colhash -> colIdx , sizeof (uint32_t ) * tableSizeNew );
168+ pPalette_new = realloc (colhash -> pPalette , 3 * tableSizeNew );
169+ colIdx_new = realloc (colhash -> colIdx , sizeof (uint32_t ) * tableSizeNew );
170+ if (pPalette_new == NULL || colIdx_new == NULL ) {
171+ if (pPalette_new ) colhash -> pPalette = pPalette_new ;
172+ if (colIdx_new ) colhash -> colIdx = colIdx_new ;
173+ return -1 ;
174+ }
175+ colhash -> pPalette = pPalette_new ;
176+ colhash -> colIdx = colIdx_new ;
177+
160178 uint8_t * hashTable_new = malloc (3 * tableSizeNew );
161179 uint8_t * indexUsed_new = malloc (tableSizeNew );
162180 uint32_t * frequ_new = malloc (sizeof (uint32_t ) * tableSizeNew );
181+ if (hashTable_new == NULL || indexUsed_new == NULL || frequ_new == NULL ) {
182+ free (hashTable_new );
183+ free (indexUsed_new );
184+ free (frequ_new );
185+ return -1 ;
186+ }
163187 memset (indexUsed_new , 0 , tableSizeNew );
164188 colhash -> cnt = 0 ;
165189 for (uint32_t j = 0 ; j < colhash -> tableSize ; ++ j ) { // TBD (no improvement when tested): easier to loop over pPalette and also leave pPalette in place?, if indexUsed is also unnecessary then
@@ -180,11 +204,15 @@ static void resize_col_hash_table(colHashTable* colhash){
180204 colhash -> hashTable = hashTable_new ; // pass pointer to new hash table
181205 colhash -> indexUsed = indexUsed_new ; // pass pointer to new hash table
182206 colhash -> frequ = frequ_new ; // pass pointer to new hash table
207+ return 0 ;
183208}
184209
185210/* take frequ indexed by hash(rgb) and return corresponding dense array */
186211static uint32_t * hash_to_dense (colHashTable * colhash , cgif_chan_fmt fmtChan ) {
187212 uint32_t * frequDense = malloc (sizeof (uint32_t ) * colhash -> cnt );
213+ if (frequDense == NULL ) {
214+ return NULL ;
215+ }
188216 uint32_t h ;
189217 (void )fmtChan ;
190218 for (uint32_t i = 0 ; i < colhash -> cnt ; ++ i ) {
@@ -243,6 +271,9 @@ static treeNode* new_tree_node(uint8_t* pPalette, uint32_t* frequ, uint16_t* num
243271 float var [3 ];
244272
245273 treeNode * node = malloc (sizeof (treeNode ));
274+ if (node == NULL ) {
275+ return NULL ;
276+ }
246277 node -> idxMin = idxMin ; // minimum color in pPalette belonging to the node
247278 node -> idxMax = idxMax ; // maximum color in pPalette belonging to the node
248279 get_variance (pPalette , frequ , idxMin , idxMax , var , node -> mean );
@@ -254,7 +285,7 @@ static treeNode* new_tree_node(uint8_t* pPalette, uint32_t* frequ, uint16_t* num
254285}
255286
256287/* create the decision tree. (Similar to qsort with limited depth: pPalette, frequ get sorted) */
257- static void crawl_decision_tree (treeNode * root , uint16_t * numLeaveNodes , uint8_t * pPalette , uint32_t * frequ , uint16_t colMax ) {
288+ static int crawl_decision_tree (treeNode * root , uint16_t * numLeaveNodes , uint8_t * pPalette , uint32_t * frequ , uint16_t colMax ) {
258289 uint32_t i , k , saveNum ;
259290 uint16_t nodeIdx = 0 ;
260291 uint8_t saveBlk [3 ];
@@ -268,8 +299,8 @@ static void crawl_decision_tree(treeNode* root, uint16_t* numLeaveNodes, uint8_t
268299 i = parent -> idxMin ; // start of block minimum
269300 k = parent -> idxMax ; // start at block maximum
270301 while (i < k ) { // split parent node in two blocks (like one step in qsort)
271- for (; pPalette [3 * i + parent -> cutDim ] <= parent -> mean [parent -> cutDim ]; ++ i ); // && i< parent->idxMax not needed (other condition is false when i==parent>idxMax since there must be at most 1 element above mean)
272- for (; pPalette [3 * k + parent -> cutDim ] > parent -> mean [parent -> cutDim ]; -- k ); // && k> parent->idxMin not needed (other condition is false when k==parent>idxMin since there must be at most 1 element below mean)
302+ for (; pPalette [3 * i + parent -> cutDim ] <= parent -> mean [parent -> cutDim ] && i < parent -> idxMax ; ++ i );
303+ for (; pPalette [3 * k + parent -> cutDim ] > parent -> mean [parent -> cutDim ] && k > parent -> idxMin ; -- k );
273304 if (k > i ) {
274305 memcpy (saveBlk , & (pPalette [3 * i ]), 3 );
275306 memcpy (& (pPalette [3 * i ]), & (pPalette [3 * k ]), 3 ); // swap RGB-blocks in pPalette
@@ -282,11 +313,18 @@ static void crawl_decision_tree(treeNode* root, uint16_t* numLeaveNodes, uint8_t
282313 parent -> isLeave = 0 ; // parent is no leave node anymore when children added
283314 (* numLeaveNodes )-- ; // decrease counter since parent is removed as a leave node
284315 parent -> child0 = new_tree_node (pPalette , frequ , numLeaveNodes , parent -> idxMin , i - 1 , parent -> colIdx ); // i-1 is last index of 1st block, one child takes color index from parent
316+ if (parent -> child0 == NULL ) {
317+ return -1 ;
318+ }
285319 parent -> child1 = new_tree_node (pPalette , frequ , numLeaveNodes , i , parent -> idxMax , * numLeaveNodes );
320+ if (parent -> child1 == NULL ) {
321+ return -1 ;
322+ }
286323 nodeList [2 * (* numLeaveNodes ) - 3 ] = parent -> child0 ; // add new child nodes to the list (total number of nodes is always 2*(*numLeaveNodes)-1)
287324 nodeList [2 * (* numLeaveNodes ) - 2 ] = parent -> child1 ; // add new child nodes to the list (total number of nodes is always 2*(*numLeaveNodes)-1)
288325 }
289326 }
327+ return 0 ;
290328}
291329
292330/* fill 256 color table using the decision tree */
@@ -319,13 +357,22 @@ static uint8_t get_leave_node_index(const treeNode* root, const float* rgb) {
319357static treeNode * create_decision_tree (uint8_t * pPalette , uint32_t * pFrequDense , uint8_t * pPalette256 , uint32_t cnt , uint16_t colMax , uint8_t depthMax ){
320358 uint16_t numLeaveNodes = 0 ;
321359 treeNode * root = new_tree_node (pPalette , pFrequDense , & numLeaveNodes , 0 , cnt - 1 , 0 );
322- crawl_decision_tree (root , & numLeaveNodes , pPalette , pFrequDense , colMax );
360+ if (root == NULL ) {
361+ return NULL ;
362+ }
363+ if (crawl_decision_tree (root , & numLeaveNodes , pPalette , pFrequDense , colMax ) == -1 ) {
364+ free_decision_tree (root );
365+ return NULL ;
366+ }
323367 get_palette_from_decision_tree (root , pPalette256 ); // fill the reduced color table
324368 return root ;
325369}
326370
327371/* free memory allocated for the tree */
328372static void free_decision_tree (treeNode * root ){
373+ if (root == NULL ) {
374+ return ;
375+ }
329376 if (root -> isLeave == 0 ) { // if the node has children
330377 free_decision_tree (root -> child0 );
331378 free_decision_tree (root -> child1 );
@@ -446,6 +493,9 @@ static colHashTable* get_color_histogram(const uint8_t* pImageDataRGB, uint32_t
446493 uint32_t cntCollision ; // count the number of collision
447494 uint32_t tableSize = 262147 ; // initial size of the hash table
448495 colHashTable * colhash = init_col_hash_table (tableSize ); // initialize the hash table storing all the colors
496+ if (colhash == NULL ) {
497+ return NULL ;
498+ }
449499 * pHasAlpha = 0 ; // assume no alpha channel until it is found
450500 const uint8_t sizePixel = fmtChan ; // number of bytes for one pixel (e.g. 3 for RGB, 4 for RGBa)
451501 for (uint32_t i = 0 ; i < numPixel ; ++ i ) {
@@ -466,14 +516,17 @@ static colHashTable* get_color_histogram(const uint8_t* pImageDataRGB, uint32_t
466516 }
467517 // resize the hash table (if more than half-full)
468518 if ((colhash -> cnt > (colhash -> tableSize >> 1 ) || cntCollision > MAX_COLLISIONS ) && colhash -> tableSize < MAX_TABLE_SIZE ) {
469- resize_col_hash_table (colhash );
519+ if (resize_col_hash_table (colhash ) == -1 ) {
520+ free_col_hash_table (colhash );
521+ return NULL ;
522+ }
470523 }
471524 }
472525 return colhash ;
473526}
474527
475528/* quantize the image using the color histogram */
476- static uint32_t quantize_and_dither (colHashTable * colhash , const uint8_t * pImageDataRGB , uint32_t numPixel , uint32_t width , cgif_chan_fmt fmtChan , uint8_t * pImageData , uint8_t * pPalette256 , uint8_t depthMax , uint8_t dithering , int hasAlpha , uint8_t * pBef , cgif_chan_fmt befFmtChan ) {
529+ static int quantize_and_dither (colHashTable * colhash , const uint8_t * pImageDataRGB , uint32_t numPixel , uint32_t width , cgif_chan_fmt fmtChan , uint8_t * pImageData , uint8_t * pPalette256 , uint8_t depthMax , uint8_t dithering , int hasAlpha , uint8_t * pBef , cgif_chan_fmt befFmtChan ) {
477530 // pImageDataRGB: image in RGB format
478531 // numPixel: number of pixels of input image
479532 // width: width of the image (needed for dithering)
@@ -488,9 +541,19 @@ static uint32_t quantize_and_dither(colHashTable* colhash, const uint8_t* pImage
488541 const uint16_t colMax = (1uL << depthMax ) - 1 ; // maximum number of colors (-1 to leave space for transparency), disadvantage (TBD): quantization for static image with 256 colors and no alpha channel unnecessary
489542 if (colhash -> cnt > colMax ) { // color-quantization is needed
490543 uint32_t * pFrequDense = hash_to_dense (colhash , fmtChan );
544+ if (pFrequDense == NULL ) {
545+ return -1 ;
546+ }
491547 treeNode * root = create_decision_tree (colhash -> pPalette , pFrequDense , pPalette256 , colhash -> cnt , colMax , depthMax ); // create decision tree (dynamic, splits along rgb-dimension with highest variance)
492548 free (pFrequDense );
549+ if (root == NULL ) {
550+ return -1 ;
551+ }
493552 float * pImageDataRGBfloat = malloc (fmtChan * numPixel * sizeof (float )); // TBD fmtChan + only when hasAlpha
553+ if (pImageDataRGBfloat == NULL ) {
554+ free_decision_tree (root );
555+ return -1 ;
556+ }
494557 for (uint32_t i = 0 ; i < fmtChan * numPixel ; ++ i ){
495558 pImageDataRGBfloat [i ] = pImageDataRGB [i ];
496559 }
@@ -521,6 +584,9 @@ CGIFrgb* cgif_rgb_newgif(const CGIFrgb_Config* pConfig) {
521584 CGIFrgb * pGIFrgb ;
522585
523586 pGIFrgb = malloc (sizeof (CGIFrgb ));
587+ if (pGIFrgb == NULL ) {
588+ return NULL ;
589+ }
524590 memset (pGIFrgb , 0 , sizeof (CGIFrgb ));
525591 idxConfig .pWriteFn = pConfig -> pWriteFn ;
526592 idxConfig .pContext = pConfig -> pContext ;
@@ -558,18 +624,40 @@ cgif_result cgif_rgb_addframe(CGIFrgb* pGIF, const CGIFrgb_FrameConfig* pConfig)
558624 return CGIF_ERROR ;
559625 }
560626 pNewBef = malloc (pConfig -> fmtChan * MULU16 (imageWidth , imageHeight ));
627+ if (pNewBef == NULL ) {
628+ pGIF -> curResult = CGIF_EALLOC ;
629+ return CGIF_EALLOC ;
630+ }
561631 memcpy (pNewBef , pConfig -> pImageData , pConfig -> fmtChan * MULU16 (imageWidth , imageHeight ));
562632 fConfig .pLocalPalette = aPalette ;
563633 fConfig .pImageData = malloc (pGIF -> config .width * (uint32_t )pGIF -> config .height );
634+ if (fConfig .pImageData == NULL ) {
635+ free (pNewBef );
636+ pGIF -> curResult = CGIF_EALLOC ;
637+ return CGIF_EALLOC ;
638+ }
564639 fConfig .delay = pConfig -> delay ;
565640 fConfig .attrFlags = CGIF_FRAME_ATTR_USE_LOCAL_TABLE ;
566641 if (pConfig -> attrFlags & CGIF_RGB_FRAME_ATTR_INTERLACED ) {
567642 fConfig .attrFlags |= CGIF_FRAME_ATTR_INTERLACED ;
568643 }
569644
570645 colHashTable * colhash = get_color_histogram (pConfig -> pImageData , numPixel , pConfig -> fmtChan , & hasAlpha );
646+ if (colhash == NULL ) {
647+ free (fConfig .pImageData );
648+ free (pNewBef );
649+ pGIF -> curResult = CGIF_EALLOC ;
650+ return CGIF_EALLOC ;
651+ }
571652 const uint8_t bDither = !(pConfig -> attrFlags & CGIF_RGB_FRAME_ATTR_NO_DITHERING );
572653 const int sizeLCT = quantize_and_dither (colhash , pConfig -> pImageData , numPixel , pGIF -> config .width , pConfig -> fmtChan , fConfig .pImageData , aPalette , 8 , bDither , hasAlpha , pGIF -> pBefImageData , pGIF -> befFmtChan );
654+ if (sizeLCT == -1 ) {
655+ free_col_hash_table (colhash );
656+ free (fConfig .pImageData );
657+ free (pNewBef );
658+ pGIF -> curResult = CGIF_EALLOC ;
659+ return CGIF_EALLOC ;
660+ }
573661 free_col_hash_table (colhash );
574662
575663 fConfig .numLocalPaletteEntries = sizeLCT ;
0 commit comments