mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-14 23:22:52 +00:00
When doing the last unref() on a listed-ref-counted object, we keep the list locked while mutating the ref count. The destructor itself is invoked after unlocking the list. This was racy with weakable classes, since their weak pointer factory still pointed to the object after we'd decided to destroy it. That opened a small time window where someone could try to strong-ref a weak pointer to an object after it was removed from the list, but just before the destructor got invoked. This patch closes the race window by explicitly revoking all weak pointers while the list is locked.
118 lines
2.8 KiB
C++
118 lines
2.8 KiB
C++
/*
|
|
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/Singleton.h>
|
|
#include <Kernel/Debug.h>
|
|
#include <Kernel/FileSystem/DevPtsFS.h>
|
|
#include <Kernel/Process.h>
|
|
#include <Kernel/TTY/MasterPTY.h>
|
|
#include <Kernel/TTY/SlavePTY.h>
|
|
|
|
namespace Kernel {
|
|
|
|
static Singleton<SpinlockProtected<SlavePTY::List>> s_all_instances;
|
|
|
|
SpinlockProtected<SlavePTY::List>& SlavePTY::all_instances()
|
|
{
|
|
return s_all_instances;
|
|
}
|
|
|
|
bool SlavePTY::unref() const
|
|
{
|
|
bool did_hit_zero = SlavePTY::all_instances().with([&](auto&) {
|
|
if (deref_base())
|
|
return false;
|
|
m_list_node.remove();
|
|
const_cast<SlavePTY&>(*this).revoke_weak_ptrs();
|
|
return true;
|
|
});
|
|
if (did_hit_zero) {
|
|
const_cast<SlavePTY&>(*this).will_be_destroyed();
|
|
delete this;
|
|
}
|
|
return did_hit_zero;
|
|
}
|
|
|
|
SlavePTY::SlavePTY(MasterPTY& master, unsigned index, NonnullOwnPtr<KString> tty_name)
|
|
: TTY(201, index)
|
|
, m_master(master)
|
|
, m_index(index)
|
|
, m_tty_name(move(tty_name))
|
|
{
|
|
auto& process = Process::current();
|
|
set_uid(process.uid());
|
|
set_gid(process.gid());
|
|
set_size(80, 25);
|
|
|
|
SlavePTY::all_instances().with([&](auto& list) { list.append(*this); });
|
|
}
|
|
|
|
SlavePTY::~SlavePTY()
|
|
{
|
|
dbgln_if(SLAVEPTY_DEBUG, "~SlavePTY({})", m_index);
|
|
}
|
|
|
|
KString const& SlavePTY::tty_name() const
|
|
{
|
|
return *m_tty_name;
|
|
}
|
|
|
|
void SlavePTY::echo(u8 ch)
|
|
{
|
|
if (should_echo_input()) {
|
|
auto buffer = UserOrKernelBuffer::for_kernel_buffer(&ch);
|
|
[[maybe_unused]] auto result = m_master->on_slave_write(buffer, 1);
|
|
}
|
|
}
|
|
|
|
void SlavePTY::on_master_write(const UserOrKernelBuffer& buffer, size_t size)
|
|
{
|
|
auto result = buffer.read_buffered<128>(size, [&](ReadonlyBytes data) {
|
|
for (const auto& byte : data)
|
|
emit(byte, false);
|
|
return data.size();
|
|
});
|
|
if (!result.is_error())
|
|
evaluate_block_conditions();
|
|
}
|
|
|
|
ErrorOr<size_t> SlavePTY::on_tty_write(const UserOrKernelBuffer& data, size_t size)
|
|
{
|
|
m_time_of_last_write = kgettimeofday().to_truncated_seconds();
|
|
return m_master->on_slave_write(data, size);
|
|
}
|
|
|
|
bool SlavePTY::can_write(const OpenFileDescription&, size_t) const
|
|
{
|
|
return m_master->can_write_from_slave();
|
|
}
|
|
|
|
bool SlavePTY::can_read(const OpenFileDescription& description, size_t offset) const
|
|
{
|
|
if (m_master->is_closed())
|
|
return true;
|
|
return TTY::can_read(description, offset);
|
|
}
|
|
|
|
ErrorOr<size_t> SlavePTY::read(OpenFileDescription& description, u64 offset, UserOrKernelBuffer& buffer, size_t size)
|
|
{
|
|
if (m_master->is_closed())
|
|
return 0;
|
|
return TTY::read(description, offset, buffer, size);
|
|
}
|
|
|
|
ErrorOr<void> SlavePTY::close()
|
|
{
|
|
m_master->notify_slave_closed({});
|
|
return {};
|
|
}
|
|
|
|
FileBlockerSet& SlavePTY::blocker_set()
|
|
{
|
|
return m_master->blocker_set();
|
|
}
|
|
|
|
}
|