| 22 | MainThreadDispatcher::~MainThreadDispatcher() = default; |
| 23 | |
| 24 | void MainThreadDispatcher::dispatch(Valdi::DispatchFunction* function, bool sync) { |
| 25 | if (sync) { |
| 26 | std::promise<void> promise; |
| 27 | auto future = promise.get_future(); |
| 28 | |
| 29 | // Capture `function` by value (copy the pointer) to avoid a dangling reference. |
| 30 | // The original code used [&] which captured `function` by reference to the stack |
| 31 | // variable. After promise.set_value(), the calling thread wakes up from future.get() |
| 32 | // and could potentially destroy its stack frame before `delete function` executes, |
| 33 | // causing a use-after-free on the `function` pointer itself. |
| 34 | auto wrappedFn = new Valdi::DispatchFunction([function, &promise]() { |
| 35 | (*function)(); |
| 36 | promise.set_value(); |
| 37 | delete function; |
| 38 | }); |
| 39 | |
| 40 | _runOnMainThreadMethod.call(toObject(), reinterpret_cast<int64_t>(wrappedFn)); |
| 41 | future.get(); |
| 42 | } else { |
| 43 | _runOnMainThreadMethod.call(toObject(), reinterpret_cast<int64_t>(function)); |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | void MainThreadDispatcher::dispatchAfter(int64_t delayMs, Valdi::DispatchFunction* function) { |
| 48 | _runOnMainThreadDelayedMethod.call(toObject(), delayMs, reinterpret_cast<int64_t>(function)); |