Skip to content

Commit 52659ef

Browse files
committed
src/cgif_rgb: fix missing NULL checks for memory allocations
1 parent 6a22c44 commit 52659ef

1 file changed

Lines changed: 97 additions & 9 deletions

File tree

src/cgif_rgb.c

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */
130130
static 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 */
186211
static 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) {
319357
static 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 */
328372
static 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

Comments
 (0)