Backed out 2 changesets (bug 1767514) for causing mochitest failures on browser_fullscreen_warning.js CLOSED TREE
Backed out changeset 53ebc3f919ba (bug 1767514) Backed out changeset 62befea29e73 (bug 1767514)
This commit is contained in:
@@ -195,13 +195,11 @@ void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
|
||||
// Verify that we fit in a "quantum-spaced" jemalloc bucket.
|
||||
static_assert(sizeof(*this) <= 512, "Exceeded expected size class");
|
||||
|
||||
MOZ_RELEASE_ASSERT(kControlBufferHeaderSize >= CMSG_SPACE(0));
|
||||
MOZ_RELEASE_ASSERT(kControlBufferSize >=
|
||||
CMSG_SPACE(sizeof(int) * kControlBufferMaxFds));
|
||||
DCHECK(kControlBufferHeaderSize >= CMSG_SPACE(0));
|
||||
|
||||
mode_ = mode;
|
||||
is_blocked_on_write_ = false;
|
||||
partial_write_.reset();
|
||||
partial_write_iter_.reset();
|
||||
input_buf_offset_ = 0;
|
||||
input_buf_ = mozilla::MakeUnique<char[]>(Channel::kReadBufferSize);
|
||||
input_cmsg_buf_ = mozilla::MakeUnique<char[]>(kControlBufferSize);
|
||||
@@ -573,9 +571,11 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
|
||||
struct msghdr msgh = {0};
|
||||
|
||||
char cmsgBuf[kControlBufferSize];
|
||||
static const int tmp =
|
||||
CMSG_SPACE(sizeof(int[IPC::Message::MAX_DESCRIPTORS_PER_MESSAGE]));
|
||||
char buf[tmp];
|
||||
|
||||
if (partial_write_.isNothing()) {
|
||||
if (partial_write_iter_.isNothing()) {
|
||||
#if defined(OS_MACOSX)
|
||||
if (!TransferMachPorts(*msg)) {
|
||||
return false;
|
||||
@@ -583,30 +583,44 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
#endif
|
||||
Pickle::BufferList::IterImpl iter(msg->Buffers());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!iter.Done(), "empty message");
|
||||
partial_write_.emplace(PartialWrite{iter, msg->attached_handles_});
|
||||
partial_write_iter_.emplace(iter);
|
||||
}
|
||||
|
||||
if (partial_write_->iter_.Done()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "partial_write_->iter_ should not be done");
|
||||
if (partial_write_iter_.ref().Done()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "partial_write_iter_ should not be null");
|
||||
// report a send error to our caller, which will close the channel.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (partial_write_->iter_.Data() == msg->Buffers().Start()) {
|
||||
if (partial_write_iter_.value().Data() == msg->Buffers().Start()) {
|
||||
AddIPCProfilerMarker(*msg, other_pid_, MessageDirection::eSending,
|
||||
MessagePhase::TransferStart);
|
||||
|
||||
if (!msg->attached_handles_.IsEmpty()) {
|
||||
// This is the first chunk of a message which has descriptors to send
|
||||
if (msg->attached_handles_.Length() >
|
||||
IPC::Message::MAX_DESCRIPTORS_PER_MESSAGE) {
|
||||
struct cmsghdr* cmsg;
|
||||
const unsigned num_fds = msg->attached_handles_.Length();
|
||||
|
||||
if (num_fds > IPC::Message::MAX_DESCRIPTORS_PER_MESSAGE) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "Too many file descriptors!");
|
||||
CHROMIUM_LOG(FATAL) << "Too many file descriptors!";
|
||||
// This should not be reached.
|
||||
return false;
|
||||
}
|
||||
|
||||
msg->header()->num_handles = msg->attached_handles_.Length();
|
||||
msgh.msg_control = buf;
|
||||
msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
|
||||
cmsg = CMSG_FIRSTHDR(&msgh);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
|
||||
for (unsigned i = 0; i < num_fds; ++i) {
|
||||
reinterpret_cast<int*>(CMSG_DATA(cmsg))[i] =
|
||||
msg->attached_handles_[i].get();
|
||||
}
|
||||
msgh.msg_controllen = cmsg->cmsg_len;
|
||||
|
||||
msg->header()->num_handles = num_fds;
|
||||
#if defined(OS_MACOSX)
|
||||
msg->set_fd_cookie(++last_pending_fd_id_);
|
||||
#endif
|
||||
@@ -618,37 +632,14 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
size_t amt_to_write = 0;
|
||||
|
||||
// How much of this message have we written so far?
|
||||
Pickle::BufferList::IterImpl iter = partial_write_->iter_;
|
||||
auto handles = partial_write_->handles_;
|
||||
Pickle::BufferList::IterImpl iter = partial_write_iter_.value();
|
||||
|
||||
size_t max_amt_to_write = iter.TotalBytesAvailable(msg->Buffers());
|
||||
if (!handles.IsEmpty()) {
|
||||
// We can only send at most kControlBufferMaxFds files per sendmsg call.
|
||||
const size_t num_fds = std::min(handles.Length(), kControlBufferMaxFds);
|
||||
|
||||
// Populate the cmsg header for this call
|
||||
msgh.msg_control = cmsgBuf;
|
||||
msgh.msg_controllen = CMSG_LEN(sizeof(int) * num_fds);
|
||||
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msgh);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = msgh.msg_controllen;
|
||||
for (size_t i = 0; i < num_fds; ++i) {
|
||||
reinterpret_cast<int*>(CMSG_DATA(cmsg))[i] = handles[i].get();
|
||||
}
|
||||
|
||||
// Update partial_write_ to record which handles were written.
|
||||
auto remaining = handles.From(num_fds);
|
||||
partial_write_->handles_ = remaining;
|
||||
|
||||
// Avoid writing one byte per remaining handle in excess of
|
||||
// kControlBufferMaxFds. Each handle written will consume a minimum of 4
|
||||
// bytes in the message (to store it's index), so we can depend on there
|
||||
// being enough data to send every handle.
|
||||
MOZ_ASSERT(max_amt_to_write > remaining.Length(),
|
||||
"must be at least one byte in the message for each handle");
|
||||
max_amt_to_write -= remaining.Length();
|
||||
}
|
||||
// Store the unwritten part of the first segment to write into the iovec.
|
||||
iov[0].iov_base = const_cast<char*>(iter.Data());
|
||||
iov[0].iov_len = iter.RemainingInSegment();
|
||||
amt_to_write += iov[0].iov_len;
|
||||
iter.Advance(msg->Buffers(), iov[0].iov_len);
|
||||
iov_count++;
|
||||
|
||||
// Store remaining segments to write into iovec.
|
||||
//
|
||||
@@ -656,11 +647,9 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
// OS-dependent limits. Also, stop adding iovecs if we've already
|
||||
// prepared to write at least the full buffer size.
|
||||
while (!iter.Done() && iov_count < kMaxIOVecSize &&
|
||||
PipeBufHasSpaceAfter(amt_to_write) &&
|
||||
amt_to_write < max_amt_to_write) {
|
||||
PipeBufHasSpaceAfter(amt_to_write)) {
|
||||
char* data = iter.Data();
|
||||
size_t size =
|
||||
std::min(iter.RemainingInSegment(), max_amt_to_write - amt_to_write);
|
||||
size_t size = iter.RemainingInSegment();
|
||||
|
||||
iov[iov_count].iov_base = data;
|
||||
iov[iov_count].iov_len = size;
|
||||
@@ -668,7 +657,6 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
amt_to_write += size;
|
||||
iter.Advance(msg->Buffers(), size);
|
||||
}
|
||||
MOZ_ASSERT(amt_to_write <= max_amt_to_write);
|
||||
|
||||
const bool intentional_short_write = !iter.Done();
|
||||
msgh.msg_iov = iov;
|
||||
@@ -677,6 +665,14 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
ssize_t bytes_written =
|
||||
HANDLE_EINTR(corrected_sendmsg(pipe_, &msgh, MSG_DONTWAIT));
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
// On OSX the attached_handles_ array gets cleared later, once we get the
|
||||
// RECEIVED_FDS_MESSAGE_TYPE message.
|
||||
if (bytes_written > 0) {
|
||||
msg->attached_handles_.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bytes_written < 0) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
@@ -722,10 +718,10 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(intentional_short_write ||
|
||||
static_cast<size_t>(bytes_written) <
|
||||
amt_to_write);
|
||||
partial_write_->iter_.AdvanceAcrossSegments(msg->Buffers(),
|
||||
bytes_written);
|
||||
partial_write_iter_.ref().AdvanceAcrossSegments(msg->Buffers(),
|
||||
bytes_written);
|
||||
// We should not hit the end of the buffer.
|
||||
MOZ_DIAGNOSTIC_ASSERT(!partial_write_->iter_.Done());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!partial_write_iter_.ref().Done());
|
||||
}
|
||||
|
||||
// Tell libevent to call us back once things are unblocked.
|
||||
@@ -736,17 +732,13 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
MessageLoopForIO::WATCH_WRITE, &write_watcher_, this);
|
||||
return true;
|
||||
} else {
|
||||
partial_write_.reset();
|
||||
partial_write_iter_.reset();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
if (!msg->attached_handles_.IsEmpty()) {
|
||||
pending_fds_.push_back(PendingDescriptors{
|
||||
msg->fd_cookie(), std::move(msg->attached_handles_)});
|
||||
}
|
||||
#else
|
||||
if (bytes_written > 0) {
|
||||
msg->attached_handles_.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Message sent OK!
|
||||
@@ -851,7 +843,7 @@ void Channel::ChannelImpl::OutputQueuePush(mozilla::UniquePtr<Message> msg) {
|
||||
|
||||
void Channel::ChannelImpl::OutputQueuePop() {
|
||||
// Clear any reference to the front of output_queue_ before we destroy it.
|
||||
partial_write_.reset();
|
||||
partial_write_iter_.reset();
|
||||
|
||||
mozilla::UniquePtr<Message> message = output_queue_.Pop();
|
||||
}
|
||||
|
||||
@@ -100,11 +100,7 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
|
||||
// If sending a message blocks then we use this iterator to keep track of
|
||||
// where in the message we are. It gets reset when the message is finished
|
||||
// sending.
|
||||
struct PartialWrite {
|
||||
Pickle::BufferList::IterImpl iter_;
|
||||
mozilla::Span<const mozilla::UniqueFileHandle> handles_;
|
||||
};
|
||||
mozilla::Maybe<PartialWrite> partial_write_;
|
||||
mozilla::Maybe<Pickle::BufferList::IterImpl> partial_write_iter_;
|
||||
|
||||
int server_listen_pipe_;
|
||||
int pipe_;
|
||||
@@ -124,19 +120,18 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
|
||||
// The control message buffer will hold all of the file descriptors that will
|
||||
// be read in during a single recvmsg call. Message::WriteFileDescriptor
|
||||
// always writes one word of data for every file descriptor added to the
|
||||
// message, and the number of file descriptors per recvmsg will not exceed
|
||||
// kControlBufferMaxFds. This is based on the true maximum SCM_RIGHTS
|
||||
// descriptor count, which is just over 250 on both Linux and macOS.
|
||||
// message, and the number of file descriptors per message will not exceed
|
||||
// MAX_DESCRIPTORS_PER_MESSAGE.
|
||||
//
|
||||
// This buffer also holds a control message header of size CMSG_SPACE(0)
|
||||
// bytes. However, CMSG_SPACE is not a constant on Macs, so we can't use it
|
||||
// here. Consequently, we pick a number here that is at least CMSG_SPACE(0) on
|
||||
// all platforms. We assert at runtime, in Channel::ChannelImpl::Init, that
|
||||
// it's big enough.
|
||||
static constexpr size_t kControlBufferMaxFds = 200;
|
||||
static constexpr size_t kControlBufferHeaderSize = 32;
|
||||
static constexpr size_t kControlBufferSize =
|
||||
kControlBufferMaxFds * sizeof(int) + kControlBufferHeaderSize;
|
||||
IPC::Message::MAX_DESCRIPTORS_PER_MESSAGE * sizeof(int) +
|
||||
kControlBufferHeaderSize;
|
||||
|
||||
// Large incoming messages that span multiple pipe buffers get built-up in the
|
||||
// buffers of this message.
|
||||
|
||||
@@ -93,8 +93,9 @@ class Message : public mojo::core::ports::UserMessage, public Pickle {
|
||||
REPLY = 1,
|
||||
};
|
||||
|
||||
// The hard limit of handles or file descriptors allowed in a single message.
|
||||
static constexpr size_t MAX_DESCRIPTORS_PER_MESSAGE = 32767;
|
||||
// Mac and Linux both limit the number of file descriptors per message to
|
||||
// slightly more than 250.
|
||||
enum { MAX_DESCRIPTORS_PER_MESSAGE = 200 };
|
||||
|
||||
class HeaderFlags {
|
||||
friend class Message;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
[ParentImpl=virtual, ChildImpl=virtual]
|
||||
async protocol PTestManyHandles {
|
||||
child:
|
||||
async ManyHandles(FileDescriptor[] descrs);
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
@@ -1,72 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "mozilla/_ipdltest/IPDLUnitTest.h"
|
||||
#include "mozilla/_ipdltest/PTestManyHandlesChild.h"
|
||||
#include "mozilla/_ipdltest/PTestManyHandlesParent.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla::_ipdltest {
|
||||
|
||||
class TestManyHandlesChild : public PTestManyHandlesChild {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestManyHandlesChild, override)
|
||||
|
||||
public:
|
||||
IPCResult RecvManyHandles(nsTArray<FileDescriptor>&& aDescrs) override {
|
||||
EXPECT_EQ(aDescrs.Length(), 500u);
|
||||
for (int i = 0; i < static_cast<int>(aDescrs.Length()); ++i) {
|
||||
UniqueFileHandle handle = aDescrs[i].TakePlatformHandle();
|
||||
int value;
|
||||
const int size = sizeof(value);
|
||||
#ifdef XP_WIN
|
||||
EXPECT_TRUE(::ReadFile(handle.get(), &value, size, nullptr, nullptr));
|
||||
#else
|
||||
EXPECT_EQ(read(handle.get(), &value, size), size);
|
||||
#endif
|
||||
EXPECT_EQ(value, i);
|
||||
}
|
||||
Close();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
private:
|
||||
~TestManyHandlesChild() = default;
|
||||
};
|
||||
|
||||
class TestManyHandlesParent : public PTestManyHandlesParent {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestManyHandlesParent, override)
|
||||
|
||||
private:
|
||||
~TestManyHandlesParent() = default;
|
||||
};
|
||||
|
||||
IPDL_TEST(TestManyHandles) {
|
||||
nsTArray<FileDescriptor> descrs;
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
const int size = sizeof(i);
|
||||
UniqueFileHandle readPipe;
|
||||
UniqueFileHandle writePipe;
|
||||
#ifdef XP_WIN
|
||||
ASSERT_TRUE(::CreatePipe(getter_Transfers(readPipe),
|
||||
getter_Transfers(writePipe), nullptr, size));
|
||||
ASSERT_TRUE(::WriteFile(writePipe.get(), &i, size, nullptr, nullptr));
|
||||
#else
|
||||
int fds[2];
|
||||
ASSERT_EQ(pipe(fds), 0);
|
||||
readPipe.reset(fds[0]);
|
||||
writePipe.reset(fds[1]);
|
||||
ASSERT_EQ(write(writePipe.get(), &i, size), size);
|
||||
#endif
|
||||
descrs.AppendElement(FileDescriptor(std::move(readPipe)));
|
||||
}
|
||||
bool ok = mActor->SendManyHandles(descrs);
|
||||
ASSERT_TRUE(ok);
|
||||
}
|
||||
|
||||
} // namespace mozilla::_ipdltest
|
||||
@@ -17,13 +17,11 @@ EXPORTS.mozilla._ipdltest += [
|
||||
SOURCES += [
|
||||
"IPDLUnitTest.cpp",
|
||||
"TestBasic.cpp",
|
||||
"TestManyHandles.cpp",
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
"PIPDLUnitTest.ipdl",
|
||||
"PTestBasic.ipdl",
|
||||
"PTestManyHandles.ipdl",
|
||||
]
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
||||
Reference in New Issue
Block a user