gecko-dev/ipc/glue/FileDescriptorShuffle.h
Jed Davis b0a1468c01 Bug 1456911 - Rewrite the fd shuffling to be simpler & handle identity mappings correctly. r=froydnj
This replaces some old Chromium code that tries to minimally disentangle
an arbitrary file descriptor mapping with simpler algorithm, for several
reasons:

1. Do something appropriate when a file descriptor is mapped to the same
fd number in the child; currently they're ignored, which means they'll
be closed if they were close-on-exec.  This implementation duplicates
the fd twice in that case, which seems to be uncommon in practice; this
isn't maximally efficient but avoids special-case code.

2. Make this more generally applicable; the previous design is
specialized for arbitrary code running between fork and exec, but we
also want to use this on OS X with posix_spawn, which exposes a very
limited set of operations.

3. Avoid the use of C++ standard library iterators in async signal safe
code; the Chromium developers mention that this is a potential problem in
some debugging implementations that take locks.

4. In general the algorithm is simpler and should be more "obviously
correct"; more concretely, it should get complete coverage just by being
run normally in a debug build.

As a convenient side benefit, CloseSuperfluousFds now takes an arbitrary
predicate for which fds to leave open, which means it can be used in
other code that needs it without creating a fake fd mapping.

MozReview-Commit-ID: EoiRttrbrKL

--HG--
extra : rebase_source : 336e0ba9f56dc80f7347dc62617b4ad1efea7e7e
2018-04-25 17:44:08 -06:00

72 lines
2.4 KiB
C++

/* -*- 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/. */
#ifndef mozilla_ipc_FileDescriptorShuffle_h
#define mozilla_ipc_FileDescriptorShuffle_h
#include "mozilla/Span.h"
#include "nsTArray.h"
#include <functional>
#include <utility>
// This class converts a set of file descriptor mapping, which may
// contain conflicts (like {a->b, b->c} or {a->b, b->a}) into a
// sequence of dup2() operations that can be performed between fork
// and exec, or with posix_spawn_file_actions_adddup2. It may create
// temporary duplicates of fds to use as the source of a dup2; they
// are closed on destruction.
//
// The dup2 sequence is guaranteed to not contain dup2(x, x) for any
// x; if such an element is present in the input, it will be dup2()ed
// from a temporary fd to ensure that the close-on-exec bit is cleared.
//
// In general, this is *not* guaranteed to minimize the use of
// temporary fds.
namespace mozilla {
namespace ipc {
class FileDescriptorShuffle
{
public:
FileDescriptorShuffle() = default;
~FileDescriptorShuffle();
using MappingRef = mozilla::Span<const std::pair<int, int>>;
// Translate the given mapping, creating temporary fds as needed.
// Can fail (return false) on failure to duplicate fds.
bool Init(MappingRef aMapping);
// Accessor for the dup2() sequence. Do not use the returned value
// or the fds contained in it after this object is destroyed.
MappingRef Dup2Sequence() const { return mMapping; }
// Tests whether the given fd is used as a destination in this mapping.
// Can be used to close other fds after performing the dup2()s.
bool MapsTo(int aFd) const;
// Wraps MapsTo in a function object, as a convenience for use with
// base::CloseSuperfluousFds.
std::function<bool(int)> MapsToFunc() const {
return [this](int fd) { return MapsTo(fd); };
}
private:
nsTArray<std::pair<int, int>> mMapping;
nsTArray<int> mTempFds;
int mMaxDst;
FileDescriptorShuffle(const FileDescriptorShuffle&) = delete;
void operator=(const FileDescriptorShuffle&) = delete;
};
} // namespace ipc
} // namespace mozilla
#endif // mozilla_ipc_FileDescriptorShuffle_h