This will allow sharing e.g. document cookie versions between the UI and
WebContent processes, and safely accessing those versions.
Core::AnonymousBuffer internally creates a minimum buffer of PAGE_SIZE
bytes. This is much more than the size of a single version, but this
affords us the opportunity to share multiple versions in a single buffer
between processes. With a PAGE_SIZE of 4096, we can share up to 512
versions in a single buffer.
This commit stops using deprecated WSA functions. While the ANSI
versions are most likely not going anywhere, Windows is natively UTF-16
so it has to convert to ANSI internally. All the ANSI functions in
Winsock are marked as deprecated. The macro suppressing the warnings is
no longer defined.
Add a thread-safe deferred_invoke() API on WeakEventLoopReference that
queues work onto the owning thread's event queue and wakes that thread
via EventLoopManager hooks. This avoids calling wake() from foreign
threads during teardown.
Implement current_thread_handle()/wake_thread() in each backend and
track per-thread data so handles are validated before waking:
- Unix: wake via per-thread wake pipe
- Windows: wake via thread wake event
- macOS: wake via stored CFRunLoopRef
- Qt: wake via event target or QEventLoop::wakeUp()
- Android: wake via stored ALooper
The mmap() call here served no purpose - anon_create() is only meant to
create and return a file descriptor. The actual mapping is done later
by AnonymousBufferImpl::create().
This leaked an mmap of `size` bytes for every AnonymousBuffer created,
which includes backing stores, shareable bitmaps, and more.
When test-web has completed running all tests there is a pending
DeferredInvoke in the main threads event queue. For Unix pthread, the
main threads event queue is leaked as the destructor callback in
pthread_key_create is not invoked. For Windows pthreads4w, the
destructor callback is invoked when the main thread is exiting. When
the main threads event queue is destroyed, the pending DeferredInvoke
event is destroyed which causes a leftover WebContentClient reference
to also get destroyed; however, the static WebContentClient::s_clients
HashTable has already been destroyed at this point, so we get a UAF in
the WebContentClient destructor and ASAN reports that error.
The reason why cleaning up the pending deferred invoke results in a
WebContentClient instance also being cleaned up is that class inherits
from IPC::ConnectionBase which is a Core::EventReceiver. The
deferred_invoke() method exposed on event receivers takes a strong
reference to itself to ensure it is still alive by the time the event
loop is ready to execute the function. There are a couple places in
IPC::ConnectionBase::drain_messages_from_peer() that utilized deferred
invocation which is why we have a leftover WebContentClient that has
past its useful lifetime at the end of TestWeb::run_tests().
Instead of holding onto a strong reference when the event has not yet
been processed, we take a weak reference and only grab a strong ref if
the receiver is alive when the event loop is about to execute our
function.
This fixes an issue where RequestServer would churn as poll() returned
immediately due to a file descriptor yielding POLLHUP.
In that case, we should just wake the notifier and let it figure out
what to do.
For some reason, writing to the wake fd from the same thread in
deferred_invoke was causing a deadlock. However, we don't actually need
to wake from the same thread, since the event loop is not waiting and
will therefore process the deferred_invoke on the next iteration.
This issue was introduced in 3742138cc3.
The deadlock could be reproduced consistently by increasing
LOCAL_STORAGE_QUOTA in StorageJar.cpp to a large value like 50 MiB.
Since the event loop has a very specifically scoped lifetime, we can't
ensure that it outlives threads that hold a reference to it without
blocking the thread that owns it. In order to make threads use the
event loop safely, we now have an atomically ref-counted
WeakEventLoopReference class that can be passed off to threads to
safely post events/callbacks to it.
Another possibility was to use an RWLock per event loop that each
thread holds a read lock on, while ~EventLoop() uses a write lock to
block and prevent it being destroyed until all its threads exit.
However, media data providers don't receive a signal to exit due to the
GC heap being intentionally leaked, so the process never actually
exits. It would be possible to specifically drop the reference to
PlaybackManager in HTMLMediaElement in order to make those data
providers die on their own, but that doesn't help prevent this problem
in other cases where it may arise.