Skip to content

Commit 1ed689e

Browse files
authored
Move FdGuard to IOUtils and improve it (#2607)
Improvements: - Make it moveable. - Make it unabuseable: don't throwing exceptions in destructor if exception is already being thrown (= undefined behavior). Just warn. Partially addresses #2596.
1 parent 62b1f25 commit 1ed689e

File tree

6 files changed

+103
-36
lines changed

6 files changed

+103
-36
lines changed

src/agent/Core/ApplicationPool/Implementation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ void processAndLogNewSpawnException(SpawningKit::SpawnException &e, const Option
193193
getSystemTempDir());
194194
fd = mkstemp(filename);
195195
#endif
196-
FdGuard guard(fd, NULL, 0, true);
196+
FdGuard guard(fd, nullptr, 0);
197197
if (fd == -1) {
198198
int e = errno;
199199
throw SystemException("Cannot generate a temporary filename",

src/agent/Core/CoreMain.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
#include <Utils.h>
8989
#include <Utils/Timer.h>
9090
#include <IOTools/MessageIO.h>
91+
#include <IOTools/IOUtils.h>
9192
#include <Core/OptionParser.h>
9293
#include <Core/Controller.h>
9394
#include <Core/ApiServer.h>

src/agent/Core/SpawningKit/Handshake/Perform.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include <FileDescriptor.h>
5151
#include <FileTools/FileManip.h>
5252
#include <FileTools/PathManip.h>
53+
#include <IOTools/IOUtils.h>
5354
#include <Utils.h>
5455
#include <Utils/ScopeGuard.h>
5556
#include <SystemTools/SystemTime.h>

src/cxx_supportlib/IOTools/IOUtils.cpp

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
// https://bugzilla.redhat.com/show_bug.cgi?id=165427
3030
// Also needed for SO_PEERCRED.
3131
#define _GNU_SOURCE
32+
#include <exception>
3233
#endif
3334

3435
#include <oxt/system_calls.hpp>
@@ -215,7 +216,7 @@ createUnixServer(const StaticString &filename, unsigned int backlogSize, bool au
215216
throw SystemException("Cannot create a Unix socket file descriptor", e);
216217
}
217218

218-
FdGuard guard(fd, file, line, true);
219+
FdGuard guard(fd, file, line);
219220
addr.sun_family = AF_LOCAL;
220221
strncpy(addr.sun_path, filename.c_str(), filename.size());
221222
addr.sun_path[filename.size()] = '\0';
@@ -306,7 +307,7 @@ createTcpServer(const char *address, unsigned short port, unsigned int backlogSi
306307
}
307308
// Ignore SO_REUSEADDR error, it's not fatal.
308309

309-
FdGuard guard(fd, file, line, true);
310+
FdGuard guard(fd, file, line);
310311
if (family == AF_INET) {
311312
ret = syscalls::bind(fd, (const struct sockaddr *) &addr.v4, sizeof(struct sockaddr_in));
312313
} else {
@@ -369,7 +370,7 @@ connectToUnixServer(const StaticString &filename, const char *file,
369370
throw SystemException("Cannot create a Unix socket file descriptor", e);
370371
}
371372

372-
FdGuard guard(fd, file, line, true);
373+
FdGuard guard(fd, file, line);
373374
int ret;
374375
struct sockaddr_un addr;
375376

@@ -656,6 +657,72 @@ NConnect_State::asNTCP_State() {
656657
}
657658

658659

660+
/****** Scope guards ******/
661+
662+
FdGuard::FdGuard(FdGuard &&other)
663+
: mFd(other.mFd)
664+
{
665+
other.mFd = -1;
666+
}
667+
668+
FdGuard::FdGuard(int fd, const char *sourceFile, unsigned int sourceLine)
669+
: mFd(fd)
670+
{
671+
if (mFd != -1 && sourceFile != nullptr) {
672+
P_LOG_FILE_DESCRIPTOR_OPEN3(fd, sourceFile, sourceLine);
673+
}
674+
}
675+
676+
FdGuard::~FdGuard() noexcept(false) {
677+
if (mFd != -1) {
678+
try {
679+
safelyClose(mFd);
680+
} catch (const std::exception &e) {
681+
bool uncaughtException =
682+
#if __cplusplus >= 201703L
683+
std::uncaught_exceptions() > 0;
684+
#else
685+
std::uncaught_exception();
686+
#endif
687+
if (uncaughtException) {
688+
P_WARN("Error closing file descriptor " << mFd << ": " << e.what());
689+
return;
690+
} else {
691+
throw e;
692+
}
693+
}
694+
P_LOG_FILE_DESCRIPTOR_CLOSE(mFd);
695+
}
696+
}
697+
698+
FdGuard &
699+
FdGuard::operator=(FdGuard &&other) {
700+
if (this != &other) {
701+
if (mFd != -1) {
702+
safelyClose(mFd);
703+
P_LOG_FILE_DESCRIPTOR_CLOSE(mFd);
704+
}
705+
mFd = other.mFd;
706+
other.mFd = -1;
707+
}
708+
return *this;
709+
}
710+
711+
void
712+
FdGuard::clear() noexcept {
713+
mFd = -1;
714+
}
715+
716+
void
717+
FdGuard::runNow() noexcept(false) {
718+
if (mFd != -1) {
719+
safelyClose(mFd);
720+
P_LOG_FILE_DESCRIPTOR_CLOSE(mFd);
721+
mFd = -1;
722+
}
723+
}
724+
725+
659726
/****** Other ******/
660727

661728
bool

src/cxx_supportlib/IOTools/IOUtils.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,36 @@ struct NConnect_State {
358358
};
359359

360360

361+
/****** Scope guards ******/
362+
363+
/** RAII construct for ensuring that a file descriptor gets closed at scope exit. */
364+
class FdGuard {
365+
private:
366+
int mFd = -1;
367+
368+
public:
369+
FdGuard() { }
370+
FdGuard(const FdGuard &other) = delete;
371+
FdGuard(FdGuard &&other);
372+
FdGuard(int fd, const char *sourceFile, unsigned int sourceLine);
373+
/** @throws SystemException File descriptor close error. If exception is already being thrown, then only warns. */
374+
~FdGuard() noexcept(false);
375+
376+
FdGuard &operator=(const FdGuard &other) = delete;
377+
FdGuard &operator=(FdGuard &&other);
378+
379+
/** Don't close file descriptor at object destruction. */
380+
void clear() noexcept;
381+
382+
/**
383+
* Close file descriptor now. Idempotent.
384+
*
385+
* @throws SystemException
386+
*/
387+
void runNow() noexcept(false);
388+
};
389+
390+
361391
/****** Other ******/
362392

363393
typedef ssize_t (*WritevFunction)(int fildes, const struct iovec *iov, int iovcnt);

src/cxx_supportlib/Utils/ScopeGuard.h

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -117,38 +117,6 @@ class StdioGuard: public noncopyable {
117117
}
118118
};
119119

120-
class FdGuard: public noncopyable {
121-
private:
122-
int fd;
123-
bool ignoreErrors;
124-
125-
public:
126-
FdGuard(int _fd, const char *file, unsigned int line, bool _ignoreErrors = false)
127-
: fd(_fd),
128-
ignoreErrors(_ignoreErrors)
129-
{
130-
if (_fd != -1 && file != NULL) {
131-
P_LOG_FILE_DESCRIPTOR_OPEN3(_fd, file, line);
132-
}
133-
}
134-
135-
~FdGuard() {
136-
runNow();
137-
}
138-
139-
void clear() {
140-
fd = -1;
141-
}
142-
143-
void runNow() {
144-
if (fd != -1) {
145-
safelyClose(fd, ignoreErrors);
146-
P_LOG_FILE_DESCRIPTOR_CLOSE(fd);
147-
fd = -1;
148-
}
149-
}
150-
};
151-
152120

153121
} // namespace Passenger
154122

0 commit comments

Comments
 (0)