refactor: minor UnixFd cleanups (#376)

* chore: Use std::exchange in UnixFd

This was suggested in code review for #376 .

* fix: Protect against UnixFd self-assignment

While self-assignment is rare, it is expected to be safe.  Add a check
to prevent putting the object in an invalid state.

* fix: Improve hygiene around dup system call

- Don't try to call dup on a negative value.
- Check dup return code and throw if it fails, rather than returning an
  empty UnixFd object.

* chore: Move UnixFd::close to Types.cpp

Minor convenience for applications: unistd.h doesn't have to be included
in the public header.

---------

Co-authored-by: David Reiss <dreiss@meta.com>
This commit is contained in:
David Reiss
2023-11-18 09:11:00 -08:00
committed by GitHub
parent f50e4676fe
commit 6e348f3910
2 changed files with 45 additions and 13 deletions

View File

@ -34,7 +34,7 @@
#include <typeinfo> #include <typeinfo>
#include <memory> #include <memory>
#include <tuple> #include <tuple>
#include <unistd.h> #include <utility>
namespace sdbus { namespace sdbus {
@ -209,7 +209,7 @@ namespace sdbus {
UnixFd() = default; UnixFd() = default;
explicit UnixFd(int fd) explicit UnixFd(int fd)
: fd_(::dup(fd)) : fd_(checkedDup(fd))
{ {
} }
@ -225,8 +225,12 @@ namespace sdbus {
UnixFd& operator=(const UnixFd& other) UnixFd& operator=(const UnixFd& other)
{ {
if (this == &other)
{
return *this;
}
close(); close();
fd_ = ::dup(other.fd_); fd_ = checkedDup(other.fd_);
return *this; return *this;
} }
@ -237,9 +241,12 @@ namespace sdbus {
UnixFd& operator=(UnixFd&& other) UnixFd& operator=(UnixFd&& other)
{ {
if (this == &other)
{
return *this;
}
close(); close();
fd_ = other.fd_; fd_ = std::exchange(other.fd_, -1);
other.fd_ = -1;
return *this; return *this;
} }
@ -265,9 +272,7 @@ namespace sdbus {
int release() int release()
{ {
auto fd = fd_; return std::exchange(fd_, -1);
fd_ = -1;
return fd;
} }
bool isValid() const bool isValid() const
@ -276,11 +281,12 @@ namespace sdbus {
} }
private: private:
void close() /// Closes file descriptor, but does not set it to -1.
{ void close();
if (fd_ >= 0)
::close(fd_); /// Returns negative argument unchanged.
} /// Otherwise, call ::dup and throw on failure.
static int checkedDup(int fd);
int fd_ = -1; int fd_ = -1;
}; };

View File

@ -29,6 +29,9 @@
#include "MessageUtils.h" #include "MessageUtils.h"
#include SDBUS_HEADER #include SDBUS_HEADER
#include <cassert> #include <cassert>
#include <cerrno>
#include <system_error>
#include <unistd.h>
namespace sdbus { namespace sdbus {
@ -64,4 +67,27 @@ bool Variant::isEmpty() const
return msg_.isEmpty(); return msg_.isEmpty();
} }
void UnixFd::close()
{
if (fd_ >= 0)
{
::close(fd_);
}
}
int UnixFd::checkedDup(int fd)
{
if (fd < 0)
{
return fd;
}
int ret = ::dup(fd);
if (ret < 0)
{
throw std::system_error(errno, std::generic_category(), "dup failed");
}
return ret;
}
} }