Fix unchecked strdup() return values in lib_ccx (#2213)

Two related strdup bugs across multiple lib_ccx files:

1. strdup(variable) return not checked for NULL — use after potential
   NULL dereference causes undefined behavior / segfault on OOM.
   Fixed by adding NULL check + fatal(EXIT_NOT_ENOUGH_MEMORY, ...).

2. strdup("literal") in get_buffer_type_str returned directly as
   function result — unchecked and leaks memory on every call since
   the function has no callers that free it.  Fixed by removing strdup
   and returning string literals directly; return type changed from
   char * to const char * (no callers exist, no header declaration).

Files changed:
  src/lib_ccx/ccx_common_common.c
  src/lib_ccx/ccx_encoders_common.c
  src/lib_ccx/ccx_encoders_helpers.c
  src/lib_ccx/configuration.c
  src/lib_ccx/hardsubx.c
  src/lib_ccx/hardsubx_decoder.c
  src/lib_ccx/ocr.c
  src/lib_ccx/output.c
  src/lib_ccx/ts_functions.c

Fixes #2194

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Abhijeet Kumar
2026-03-29 00:29:35 +05:30
committed by GitHub
parent 159b2193f4
commit 8e4bcfc0cb
9 changed files with 58 additions and 11 deletions

View File

@@ -59,6 +59,9 @@ int add_cc_sub_text(struct cc_subtitle *sub, char *str, LLONG start_time,
sub->type = CC_TEXT;
sub->enc_type = e_type;
sub->data = strdup(str);
if (sub->data == NULL)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY,
"In add_cc_sub_text: Not enough memory for subtitle data.\n");
sub->datatype = CC_DATATYPE_GENERIC;
sub->nb_data = str ? strlen(str) : 0;
sub->start_time = start_time;

View File

@@ -607,7 +607,11 @@ static int init_output_ctx(struct encoder_ctx *ctx, struct encoder_cfg *cfg)
char *basefilename = get_basename(cfg->output_filename);
extension = get_file_extension(cfg->write_format);
ret = init_write(&ctx->out[0], strdup(cfg->output_filename), cfg->with_semaphore);
char *fname0 = strdup(cfg->output_filename);
if (fname0 == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In init_output_ctx: Not enough memory for output filename.\n");
ret = init_write(&ctx->out[0], fname0, cfg->with_semaphore);
check_ret(cfg->output_filename);
ret = init_write(&ctx->out[1], create_outfilename(basefilename, "_2", extension), cfg->with_semaphore);
check_ret(ctx->out[1].filename);
@@ -615,7 +619,11 @@ static int init_output_ctx(struct encoder_ctx *ctx, struct encoder_cfg *cfg)
}
else
{
ret = init_write(ctx->out, strdup(cfg->output_filename), cfg->with_semaphore);
char *fname = strdup(cfg->output_filename);
if (fname == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In init_output_ctx: Not enough memory for output filename.\n");
ret = init_write(ctx->out, fname, cfg->with_semaphore);
check_ret(cfg->output_filename);
}
}

View File

@@ -98,6 +98,9 @@ void call_function_if_match(unsigned char *line, struct word_list *list, void (*
'{', '|', '}', '~', '\0'};
unsigned char *line_token = strdup(line);
if (line_token == NULL)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY,
"In call_function_if_match: Not enough memory for line copy.\n");
unsigned char *c = strtok(line_token, delim);
if (c != NULL)
@@ -127,6 +130,9 @@ void telx_correct_case(char *sub_line)
'{', '|', '}', '~', '\0'};
char *line = strdup(((char *)sub_line));
if (line == NULL)
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY,
"In telx_correct_case: Not enough memory for line copy.\n");
char *oline = (char *)sub_line;
char *c = strtok(line, delim);
if (c == NULL)

View File

@@ -19,6 +19,9 @@ static int set_string(void *var, char *val)
return -1;
val1 = strdup(val);
if (val1 == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In set_string: Not enough memory for string copy.\n");
*p = val1;
return 0;
}

View File

