Skip to content

virtualcam-module: Make placeholder initialization thread-safe - #13728

Open
notr1ch wants to merge 1 commit into
obsproject:masterfrom
notr1ch:r1ch/vcam-placeholder-init-fix
Open

virtualcam-module: Make placeholder initialization thread-safe#13728
notr1ch wants to merge 1 commit into
obsproject:masterfrom
notr1ch:r1ch/vcam-placeholder-init-fix

Conversation

@notr1ch

@notr1ch notr1ch commented Jul 31, 2026

Copy link
Copy Markdown
Member

Description

A single application can create any number of VCamFilter instances, all of which create a thread that tries to initialize the placeholder image. This can result in a race where the placeholder vector gets resized by multiple threads, causing dangling pointers and a crash.

This PR makes placeholder initialization thread-safe by using C++11 function-local static initialization, ensuring only one thread runs the initialization and the rest wait for it. State was moved to a struct to ensure it can be updated and passed around atomically. A missing return check from GdiplusStartup was also added.

Note: this goes against a CODESTYLE.md section that says:

Use thread-safe functions to initialize a function-local static variable

Initialization of function-local static variables is inherently thread-safe in C++11 and later, so adding additional synchronization seemed unnecessary.

Motivation and Context

As the virtual camera gets injected into any application enumerating Directshow devices, we should be a good citizen and not crash the host application.

How Has This Been Tested?

Loaded the new filter and tested that the placeholder appeared. The actual crash I wasn't able to reproduce given it's a race.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • I have read the contributing document.
  • My code has been run through clang-format.
  • My code follows the project's style guidelines
  • My code is not on the master branch.
  • My code has been tested (kind of).
  • All commit messages are properly formatted and commits squashed where appropriate.
  • I have included updates to all appropriate documentation.

@notr1ch notr1ch added kind/bug Categorizes issue or PR as related to a bug. platform/windows Categorizes issue or PR as affecting Windows specifically labels Jul 31, 2026
Comment on lines +138 to 144
if (GdiplusStartup(&token, &si, nullptr) != Status::Ok) {
return Placeholder();
}

Placeholder result = load_placeholder_internal();

GdiplusShutdown(token);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does GdiplusShutdown() only need to be called if GdiplusStartup() succeeds? If it needs to be called all the time, this could instead be something like:

	Placeholder result;
	Status s = GdiplusStartup(&token, &si, nullptr);
	if (s != Status::Ok) {
		result = Placeholder();
	} else {
		result = load_placeholder_internal();
	}

	GdiplusShutdown(token);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The documentation isn't specific, but I imagine a failure means the token isn't returned, so it's undefined behavior to pass it to GdiplusShutdown.

Comment thread plugins/win-dshow/virtualcam-module/placeholder.cpp Outdated
A single application can open any number of VCamFilter instances, all of
which create a thread that tries to initialize the placeholder image.
This can result in a race where the placeholder vector gets resized by
multiple threads, causing dangling pointers and a crash.

This commit makes placeholder initialization thread-safe by using C++11
function-local static initialization, ensuring only one thread runs the
initialization and the rest wait for it. State was moved to a struct to
ensure it can be updated and passed around atomically. A missing return
check from GdiplusStartup was also added.
@notr1ch
notr1ch force-pushed the r1ch/vcam-placeholder-init-fix branch from da8d179 to becd548 Compare July 31, 2026 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bug Categorizes issue or PR as related to a bug. platform/windows Categorizes issue or PR as affecting Windows specifically

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants