Skip to content

Commit d78dbe8

Browse files
wysaidclaude
andcommitted
refactor(macos): drop the C++ wait helper, keep the minimal GCD fix
The deadlock was caused solely by dispatch_async'ing the permission request onto the main queue, which never runs when no run loop services it. The fix is just to delete that bounce and call requestAccessForMediaType: directly on the calling thread, keeping the original dispatch_semaphore wait. The earlier ccap_apple_async.h helper (std::mutex/condition_variable) and its unit test were introduced only to make the path portable-C++-testable, but the file was macOS-only (portability was moot), the cv-on-the-stack rewrite introduced its own destroy-after-notify UAF, and the test never exercised ProviderApple::open() -- it tested the invented helper, not the real code path. GCD's dispatch_semaphore is simpler and, because the completion block retains the semaphore, has no destroy race. Removes src/ccap_apple_async.h and tests/test_apple_permission.cpp. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 150f212 commit d78dbe8

4 files changed

Lines changed: 12 additions & 177 deletions

File tree

src/ccap_apple_async.h

Lines changed: 0 additions & 61 deletions
This file was deleted.

src/ccap_imp_apple.mm

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include "ccap_imp_apple.h"
1212
#include "ccap_file_reader_apple.h"
1313

14-
#include "ccap_apple_async.h"
1514
#include "ccap_convert.h"
1615
#include "ccap_convert_frame.h"
1716

@@ -20,7 +19,6 @@
2019
#import <Foundation/Foundation.h>
2120
#include <cassert>
2221
#include <cmath>
23-
#include <functional>
2422

2523
#if _CCAP_LOG_ENABLED_
2624
#include <deque>
@@ -257,22 +255,19 @@ - (instancetype)initWithProvider:(ProviderApple*)provider {
257255
- (BOOL)open {
258256
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
259257
if (authStatus == AVAuthorizationStatusNotDetermined) {
258+
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
260259
CCAP_NSLOG_I(@"ccap: Waiting for camera access permission...");
261-
// Request authorization on the calling thread and block until the system's
262-
// completion handler fires. We deliberately do NOT dispatch the request onto the
263-
// main queue: requestAccessForMediaType: may be called from any thread and
264-
// delivers its completion on an internal queue, so bouncing to the main queue
265-
// would deadlock whenever no run loop is servicing it (e.g. a ccap::Provider
266-
// opened from a worker thread in a process without a CFRunLoop). See
267-
// tests/test_apple_permission.cpp.
268-
ccap::runBlockingAsyncRequest([](const std::function<void()>& done) {
269-
std::function<void()> notifyDone = done; // outlive the async completion
270-
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
271-
completionHandler:^(BOOL granted) {
272-
CCAP_NSLOG_I(@"ccap: Camera access %@", granted ? @"granted" : @"denied");
273-
notifyDone();
274-
}];
275-
});
260+
// Request authorization on the calling thread. requestAccessForMediaType: may be
261+
// called from any thread and delivers its completion on an internal queue, so we
262+
// do NOT bounce the request onto the main queue: that deadlocks whenever no run
263+
// loop is servicing the main queue (e.g. a ccap::Provider opened from a worker
264+
// thread in a process without a CFRunLoop, such as a Node.js/Electron addon).
265+
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
266+
completionHandler:^(BOOL granted) {
267+
CCAP_NSLOG_I(@"ccap: Camera access %@", granted ? @"granted" : @"denied");
268+
dispatch_semaphore_signal(sema);
269+
}];
270+
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
276271
authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
277272
}
278273

tests/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ add_executable(
203203
test_frame_conversions.cpp
204204
test_boundary_conditions.cpp
205205
test_grab_timeout.cpp
206-
test_apple_permission.cpp # macOS camera-permission deadlock regression (empty TU elsewhere)
207206
)
208207

209208
target_link_libraries(

tests/test_apple_permission.cpp

Lines changed: 0 additions & 98 deletions
This file was deleted.

0 commit comments

Comments
 (0)