Skip to content

Commit 6595663

Browse files
committed
fix(cgif_rgb): add NULL checks after malloc/realloc and fix integer overflow
1 parent dcd45c7 commit 6595663

1 file changed

Lines changed: 60 additions & 16 deletions

File tree

src/cgif_rgb.c

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,25 @@ 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) return NULL;
132133
colhash->tableSize = getNextPrimePower2(tableSize); // increase table size to next prime number
133-
colhash->frequ = malloc(sizeof(uint32_t) * colhash->tableSize);
134+
colhash->frequ = malloc(sizeof(uint32_t) * colhash->tableSize);
134135
colhash->hashTable = malloc(3 * colhash->tableSize);
135136
colhash->indexUsed = malloc(colhash->tableSize);
136-
colhash->pPalette = malloc(3 * colhash->tableSize);
137-
colhash->colIdx = malloc(sizeof(uint32_t)*colhash->tableSize);
137+
colhash->pPalette = malloc(3 * colhash->tableSize);
138+
colhash->colIdx = malloc(sizeof(uint32_t) * colhash->tableSize);
139+
if(colhash->frequ == NULL || colhash->hashTable == NULL || colhash->indexUsed == NULL ||
140+
colhash->pPalette == NULL || colhash->colIdx == NULL) {
141+
free(colhash->frequ);
142+
free(colhash->hashTable);
143+
free(colhash->indexUsed);
144+
free(colhash->pPalette);
145+
free(colhash->colIdx);
146+
free(colhash);
147+
return NULL;
148+
}
138149
colhash->cnt = 0; // no colors initially
139-
memset(colhash->pPalette, 0, 3 * colhash->tableSize); // unused part of color table is uninitialized otheriwse
150+
memset(colhash->pPalette, 0, 3 * colhash->tableSize); // unused part of color table is uninitialized otherwise
140151
memset(colhash->indexUsed, 0, colhash->tableSize); // initially no entry in hash-table is used
141152
return colhash;
142153
}
@@ -154,12 +165,25 @@ static void free_col_hash_table(colHashTable* colhash){
154165
/* increase the size of the color hash table */
155166
static void resize_col_hash_table(colHashTable* colhash){
156167
uint32_t tableSizeNew;
157-
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);
160-
uint8_t* hashTable_new = malloc(3 * tableSizeNew);
161-
uint8_t* indexUsed_new = malloc(tableSizeNew);
162-
uint32_t* frequ_new = malloc(sizeof(uint32_t) * tableSizeNew);
168+
tableSizeNew = getNextPrimePower2(colhash->tableSize); // increase table size to the next prime number above the next power of two
169+
uint8_t* pPalette_new = realloc(colhash->pPalette, 3 * tableSizeNew);
170+
uint32_t* colIdx_new = realloc(colhash->colIdx, sizeof(uint32_t) * tableSizeNew);
171+
uint8_t* hashTable_new = malloc(3 * tableSizeNew);
172+
uint8_t* indexUsed_new = malloc(tableSizeNew);
173+
uint32_t* frequ_new = malloc(sizeof(uint32_t) * tableSizeNew);
174+
if(pPalette_new == NULL || colIdx_new == NULL || hashTable_new == NULL ||
175+
indexUsed_new == NULL || frequ_new == NULL) {
176+
// realloc failure: original pointers may be freed or unchanged; clean up and leave colhash intact
177+
free(hashTable_new);
178+
free(indexUsed_new);
179+
free(frequ_new);
180+
// if realloc returned NULL, original pointer is still valid
181+
if(pPalette_new != NULL) colhash->pPalette = pPalette_new;
182+
if(colIdx_new != NULL) colhash->colIdx = colIdx_new;
183+
return;
184+
}
185+
colhash->pPalette = pPalette_new;
186+
colhash->colIdx = colIdx_new;
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
@@ -176,15 +200,16 @@ static void resize_col_hash_table(colHashTable* colhash){
176200
colhash->tableSize = tableSizeNew;
177201
free(colhash->hashTable); // free part of old hash table that is not used anymore
178202
free(colhash->indexUsed); // free part of old hash table that is not used anymore
179-
free(colhash->frequ); // free part of old hash table that is not used anymore
203+
free(colhash->frequ); // free part of old hash table that is not used anymore
180204
colhash->hashTable = hashTable_new; // pass pointer to new hash table
181205
colhash->indexUsed = indexUsed_new; // pass pointer to new hash table
182-
colhash->frequ = frequ_new; // pass pointer to new hash table
206+
colhash->frequ = frequ_new; // pass pointer to new hash table
183207
}
184208

185209
/* take frequ indexed by hash(rgb) and return corresponding dense array */
186210
static uint32_t* hash_to_dense(colHashTable* colhash, cgif_chan_fmt fmtChan) {
187211
uint32_t* frequDense = malloc(sizeof(uint32_t) * colhash->cnt);
212+
if(frequDense == NULL) return NULL;
188213
uint32_t h;
189214
(void)fmtChan;
190215
for(uint32_t i = 0; i < colhash->cnt; ++i) {
@@ -243,6 +268,7 @@ static treeNode* new_tree_node(uint8_t* pPalette, uint32_t* frequ, uint16_t* num
243268
float var[3];
244269

245270
treeNode* node = malloc(sizeof(treeNode));
271+
if(node == NULL) return NULL;
246272
node->idxMin = idxMin; // minimum color in pPalette belonging to the node
247273
node->idxMax = idxMax; // maximum color in pPalette belonging to the node
248274
get_variance(pPalette, frequ, idxMin, idxMax, var, node->mean);
@@ -488,10 +514,18 @@ static uint32_t quantize_and_dither(colHashTable* colhash, const uint8_t* pImage
488514
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
489515
if(colhash->cnt > colMax) { // color-quantization is needed
490516
uint32_t* pFrequDense = hash_to_dense(colhash, fmtChan);
517+
if(pFrequDense == NULL) return 0;
491518
treeNode* root = create_decision_tree(colhash->pPalette, pFrequDense, pPalette256, colhash->cnt, colMax, depthMax); // create decision tree (dynamic, splits along rgb-dimension with highest variance)
492519
free(pFrequDense);
493-
float* pImageDataRGBfloat = malloc(fmtChan * numPixel * sizeof(float)); // TBD fmtChan + only when hasAlpha
494-
for(uint32_t i = 0; i < fmtChan * numPixel; ++i){
520+
if(root == NULL) return 0;
521+
// Guard against integer overflow: fmtChan (uint8_t) * numPixel (uint32_t) can overflow uint32_t
522+
size_t floatBufSize = (size_t)fmtChan * (size_t)numPixel * sizeof(float);
523+
float* pImageDataRGBfloat = malloc(floatBufSize);
524+
if(pImageDataRGBfloat == NULL) {
525+
free_decision_tree(root);
526+
return 0;
527+
}
528+
for(uint32_t i = 0; i < (size_t)fmtChan * numPixel; ++i){
495529
pImageDataRGBfloat[i] = pImageDataRGB[i];
496530
}
497531
uint8_t transIndex = colMax;
@@ -519,8 +553,9 @@ static uint32_t quantize_and_dither(colHashTable* colhash, const uint8_t* pImage
519553
CGIFrgb* cgif_rgb_newgif(const CGIFrgb_Config* pConfig) {
520554
CGIF_Config idxConfig = {0};
521555
CGIFrgb* pGIFrgb;
522-
556+
523557
pGIFrgb = malloc(sizeof(CGIFrgb));
558+
if(pGIFrgb == NULL) return NULL;
524559
memset(pGIFrgb, 0, sizeof(CGIFrgb));
525560
idxConfig.pWriteFn = pConfig->pWriteFn;
526561
idxConfig.pContext = pConfig->pContext;
@@ -536,7 +571,7 @@ CGIFrgb* cgif_rgb_newgif(const CGIFrgb_Config* pConfig) {
536571
}
537572
pGIFrgb->config = *pConfig;
538573
pGIFrgb->curResult = CGIF_PENDING;
539-
return pGIFrgb;
574+
return pGIFrgb;
540575
}
541576

542577
cgif_result cgif_rgb_addframe(CGIFrgb* pGIF, const CGIFrgb_FrameConfig* pConfig) {
@@ -558,9 +593,18 @@ cgif_result cgif_rgb_addframe(CGIFrgb* pGIF, const CGIFrgb_FrameConfig* pConfig)
558593
return CGIF_ERROR;
559594
}
560595
pNewBef = malloc(pConfig->fmtChan * MULU16(imageWidth, imageHeight));
596+
if(pNewBef == NULL) {
597+
pGIF->curResult = CGIF_ERROR;
598+
return CGIF_ERROR;
599+
}
561600
memcpy(pNewBef, pConfig->pImageData, pConfig->fmtChan * MULU16(imageWidth, imageHeight));
562601
fConfig.pLocalPalette = aPalette;
563602
fConfig.pImageData = malloc(pGIF->config.width * (uint32_t)pGIF->config.height);
603+
if(fConfig.pImageData == NULL) {
604+
free(pNewBef);
605+
pGIF->curResult = CGIF_ERROR;
606+
return CGIF_ERROR;
607+
}
564608
fConfig.delay = pConfig->delay;
565609
fConfig.attrFlags = CGIF_FRAME_ATTR_USE_LOCAL_TABLE;
566610
if(pConfig->attrFlags & CGIF_RGB_FRAME_ATTR_INTERLACED) {

0 commit comments

Comments
 (0)