From 755984e04751eca712761d8a834de0d5d44dafc9 Mon Sep 17 00:00:00 2001 From: NexionisJake Date: Sun, 22 Mar 2026 17:04:53 +0530 Subject: [PATCH] Fix unchecked strdup() return values in lib_ccx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/lib_ccx/ccx_common_common.c | 3 +++ src/lib_ccx/ccx_encoders_common.c | 12 ++++++++++-- src/lib_ccx/ccx_encoders_helpers.c | 6 ++++++ src/lib_ccx/configuration.c | 3 +++ src/lib_ccx/hardsubx.c | 9 +++++++++ src/lib_ccx/hardsubx_decoder.c | 12 ++++++++++++ src/lib_ccx/ocr.c | 3 +++ src/lib_ccx/output.c | 3 +++ src/lib_ccx/ts_functions.c | 18 +++++++++--------- 9 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/lib_ccx/ccx_common_common.c b/src/lib_ccx/ccx_common_common.c index 0095ede51..37032adc3 100644 --- a/src/lib_ccx/ccx_common_common.c +++ b/src/lib_ccx/ccx_common_common.c @@ -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; diff --git a/src/lib_ccx/ccx_encoders_common.c b/src/lib_ccx/ccx_encoders_common.c index 8cb4b1f07..60ead8641 100644 --- a/src/lib_ccx/ccx_encoders_common.c +++ b/src/lib_ccx/ccx_encoders_common.c @@ -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); } } diff --git a/src/lib_ccx/ccx_encoders_helpers.c b/src/lib_ccx/ccx_encoders_helpers.c index 277659930..9827ba7f5 100644 --- a/src/lib_ccx/ccx_encoders_helpers.c +++ b/src/lib_ccx/ccx_encoders_helpers.c @@ -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) diff --git a/src/lib_ccx/configuration.c b/src/lib_ccx/configuration.c index 76da5a2ba..df8f20f3c 100644 --- a/src/lib_ccx/configuration.c +++ b/src/lib_ccx/configuration.c @@ -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; } diff --git a/src/lib_ccx/hardsubx.c b/src/lib_ccx/hardsubx.c index 7ddff8d44..e9f99f93b 100644 --- a/src/lib_ccx/hardsubx.c +++ b/src/lib_ccx/hardsubx.c @@ -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; diff --git a/src/lib_ccx/hardsubx_decoder.c b/src/lib_ccx/hardsubx_decoder.c index ddfa69914..4c5d51fe3 100644 --- a/src/lib_ccx/hardsubx_decoder.c +++ b/src/lib_ccx/hardsubx_decoder.c @@ -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; diff --git a/src/lib_ccx/ocr.c b/src/lib_ccx/ocr.c index 1b57c7edf..febcb2024 100644 --- a/src/lib_ccx/ocr.c +++ b/src/lib_ccx/ocr.c @@ -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"); } } diff --git a/src/lib_ccx/output.c b/src/lib_ccx/output.c index 492c27141..6604e5856 100644 --- a/src/lib_ccx/output.c +++ b/src/lib_ccx/output.c @@ -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; diff --git a/src/lib_ccx/ts_functions.c b/src/lib_ccx/ts_functions.c index 2f31b0f78..8c8503f51 100644 --- a/src/lib_ccx/ts_functions.c +++ b/src/lib_ccx/ts_functions.c @@ -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 {