@@ -233,7 +233,16 @@ struct lib_hardsubx_ctx *_init_hardsubx(struct ccx_s_options *options)
ctx->tess_handle = TessBaseAPICreate();
char *pars_vec = strdup("debug_file");
if (pars_vec == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In _init_hardsubx: Not enough memory for pars_vec.\n");
char *pars_values = strdup("/dev/null");
if (pars_values == NULL)
{
free(pars_vec);
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In _init_hardsubx: Not enough memory for pars_values.\n");
}
char *tessdata_path = NULL;
char *lang = (char *)options->ocrlang;

View File

@@ -227,6 +227,9 @@ void hardsubx_process_frames_linear(struct lib_hardsubx_ctx *ctx, struct encoder
if (subtitle_text)
{
prev_subtitle_text = strdup(subtitle_text);
if (prev_subtitle_text == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In hardsubx_process_frames_linear: Not enough memory for subtitle text.\n");
prev_sub_encoded = 0;
}
}
@@ -251,6 +254,9 @@ void hardsubx_process_frames_linear(struct lib_hardsubx_ctx *ctx, struct encoder
prev_begin_time = prev_end_time + 1;
prev_end_time = convert_pts_to_ms(ctx->packet.pts, ctx->format_ctx->streams[ctx->video_stream_id]->time_base);
prev_subtitle_text = strdup(subtitle_text);
if (prev_subtitle_text == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In hardsubx_process_frames_linear: Not enough memory for subtitle text.\n");
prev_sub_encoded = 0;
}
prev_packet_pts = ctx->packet.pts;
@@ -514,6 +520,9 @@ void process_hardsubx_linear_frames_and_normal_subs(struct lib_hardsubx_ctx *har
if (subtitle_text_hard)
{
prev_subtitle_text_hard = strdup(subtitle_text_hard);
if (prev_subtitle_text_hard == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In process_hardsubx_linear_frames_and_normal_subs: Not enough memory for subtitle text.\n");
prev_sub_encoded_hard = 0;
}
}
@@ -525,6 +534,9 @@ void process_hardsubx_linear_frames_and_normal_subs(struct lib_hardsubx_ctx *har
prev_begin_time_hard = prev_end_time_hard + 1;
prev_end_time_hard = convert_pts_to_ms(hard_ctx->packet.pts, hard_ctx->format_ctx->streams[hard_ctx->video_stream_id]->time_base);
prev_subtitle_text_hard = strdup(subtitle_text_hard);
if (prev_subtitle_text_hard == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In process_hardsubx_linear_frames_and_normal_subs: Not enough memory for subtitle text.\n");
prev_sub_encoded_hard = 0;
}
prev_packet_pts_hard = hard_ctx->packet.pts;

View File

@@ -519,6 +519,9 @@ static char *ocr_single_line(struct ocrCtx *ctx, PIX *line_pix)
{
text = strdup(tess_text);
TessDeleteText(tess_text);
if (text == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In ocr_single_line: Not enough memory for OCR text.\n");
}
}

View File

@@ -70,6 +70,9 @@ int init_write(struct ccx_s_write *wb, char *filename, int with_semaphore)
wb->temporarily_closed = 0;
wb->filename = filename;
wb->original_filename = strdup(filename);
if (wb->original_filename == NULL)
fatal(EXIT_NOT_ENOUGH_MEMORY,
"In init_write: Not enough memory for original filename.\n");
wb->with_semaphore = with_semaphore;
wb->append_mode = ccx_options.enc_cfg.append_mode;

View File

@@ -27,39 +27,39 @@ uint64_t last_pts = 0; // PTS of last PES packet (debug purposes)
// Descriptions for ts ccx_stream_type
const char *desc[256];
char *get_buffer_type_str(struct cap_info *cinfo)
const char *get_buffer_type_str(struct cap_info *cinfo)
{
if (cinfo->stream == CCX_STREAM_TYPE_VIDEO_MPEG2)
{
return strdup("MPG");
return "MPG";
}
else if (cinfo->stream == CCX_STREAM_TYPE_VIDEO_H264)
{
return strdup("H.264");
return "H.264";
}
else if (cinfo->stream == CCX_STREAM_TYPE_VIDEO_HEVC)
{
return strdup("HEVC");
return "HEVC";
}
else if (cinfo->stream == CCX_STREAM_TYPE_PRIVATE_MPEG2 && cinfo->codec == CCX_CODEC_ISDB_CC)
{
return strdup("ISDB CC subtitle");
return "ISDB CC subtitle";
}
else if (cinfo->stream == CCX_STREAM_TYPE_PRIVATE_MPEG2 && cinfo->codec == CCX_CODEC_DVB)
{
return strdup("DVB subtitle");
return "DVB subtitle";
}
else if (cinfo->stream == CCX_STREAM_TYPE_UNKNOWNSTREAM && ccx_options.hauppauge_mode)
{
return strdup("Hauppage");
return "Hauppage";
}
else if (cinfo->stream == CCX_STREAM_TYPE_PRIVATE_MPEG2 && cinfo->codec == CCX_CODEC_TELETEXT)
{
return strdup("Teletext");
return "Teletext";
}
else if (cinfo->stream == CCX_STREAM_TYPE_PRIVATE_MPEG2 && cinfo->codec == CCX_CODEC_ATSC_CC)
{
return strdup("CC in private MPEG packet");
return "CC in private MPEG packet";
}
else
{