Skip to content

[BUG] Segfault in write_webvtt_header(): --out=webvtt --timestamp-map crashes on RCWT/raw input (uninitialised encoder_ctx->timing) #2341

Description

@pranayr710

CCExtractor version: master (907be05), built from source

Necessary information

  • Is this a regression (i.e. did it work before)? Unknown — the uninitialised field predates the --timestamp-map option, so it has likely never worked on these input paths.
  • What platform did you use? Linux (Debian bookworm in Docker, x86-64). Platform-independent — nothing here is OS-specific.
  • What were the used arguments? --out=webvtt --timestamp-map

Video links

The reproducer is 153 bytes, so it is inline below rather than on a file host. Save it with:

base64 -d > sample.rcwt <<'EOF'
zMztzABQAAEAAADoAwAAAAAAAAsABJQgBJSuBJRwBEZJBFLTBFQgBEPBBNBUBElPBM6ABJQvuAsA
AAAAAAALAASUIASUrgSUcATTRQRDTwTOxAQgQwTB0ARUSQRPzgSUL4gTAAAAAAAACwAElCAElK4E
lHAEVMgESVIExCAEQ8EE0FQESU8EzoAElC9YGwAAAAAAAAEABJQs
EOF

sha256: 1e7e3f58151190124b113facc7543ac5ee6d7e230830cda88744de19cc17250c

It is a hand-built RCWT file (per docs/BINARY_FILE_FORMAT.TXT) holding three EIA-608 CC1 pop-on captions at 1 s, 3 s and 5 s. It decodes correctly on master (--out=srt etc. all work), so it is a valid input, not a fuzz artefact. Happy to have it in the regression suite.

Additional information

Symptom

$ ccextractor sample.rcwt --out=webvtt --timestamp-map -o out.vtt
...
Analyzing data in CCExtractor's binary format
Segmentation fault
$ echo $?
139

Without --timestamp-map the same file processes fine (exit 0). With --out=srt --timestamp-map it is also fine. The crash needs webvtt + --timestamp-map.

Backtrace

Program received signal SIGSEGV, Segmentation fault.
#0  write_webvtt_header ()
#1  write_cc_buffer_as_webvtt ()
#2  encode_sub ()
#3  rcwt_loop ()
#4  start_ccx ()
#5  main ()

Root cause

init_encoder() allocates with malloc and never assigns ctx->timing:

https://github.com/CCExtractor/ccextractor/blob/master/src/lib_ccx/ccx_encoders_common.c#L765

struct encoder_ctx *ctx = malloc(sizeof(struct encoder_ctx));

encoder_ctx.timing is assigned in only four places, and none of them covers this path:

Location Condition
general_loop.c:1534 (general_loop) always
general_loop.c:697 (raw_loop) only when write_format == CCX_OF_MCC
general_loop.c:1357 DVB path
mp4.c:892 MP4 path

So rcwt_loop(), process_hex(), and raw_loop() for every non-MCC output format leave ctx->timing holding indeterminate heap contents.

write_webvtt_header() then does:

https://github.com/CCExtractor/ccextractor/blob/master/src/lib_ccx/ccx_encoders_webvtt.c#L215

if (ccx_options.timestamp_map && context->timing != NULL && context->timing->sync_pts2fts_set)

The != NULL guard is the right check, but an indeterminate value is almost never NULL, so it passes and ->sync_pts2fts_set dereferences a wild pointer. Reading an indeterminate value is undefined behaviour in the first place (CWE-457), and the dereference is CWE-824.

This also explains why it is --timestamp-map-specific: that flag is the only thing that makes timing be read at all on this path.

Scope

init_encoder() assigns 60 of the struct's 74 members. Nine are never assigned:

timing, list, dtvcc_writers, dvb_lang, cdp_hdr_seq, next_caption_time, force_dropframe, header_printed_flag, write_previous

Some are filled in by callers, but any that are not are indeterminate. timing is the one currently reachable as a crash.

Suggested fix

Allocate with calloc instead of malloc. One line, no behaviour change for the 60 explicitly-assigned members, and it makes the existing != NULL guard work as intended — with timing == NULL, RCWT input simply skips X-TIMESTAMP-MAP (correct, since sync_pts2fts_set would be 0 anyway).

Verification

Built master and a calloc build from identical source in the same Docker image:

  • crash: exit 139exit 0
  • output across 13 formats (webvtt, srt, sami, ttxt, txt, scc, ssa, smptett, g608, mcc, spupng, simple_xml, rcwt): byte-identical exit codes and SHA-256 hashes before and after
  • --timestamp-map output now matches plain --out=webvtt, i.e. the header is correctly omitted rather than crashing

PR follows.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions