Skip to content

Commit 1342e4e

Browse files
cfsmp3claude
andcommitted
fix(ocr): add NULL checks and fix memory leaks
- search_language_pack: add NULL check after strdup(), fix unsafe realloc() that lost original pointer on failure - init_ocr: fix memory leak where ctx wasn't freed on early return when tessdata not found, add NULL checks for strdup() calls - ocr_bitmap: fix memory leak when pixCreate partially fails, add missing boxDestroy for crop_points on early return, add NULL checks for histogram/iot/mcit allocations, fix unsafe realloc() calls, add NULL check for text_out strdup - ocr_rect: add NULL check for copy allocation, initialize copy->data to NULL to prevent freep on uninitialized pointer, add NULL check for copy->data allocation - paraof_ocrtext: use fatal() on malloc failure for consistent OOM handling All OOM conditions now use fatal(EXIT_NOT_ENOUGH_MEMORY, ...) following the project's coding patterns. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 4d1d874 commit 1342e4e

File tree

1 file changed

+83
-9
lines changed

1 file changed

+83
-9
lines changed

src/lib_ccx/ocr.c

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,19 @@ static int search_language_pack(const char *dir_name, const char *lang_name)
5050

5151
// Search for a tessdata folder in the specified directory
5252
char *dirname = strdup(dir_name);
53-
dirname = realloc(dirname, strlen(dirname) + strlen("tessdata/") + (dirname[strlen(dirname) - 1] != '/') + 1);
53+
if (!dirname)
54+
{
55+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In search_language_pack: Out of memory allocating dirname.");
56+
}
57+
58+
size_t new_size = strlen(dirname) + strlen("tessdata/") + (dirname[strlen(dirname) - 1] != '/') + 1;
59+
char *new_dirname = realloc(dirname, new_size);
60+
if (!new_dirname)
61+
{
62+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In search_language_pack: Out of memory reallocating dirname.");
63+
}
64+
dirname = new_dirname;
65+
5466
if (dirname[strlen(dirname) - 1] != '/')
5567
strcat(dirname, "/");
5668
strcat(dirname, "tessdata/");
@@ -147,6 +159,7 @@ void *init_ocr(int lang_index)
147159
if (lang_index == 1)
148160
{
149161
mprint("eng.traineddata not found! No Switching Possible\n");
162+
free(ctx);
150163
return NULL;
151164
}
152165
mprint("%s.traineddata not found! Switching to English\n", lang);
@@ -156,12 +169,24 @@ void *init_ocr(int lang_index)
156169
if (!tessdata_path)
157170
{
158171
mprint("eng.traineddata not found! No Switching Possible\n");
172+
free(ctx);
159173
return NULL;
160174
}
161175
}
162176

163177
char *pars_vec = strdup("debug_file");
178+
if (!pars_vec)
179+
{
180+
free(ctx);
181+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In init_ocr: Out of memory allocating pars_vec.");
182+
}
164183
char *pars_values = strdup("tess.log");
184+
if (!pars_values)
185+
{
186+
free(pars_vec);
187+
free(ctx);
188+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In init_ocr: Out of memory allocating pars_values.");
189+
}
165190

166191
ctx->api = TessBaseAPICreate();
167192
if (!strncmp("4.", TessVersion(), 2) || !strncmp("5.", TessVersion(), 2))
@@ -286,6 +311,10 @@ char *ocr_bitmap(void *arg, png_color *palette, png_byte *alpha, unsigned char *
286311
color_pix = pixCreate(w, h, 32);
287312
if (pix == NULL || color_pix == NULL)
288313
{
314+
if (pix)
315+
pixDestroy(&pix);
316+
if (color_pix)
317+
pixDestroy(&color_pix);
289318
return NULL;
290319
}
291320
wpl = pixGetWpl(pix);
@@ -343,6 +372,7 @@ char *ocr_bitmap(void *arg, png_color *palette, png_byte *alpha, unsigned char *
343372
{
344373
mprint("\nIn ocr_bitmap: Failed to perform OCR. Skipped.\n");
345374

375+
boxDestroy(&crop_points);
346376
pixDestroy(&pix);
347377
pixDestroy(&cpix);
348378
pixDestroy(&cpix_gs);
@@ -360,6 +390,10 @@ char *ocr_bitmap(void *arg, png_color *palette, png_byte *alpha, unsigned char *
360390
// and using it directly causes new/free() warnings.
361391
char *text_out = strdup(text_out_from_tes);
362392
TessDeleteText(text_out_from_tes);
393+
if (!text_out)
394+
{
395+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_bitmap: Out of memory allocating text_out.");
396+
}
363397

364398
// Begin color detection
365399
// Using tlt_config.nofontcolor (true when "--nofontcolor" parameter used) to skip color detection if not required
@@ -406,8 +440,20 @@ char *ocr_bitmap(void *arg, png_color *palette, png_byte *alpha, unsigned char *
406440
int max_color = 2;
407441

408442
histogram = (uint32_t *)malloc(copy->nb_colors * sizeof(uint32_t));
443+
if (!histogram)
444+
{
445+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_bitmap: Out of memory allocating histogram.");
446+
}
409447
iot = (uint8_t *)malloc(copy->nb_colors * sizeof(uint8_t));
448+
if (!iot)
449+
{
450+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_bitmap: Out of memory allocating iot.");
451+
}
410452
mcit = (uint32_t *)malloc(copy->nb_colors * sizeof(uint32_t));
453+
if (!mcit)
454+
{
455+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_bitmap: Out of memory allocating mcit.");
456+
}
411457
struct transIntensity ti = {copy->alpha, copy->palette};
412458
memset(histogram, 0, copy->nb_colors * sizeof(uint32_t));
413459

@@ -555,7 +601,12 @@ char *ocr_bitmap(void *arg, png_color *palette, png_byte *alpha, unsigned char *
555601
{
556602
int index = pos - text_out;
557603
// Insert `<font>` tag into `text_out` at the location of `word`/`pos`
558-
text_out = realloc(text_out, text_out_len + substr_len + 1);
604+
char *new_text_out = realloc(text_out, text_out_len + substr_len + 1);
605+
if (!new_text_out)
606+
{
607+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_bitmap: Out of memory reallocating text_out.");
608+
}
609+
text_out = new_text_out;
559610
// Save the value is that is going to get overwritten by `sprintf`
560611
char replaced_by_null = text_out[index];
561612
memmove(text_out + index + substr_len + 1, text_out + index + 1, text_out_len - index);
@@ -567,7 +618,12 @@ char *ocr_bitmap(void *arg, png_color *palette, png_byte *alpha, unsigned char *
567618
else if (!written_tag)
568619
{
569620
// Insert `substr` at the beginning of `text_out`
570-
text_out = realloc(text_out, text_out_len + substr_len + 1);
621+
char *new_text_out = realloc(text_out, text_out_len + substr_len + 1);
622+
if (!new_text_out)
623+
{
624+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_bitmap: Out of memory reallocating text_out.");
625+
}
626+
text_out = new_text_out;
571627
char replaced_by_null = *text_out;
572628
memmove(text_out + substr_len + 1, text_out + 1, text_out_len);
573629
sprintf(text_out, substr_format, r_avg, g_avg, b_avg);
@@ -596,6 +652,10 @@ char *ocr_bitmap(void *arg, png_color *palette, png_byte *alpha, unsigned char *
596652
char *line_start = text_out;
597653
int length = strlen(text_out) + length_closing_font * 10; // usually enough
598654
char *new_text_out = malloc(length);
655+
if (!new_text_out)
656+
{
657+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_bitmap: Out of memory allocating new_text_out.");
658+
}
599659
char *new_text_out_iter = new_text_out;
600660

601661
char *last_valid_char = text_out; // last character that is not '\n' or '\0'
@@ -631,7 +691,12 @@ char *ocr_bitmap(void *arg, png_color *palette, png_byte *alpha, unsigned char *
631691

632692
length = max(length * 1.5, length_needed);
633693
long diff = new_text_out_iter - new_text_out;
634-
new_text_out = realloc(new_text_out, length);
694+
char *tmp = realloc(new_text_out, length);
695+
if (!tmp)
696+
{
697+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_bitmap: Out of memory reallocating new_text_out.");
698+
}
699+
new_text_out = tmp;
635700
new_text_out_iter = new_text_out + diff;
636701
}
637702

@@ -898,22 +963,25 @@ int ocr_rect(void *arg, struct cc_bitmap *rect, char **str, int bgcolor, int ocr
898963

899964
struct image_copy *copy;
900965
copy = (struct image_copy *)malloc(sizeof(struct image_copy));
966+
if (!copy)
967+
{
968+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_rect: Out of memory allocating copy.");
969+
}
901970
copy->nb_colors = rect->nb_colors;
902971
copy->palette = (png_color *)malloc(rect->nb_colors * sizeof(png_color));
903972
copy->alpha = (png_byte *)malloc(rect->nb_colors * sizeof(png_byte));
904973
copy->bgcolor = bgcolor;
974+
copy->data = NULL; // Initialize to NULL in case of early goto end
905975

906976
palette = (png_color *)malloc(rect->nb_colors * sizeof(png_color));
907977
if (!palette || !copy->palette)
908978
{
909-
ret = -1;
910-
goto end;
979+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_rect: Out of memory allocating palette.");
911980
}
912981
alpha = (png_byte *)malloc(rect->nb_colors * sizeof(png_byte));
913982
if (!alpha || !copy->alpha)
914983
{
915-
ret = -1;
916-
goto end;
984+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_rect: Out of memory allocating alpha.");
917985
}
918986

919987
mapclut_paletee(palette, alpha, (uint32_t *)rect->data1, rect->nb_colors);
@@ -931,6 +999,10 @@ int ocr_rect(void *arg, struct cc_bitmap *rect, char **str, int bgcolor, int ocr
931999
}
9321000

9331001
copy->data = (unsigned char *)malloc(sizeof(unsigned char) * size);
1002+
if (!copy->data)
1003+
{
1004+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In ocr_rect: Out of memory allocating copy->data.");
1005+
}
9341006
for (int i = 0; i < size; i++)
9351007
{
9361008
copy->data[i] = rect->data0[i];
@@ -1068,7 +1140,9 @@ char *paraof_ocrtext(struct cc_subtitle *sub, struct encoder_ctx *context)
10681140
{
10691141
str = malloc(len + 1 + 10); // Extra space for possible trailing '/n's at the end of tesseract UTF8 text
10701142
if (!str)
1071-
return NULL;
1143+
{
1144+
fatal(EXIT_NOT_ENOUGH_MEMORY, "In paraof_ocrtext: Out of memory allocating str.");
1145+
}
10721146
*str = '\0';
10731147
}
10741148

0 commit comments

Comments
 (0)