Skip to content

fix(core): end the argv array with NULL - #70

Merged
Project516 merged 2 commits into
masterfrom
fix/mt-exec-after-timeout
Oct 5, 2026
Merged

Project516 merged 2 commits into
masterfrom
fix/mt-exec-after-timeout

Conversation

@Project516

@Project516 Project516 commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

What

exec() and ffprobe() passed ffmpeg an argv array with no NULL after the last argument. fftools reads argv[argc] when the last argument is an option, so a trailing -h, -version or -formats read whatever the heap held past the allocation. Most of the time that is a harmless pointer. Sometimes it is not, and the core throws RuntimeError: memory access out of bounds.

The fix allocates one more slot and writes NULL into it.

Root cause

The failing master run (37342775756, [ffmpeg-core][mt] setLogger() should handle logs) has this wasm stack, outermost last:

function what it is
105 strlen
179 strdup
19313 show_help, which calls av_strdup(arg ? arg : "")
8885 write_option, which calls the option's func_arg
3913, 19280 ffmpeg() and the exported _ffmpeg

I identified them by disassembling the run's own core artifact. parse_options calls parse_option(optctx, opt, argv[optindex], ...), so for -h as the last argument arg is argv[argc]. stringsToPtr() allocated exactly argc slots, so that is the word after a 16-byte allocation, and it is whatever the previous heap user left.

Reproduced on the unfixed core from that run:

  • Setting argv[argc] to NULL by hand runs -h fine. Setting it to 0x7ffffff0 throws the same error with the same six frames.
  • The word after a fresh 16-byte allocation is 0. After any exec(), timed out or not, it is a non-zero heap value (e45db4, 93aa7e8, ...). A pointer into valid memory only makes strdup read garbage. A value that is out of range, or that has no NUL before the end of memory, traps.

So the timeout was not the cause. It changed the heap contents, which made the crash show up there. The #63 case (lavfi with a 50 ms timeout, then exec -h) is the same bug. The single-thread core has the same defect, since both share bind.js. A poisoned allocation traps it too.

The timeout path itself is sound. sch_stop() joins every scheduler thread before exec() returns, and five timeout and exec rounds in a row pass on both cores with the fix. No core restart or wrapper change is needed.

Tests

  • exec() argv fills every _malloc made by exec() with a bad pointer, then runs exec("-h"). It fails on the unfixed core (mt and st, locally against the CI artifacts of master) and passes now.
  • exec() after a timeout runs timeout, -h and a transcode five times in a row.
  • The existing timeout tests are unchanged.

Noticed, not fixed

None.

@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 72a1f579-a431-449a-9634-0fa1c0226898
📥 Commits

Reviewing files that changed from the base of the PR and between 36bf577 and 9114ef4.

📒 Files selected for processing (2)
  • src/bind/ffmpeg/bind.js
  • tests/ffmpeg-core.test.js
 ____________________________________________________________________________________________________________________________________________________________________________________________
< Use exceptions for exceptional problems. Exceptions can suffer from all the readability and maintainability problems of classic spaghetti code. Reserve exceptions for exceptional things. >
 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
✨ Simplify code
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Project516 Project516 changed the title fix: end the argv array with NULL fix(core): end the argv array with NULL Oct 5, 2026
@Project516
Project516 marked this pull request as ready for review October 5, 2026 21:26

@project516-review-bot project516-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR fixes a missing NULL terminator in the argv array passed to ffmpeg. The stringsToPtr function now allocates one extra slot and writes NULL into it, preventing fftools from reading past the array when the last argument is an option like -h. Two tests are added: one that poisons the heap to catch a missing terminator, and one that verifies repeated timeout/exec cycles work.


review-bot, model nvidia/nemotron-3-ultra-550b-a55b:free, verdict approve

@Project516
Project516 merged commit bed7e59 into master Oct 5, 2026
68 of 74 checks passed
@Project516
Project516 deleted the fix/mt-exec-after-timeout branch October 5, 2026 21:29
@Project516 Project516 mentioned this pull request Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant