From f6347e92bbc8642e176bf060e0f19c6fd80f89ea Mon Sep 17 00:00:00 2001 From: David Roberts Date: Wed, 17 Jun 2020 13:18:00 +0100 Subject: [PATCH 1/5] [6.8][ML] Better interrupt handling during named pipe connection This change fixes two related issues with named pipe connection when the controller process first starts up: 1. If the ES JVM dies before the controller connects its logging named pipe then since elastic/elasticsearch#56491 the resulting errors from the controller process will be seen in the ES stderr file. There is a change to the logging to make it clearer that the controller didn't fail, but exited due to the ES JVM disappearing. 2. Interrupted system calls while connecting the named pipes could cause the pipes to unnecessarily fail to connect. There is a change to retry the calls on getting an EINTR error unless the interrupt was caused by the functionality of controller that kills off the connection attempts if the ES JVM dies (i.e. the scenario described in point 1). Backport of #1311 --- .../CBlockingCallCancellerThread.cc | 13 +- bin/controller/CBlockingCallCancellerThread.h | 15 ++- bin/controller/Main.cc | 48 ++++---- .../CBlockingCallCancellerThreadTest.cc | 19 +-- docs/CHANGELOG.asciidoc | 6 + include/core/CLogger.h | 13 ++ include/core/CNamedPipeFactory.h | 19 ++- lib/api/CIoManager.cc | 7 +- lib/core/CLogger.cc | 17 ++- lib/core/CNamedPipeFactory.cc | 116 ++++++++++++------ lib/core/CNamedPipeFactory_Windows.cc | 93 ++++++++------ lib/core/CThread.cc | 2 +- lib/core/unittest/CNamedPipeFactoryTest.cc | 97 ++++++++------- lib/seccomp/unittest/CSystemCallFilterTest.cc | 31 ++--- 14 files changed, 317 insertions(+), 179 deletions(-) diff --git a/bin/controller/CBlockingCallCancellerThread.cc b/bin/controller/CBlockingCallCancellerThread.cc index 0b7861a903..ef183c42de 100644 --- a/bin/controller/CBlockingCallCancellerThread.cc +++ b/bin/controller/CBlockingCallCancellerThread.cc @@ -14,25 +14,30 @@ namespace controller { CBlockingCallCancellerThread::CBlockingCallCancellerThread(core::CThread::TThreadId potentiallyBlockedThreadId, std::istream& monitorStream) - : m_PotentiallyBlockedThreadId(potentiallyBlockedThreadId), - m_MonitorStream(monitorStream), m_Shutdown(false) { + : m_PotentiallyBlockedThreadId{potentiallyBlockedThreadId}, + m_MonitorStream{monitorStream}, m_Shutdown{false}, m_HasCancelledBlockingCall{false} { +} + +const std::atomic_bool& CBlockingCallCancellerThread::hasCancelledBlockingCall() const { + return m_HasCancelledBlockingCall; } void CBlockingCallCancellerThread::run() { char c; while (m_MonitorStream >> c) { - if (m_Shutdown) { + if (m_Shutdown.load()) { return; } } + m_HasCancelledBlockingCall.store(true); if (core::CThread::cancelBlockedIo(m_PotentiallyBlockedThreadId) == false) { LOG_WARN(<< "Failed to cancel blocked IO in thread " << m_PotentiallyBlockedThreadId); } } void CBlockingCallCancellerThread::shutdown() { - m_Shutdown = true; + m_Shutdown.store(true); // This is to wake up the stream reading in the run() method of this object. // If this has an effect then the assumption is that the program is exiting diff --git a/bin/controller/CBlockingCallCancellerThread.h b/bin/controller/CBlockingCallCancellerThread.h index b0c7d8e226..66fc709268 100644 --- a/bin/controller/CBlockingCallCancellerThread.h +++ b/bin/controller/CBlockingCallCancellerThread.h @@ -8,6 +8,7 @@ #include +#include #include namespace ml { @@ -39,12 +40,14 @@ class CBlockingCallCancellerThread : public core::CThread { CBlockingCallCancellerThread(core::CThread::TThreadId potentiallyBlockedThreadId, std::istream& monitorStream); + const std::atomic_bool& hasCancelledBlockingCall() const; + protected: //! Called when the thread is started. - virtual void run(); + void run() override; //! Called when the thread is stopped. - virtual void shutdown(); + void shutdown() override; private: //! Thread ID of the thread that this object will cancel blocking IO in @@ -54,8 +57,12 @@ class CBlockingCallCancellerThread : public core::CThread { //! Stream to monitor for end-of-file. std::istream& m_MonitorStream; - //! Flag to indicate the thread should shut down - volatile bool m_Shutdown; + //! Flag to indicate the monitoring thread should shut down + std::atomic_bool m_Shutdown; + + //! Flag to indicate that an attempt to cancel blocking calls in the + //! monitored thread has been made + std::atomic_bool m_HasCancelledBlockingCall; }; } } diff --git a/bin/controller/Main.cc b/bin/controller/Main.cc index 0caa645e35..5ad581bf80 100644 --- a/bin/controller/Main.cc +++ b/bin/controller/Main.cc @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ //! \brief -//! Controller to start other Ml processes. +//! Controller to start other ML processes. //! //! DESCRIPTION:\n -//! Starts other Ml processes based on commands sent to it +//! Starts other ML processes based on commands sent to it //! through a named pipe. //! //! Each command has the following format: @@ -59,12 +59,12 @@ #include int main(int argc, char** argv) { - const std::string& defaultNamedPipePath = ml::core::CNamedPipeFactory::defaultPath(); - const std::string& progName = ml::core::CProgName::progName(); + const std::string& defaultNamedPipePath{ml::core::CNamedPipeFactory::defaultPath()}; + const std::string& progName{ml::core::CProgName::progName()}; // Read command line options - std::string jvmPidStr = ml::core::CStringUtils::typeToString( - ml::core::CProcess::instance().parentId()); + std::string jvmPidStr{ml::core::CStringUtils::typeToString( + ml::core::CProcess::instance().parentId())}; std::string logPipe; std::string commandPipe; if (ml::controller::CCmdLineParser::parse(argc, argv, jvmPidStr, logPipe, @@ -88,8 +88,8 @@ int main(int argc, char** argv) { // 4) No plugin code ever runs // This thread will detect the death of the parent process because this // process's STDIN will be closed. - ml::controller::CBlockingCallCancellerThread cancellerThread( - ml::core::CThread::currentThreadId(), std::cin); + ml::controller::CBlockingCallCancellerThread cancellerThread{ + ml::core::CThread::currentThreadId(), std::cin}; if (cancellerThread.start() == false) { // This log message will probably never been seen as it will go to the // real stderr of this process rather than the log pipe... @@ -97,8 +97,13 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } - if (ml::core::CLogger::instance().reconfigureLogToNamedPipe(logPipe) == false) { - LOG_FATAL(<< "Could not reconfigure logging"); + if (ml::core::CLogger::instance().reconfigureLogToNamedPipe( + logPipe, cancellerThread.hasCancelledBlockingCall()) == false) { + if (cancellerThread.hasCancelledBlockingCall().load()) { + LOG_INFO(<< "Parent process died - ML controller exiting"); + } else { + LOG_FATAL(<< "Could not reconfigure logging"); + } cancellerThread.stop(); return EXIT_FAILURE; } @@ -112,10 +117,14 @@ int main(int argc, char** argv) { // the controller is critical to the overall system. Also its resource // requirements should always be very low. - ml::core::CNamedPipeFactory::TIStreamP commandStream = - ml::core::CNamedPipeFactory::openPipeStreamRead(commandPipe); + ml::core::CNamedPipeFactory::TIStreamP commandStream{ml::core::CNamedPipeFactory::openPipeStreamRead( + commandPipe, cancellerThread.hasCancelledBlockingCall())}; if (commandStream == nullptr) { - LOG_FATAL(<< "Could not open command pipe"); + if (cancellerThread.hasCancelledBlockingCall().load()) { + LOG_INFO(<< "Parent process died - ML controller exiting"); + } else { + LOG_FATAL(<< "Could not open command pipe"); + } cancellerThread.stop(); return EXIT_FAILURE; } @@ -123,7 +132,7 @@ int main(int argc, char** argv) { // Change directory to the directory containing this program, because the // permitted paths all assume the current working directory contains the // permitted programs - const std::string& progDir = ml::core::CProgName::progDir(); + const std::string& progDir{ml::core::CProgName::progDir()}; if (ml::core::COsFileFuncs::chdir(progDir.c_str()) == -1) { LOG_FATAL(<< "Could not change directory to '" << progDir << "': " << ::strerror(errno)); @@ -131,13 +140,10 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } - ml::controller::CCommandProcessor::TStrVec permittedProcessPaths; - permittedProcessPaths.push_back("./autoconfig"); - permittedProcessPaths.push_back("./autodetect"); - permittedProcessPaths.push_back("./categorize"); - permittedProcessPaths.push_back("./normalize"); + ml::controller::CCommandProcessor::TStrVec permittedProcessPaths{ + "./autoconfig", "./autodetect", "./categorize", "./normalize"}; - ml::controller::CCommandProcessor processor(permittedProcessPaths); + ml::controller::CCommandProcessor processor{permittedProcessPaths}; processor.processCommands(*commandStream); cancellerThread.stop(); @@ -145,7 +151,7 @@ int main(int argc, char** argv) { // This message makes it easier to spot process crashes in a log file - if // this isn't present in the log for a given PID and there's no other log // message indicating early exit then the process has probably core dumped - LOG_INFO(<< "Ml controller exiting"); + LOG_INFO(<< "ML controller exiting"); return EXIT_SUCCESS; } diff --git a/bin/controller/unittest/CBlockingCallCancellerThreadTest.cc b/bin/controller/unittest/CBlockingCallCancellerThreadTest.cc index ceb3f09201..05334f4326 100644 --- a/bin/controller/unittest/CBlockingCallCancellerThreadTest.cc +++ b/bin/controller/unittest/CBlockingCallCancellerThreadTest.cc @@ -18,16 +18,16 @@ namespace { class CEofThread : public ml::core::CThread { public: - CEofThread(ml::core::CDualThreadStreamBuf& buf) : m_Buf(buf) {} + CEofThread(ml::core::CDualThreadStreamBuf& buf) : m_Buf{buf} {} protected: - virtual void run() { + void run() override { ml::core::CSleep::sleep(200); m_Buf.signalEndOfFile(); } - virtual void shutdown() {} + void shutdown() override {} private: ml::core::CDualThreadStreamBuf& m_Buf; @@ -46,10 +46,10 @@ CppUnit::Test* CBlockingCallCancellerThreadTest::suite() { void CBlockingCallCancellerThreadTest::testCancelBlock() { ml::core::CDualThreadStreamBuf buf; - std::istream monStrm(&buf); + std::istream monStrm{&buf}; - ml::controller::CBlockingCallCancellerThread cancellerThread( - ml::core::CThread::currentThreadId(), monStrm); + ml::controller::CBlockingCallCancellerThread cancellerThread{ + ml::core::CThread::currentThreadId(), monStrm}; CPPUNIT_ASSERT(cancellerThread.start()); // The CBlockingCallCancellerThread should wake up the blocking open of the @@ -59,11 +59,12 @@ void CBlockingCallCancellerThreadTest::testCancelBlock() { // real program this would be STDIN, but in this test another thread is the // source, and it runs out of data after 0.2 seconds. - CEofThread eofThread(buf); + CEofThread eofThread{buf}; CPPUNIT_ASSERT(eofThread.start()); - ml::core::CNamedPipeFactory::TIStreamP pipeStrm = ml::core::CNamedPipeFactory::openPipeStreamRead( - ml::core::CNamedPipeFactory::defaultPath() + "test_pipe"); + ml::core::CNamedPipeFactory::TIStreamP pipeStrm{ml::core::CNamedPipeFactory::openPipeStreamRead( + ml::core::CNamedPipeFactory::defaultPath() + "test_pipe", + cancellerThread.hasCancelledBlockingCall())}; CPPUNIT_ASSERT(pipeStrm == nullptr); CPPUNIT_ASSERT(cancellerThread.stop()); diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 01c9745577..703947b6d0 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -28,6 +28,12 @@ //=== Regressions +== {es} version 6.8.11 + +=== Bug Fixes + +* Better interrupt handling during named pipe connection. (See {ml-pull}1311[#1311].) + == {es} version 6.8.7 === Bug Fixes diff --git a/include/core/CLogger.h b/include/core/CLogger.h index 5215b2d07d..29cdec236e 100644 --- a/include/core/CLogger.h +++ b/include/core/CLogger.h @@ -15,6 +15,8 @@ #include #include +#include + #include class CLoggerTest; @@ -76,9 +78,20 @@ class CORE_EXPORT CLogger : private CNonCopyable { //! If both are supplied the named pipe takes precedence. bool reconfigure(const std::string& pipeName, const std::string& propertiesFile); + //! As above, but with a flag to indicate named pipe connection attempts + //! should be cancelled. + bool reconfigure(const std::string& pipeName, + const std::string& propertiesFile, + const std::atomic_bool& isCancelled); + //! Tell the logger to log to a named pipe rather than a file. bool reconfigureLogToNamedPipe(const std::string& pipeName); + //! As above, but with a flag to indicate named pipe connection attempts + //! should be cancelled. + bool reconfigureLogToNamedPipe(const std::string& pipeName, + const std::atomic_bool& isCancelled); + //! Tell the logger to reconfigure itself by reading a specified //! properties file, if the file exists. bool reconfigureFromFile(const std::string& propertiesFile); diff --git a/include/core/CNamedPipeFactory.h b/include/core/CNamedPipeFactory.h index 2032e7779e..ccace4379e 100644 --- a/include/core/CNamedPipeFactory.h +++ b/include/core/CNamedPipeFactory.h @@ -10,11 +10,12 @@ #include #include +#include #include #include #include -#include +#include // fdopen() is not C++ so need the C header namespace ml { namespace core { @@ -69,20 +70,24 @@ class CORE_EXPORT CNamedPipeFactory : private CNonInstantiatable { //! Initialise and open a named pipe for reading, returning a C++ stream //! that can be used to read from it. Returns a NULL pointer on //! failure. - static TIStreamP openPipeStreamRead(const std::string& fileName); + static TIStreamP openPipeStreamRead(const std::string& fileName, + const std::atomic_bool& isCancelled); //! Initialise and open a named pipe for writing, returning a C++ stream //! that can be used to write to it. Returns a NULL pointer on failure. - static TOStreamP openPipeStreamWrite(const std::string& fileName); + static TOStreamP openPipeStreamWrite(const std::string& fileName, + const std::atomic_bool& isCancelled); //! Initialise and open a named pipe for writing, returning a C FILE //! that can be used to read from it. Returns a NULL pointer on //! failure. - static TFileP openPipeFileRead(const std::string& fileName); + static TFileP openPipeFileRead(const std::string& fileName, + const std::atomic_bool& isCancelled); //! Initialise and open a named pipe for writing, returning a C FILE //! that can be used to write to it. Returns a NULL pointer on failure. - static TFileP openPipeFileWrite(const std::string& fileName); + static TFileP openPipeFileWrite(const std::string& fileName, + const std::atomic_bool& isCancelled); //! Does the supplied file name refer to a named pipe? static bool isNamedPipe(const std::string& fileName); @@ -102,7 +107,9 @@ class CORE_EXPORT CNamedPipeFactory : private CNonInstantiatable { //! file descriptor that can be used to access it. This is the core //! implementation of the higher level encapsulations that the public //! interface provides. - static TPipeHandle initPipeHandle(const std::string& fileName, bool forWrite); + static TPipeHandle initPipeHandle(const std::string& fileName, + bool forWrite, + const std::atomic_bool& isCancelled); }; } } diff --git a/lib/api/CIoManager.cc b/lib/api/CIoManager.cc index 62d4cb376d..6409c26787 100644 --- a/lib/api/CIoManager.cc +++ b/lib/api/CIoManager.cc @@ -7,6 +7,7 @@ #include +#include #include #include #include @@ -24,7 +25,8 @@ bool setUpIStream(const std::string& fileName, return true; } if (isFileNamedPipe) { - stream = core::CNamedPipeFactory::openPipeStreamRead(fileName); + std::atomic_bool dummy{false}; + stream = core::CNamedPipeFactory::openPipeStreamRead(fileName, dummy); return stream != nullptr && !stream->bad(); } std::ifstream* fileStream(nullptr); @@ -40,7 +42,8 @@ bool setUpOStream(const std::string& fileName, return true; } if (isFileNamedPipe) { - stream = core::CNamedPipeFactory::openPipeStreamWrite(fileName); + std::atomic_bool dummy{false}; + stream = core::CNamedPipeFactory::openPipeStreamWrite(fileName, dummy); return stream != nullptr && !stream->bad(); } std::ofstream* fileStream(nullptr); diff --git a/lib/core/CLogger.cc b/lib/core/CLogger.cc index da323d9aa6..c37c68fa8a 100644 --- a/lib/core/CLogger.cc +++ b/lib/core/CLogger.cc @@ -228,6 +228,13 @@ bool CLogger::setLoggingLevel(ELevel level) { } bool CLogger::reconfigure(const std::string& pipeName, const std::string& propertiesFile) { + std::atomic_bool dummy{false}; + return this->reconfigure(pipeName, propertiesFile, dummy); +} + +bool CLogger::reconfigure(const std::string& pipeName, + const std::string& propertiesFile, + const std::atomic_bool& isCancelled) { if (pipeName.empty()) { if (propertiesFile.empty()) { // Both empty is OK - it just means we keep logging to stderr @@ -235,16 +242,22 @@ bool CLogger::reconfigure(const std::string& pipeName, const std::string& proper } return this->reconfigureFromFile(propertiesFile); } - return this->reconfigureLogToNamedPipe(pipeName); + return this->reconfigureLogToNamedPipe(pipeName, isCancelled); } bool CLogger::reconfigureLogToNamedPipe(const std::string& pipeName) { + std::atomic_bool dummy{false}; + return this->reconfigureLogToNamedPipe(pipeName, dummy); +} + +bool CLogger::reconfigureLogToNamedPipe(const std::string& pipeName, + const std::atomic_bool& isCancelled) { if (m_Reconfigured) { LOG_ERROR(<< "Cannot log to a named pipe after logger reconfiguration"); return false; } - m_PipeFile = CNamedPipeFactory::openPipeFileWrite(pipeName); + m_PipeFile = CNamedPipeFactory::openPipeFileWrite(pipeName, isCancelled); if (m_PipeFile == nullptr) { LOG_ERROR(<< "Cannot log to named pipe " << pipeName << " as it could not be opened for writing"); diff --git a/lib/core/CNamedPipeFactory.cc b/lib/core/CNamedPipeFactory.cc index ef6730d27b..f1f29b966a 100644 --- a/lib/core/CNamedPipeFactory.cc +++ b/lib/core/CNamedPipeFactory.cc @@ -44,7 +44,7 @@ bool ignoreSigPipe() { return ::sigaction(SIGPIPE, &sa, nullptr) == 0; } -const bool SIGPIPE_IGNORED(ignoreSigPipe()); +const bool SIGPIPE_IGNORED{ignoreSigPipe()}; //! \brief //! Replacement for boost::iostreams::file_descriptor_sink that retries on EINTR. @@ -78,12 +78,12 @@ class CRetryingFileDescriptorSink : private boost::iostreams::file_descriptor { //! in the event of an interrupted system call. The method signature is //! defined by Boost's Sink concept. std::streamsize write(const char* s, std::streamsize n) { - std::streamsize totalBytesWritten = 0; + std::streamsize totalBytesWritten{0}; while (n > 0) { - ssize_t ret = ::write(this->handle(), s, static_cast(n)); + ssize_t ret{::write(this->handle(), s, static_cast(n))}; if (ret == -1) { if (errno != EINTR) { - std::string reason("Failed writing to named pipe: "); + std::string reason{"Failed writing to named pipe: "}; reason += ::strerror(errno); LOG_ERROR(<< reason); // We don't usually throw exceptions, but Boost.Iostreams @@ -107,42 +107,50 @@ namespace core { // Initialise static const char CNamedPipeFactory::TEST_CHAR('\n'); -CNamedPipeFactory::TIStreamP CNamedPipeFactory::openPipeStreamRead(const std::string& fileName) { - TPipeHandle fd = CNamedPipeFactory::initPipeHandle(fileName, false); +CNamedPipeFactory::TIStreamP +CNamedPipeFactory::openPipeStreamRead(const std::string& fileName, + const std::atomic_bool& isCancelled) { + TPipeHandle fd{CNamedPipeFactory::initPipeHandle(fileName, false, isCancelled)}; if (fd == -1) { - return TIStreamP(); + return TIStreamP{}; } using TFileDescriptorSourceStream = boost::iostreams::stream; - return TIStreamP(new TFileDescriptorSourceStream( - boost::iostreams::file_descriptor_source(fd, boost::iostreams::close_handle))); + return TIStreamP{new TFileDescriptorSourceStream( + boost::iostreams::file_descriptor_source(fd, boost::iostreams::close_handle))}; } -CNamedPipeFactory::TOStreamP CNamedPipeFactory::openPipeStreamWrite(const std::string& fileName) { - TPipeHandle fd = CNamedPipeFactory::initPipeHandle(fileName, true); +CNamedPipeFactory::TOStreamP +CNamedPipeFactory::openPipeStreamWrite(const std::string& fileName, + const std::atomic_bool& isCancelled) { + TPipeHandle fd{CNamedPipeFactory::initPipeHandle(fileName, true, isCancelled)}; if (fd == -1) { - return TOStreamP(); + return TOStreamP{}; } using TRetryingFileDescriptorSinkStream = boost::iostreams::stream; - return TOStreamP(new TRetryingFileDescriptorSinkStream( - CRetryingFileDescriptorSink(fd, boost::iostreams::close_handle))); + return TOStreamP{new TRetryingFileDescriptorSinkStream( + CRetryingFileDescriptorSink(fd, boost::iostreams::close_handle))}; } -CNamedPipeFactory::TFileP CNamedPipeFactory::openPipeFileRead(const std::string& fileName) { - TPipeHandle fd = CNamedPipeFactory::initPipeHandle(fileName, false); +CNamedPipeFactory::TFileP +CNamedPipeFactory::openPipeFileRead(const std::string& fileName, + const std::atomic_bool& isCancelled) { + TPipeHandle fd{CNamedPipeFactory::initPipeHandle(fileName, false, isCancelled)}; if (fd == -1) { - return TFileP(); + return TFileP{}; } - return TFileP(::fdopen(fd, "r"), safeFClose); + return TFileP{::fdopen(fd, "r"), safeFClose}; } -CNamedPipeFactory::TFileP CNamedPipeFactory::openPipeFileWrite(const std::string& fileName) { - TPipeHandle fd = CNamedPipeFactory::initPipeHandle(fileName, true); +CNamedPipeFactory::TFileP +CNamedPipeFactory::openPipeFileWrite(const std::string& fileName, + const std::atomic_bool& isCancelled) { + TPipeHandle fd{CNamedPipeFactory::initPipeHandle(fileName, true, isCancelled)}; if (fd == -1) { - return TFileP(); + return TFileP{}; } - return TFileP(::fdopen(fd, "w"), safeFClose); + return TFileP{::fdopen(fd, "w"), safeFClose}; } bool CNamedPipeFactory::isNamedPipe(const std::string& fileName) { @@ -161,12 +169,12 @@ std::string CNamedPipeFactory::defaultPath() { // $TMPDIR is generally set on Mac OS X (to something like // /var/folders/k5/5sqcdlps5sg3cvlp783gcz740000h0/T/) and not set on other // platforms. - const char* tmpDir(::getenv("TMPDIR")); + const char* tmpDir{::getenv("TMPDIR")}; // Make sure path ends with a slash so it's ready to have a file name // appended. (_PATH_VARTMP already has this on all platforms I've seen, // but a user-defined $TMPDIR might not.) - std::string path((tmpDir == nullptr) ? _PATH_VARTMP : tmpDir); + std::string path{(tmpDir == nullptr) ? _PATH_VARTMP : tmpDir}; if (path[path.length() - 1] != '/') { path += '/'; } @@ -174,18 +182,32 @@ std::string CNamedPipeFactory::defaultPath() { } CNamedPipeFactory::TPipeHandle -CNamedPipeFactory::initPipeHandle(const std::string& fileName, bool forWrite) { +CNamedPipeFactory::initPipeHandle(const std::string& fileName, + bool forWrite, + const std::atomic_bool& isCancelled) { if (!SIGPIPE_IGNORED) { LOG_WARN(<< "Failed to ignore SIGPIPE - this process will not terminate " "gracefully if a process it is writing to via a named pipe dies"); } - bool madeFifo(false); + bool madeFifo{false}; + + auto retrySyscallOnInterruptUnlessCancelled = [&isCancelled](std::function fn) { + int ret{-1}; + if (isCancelled.load() == false) { + do { + ret = fn(); + } while (ret == -1 && errno == EINTR && isCancelled.load() == false); + } + return ret; + }; // If the name already exists, ensure it refers directly (i.e. not via a // symlink) to a named pipe COsFileFuncs::TStat statbuf; - if (COsFileFuncs::lstat(fileName.c_str(), &statbuf) == 0) { + if (retrySyscallOnInterruptUnlessCancelled([&fileName, &statbuf]() { + return COsFileFuncs::lstat(fileName.c_str(), &statbuf); + }) == 0) { if ((statbuf.st_mode & S_IFMT) != S_IFIFO) { LOG_ERROR(<< "Unable to create named pipe " << fileName << " - a file " @@ -199,36 +221,52 @@ CNamedPipeFactory::initPipeHandle(const std::string& fileName, bool forWrite) { return -1; } } else { - if (errno != ENOENT) { + if (errno != ENOENT && isCancelled.load() == false) { LOG_WARN(<< "lstat of named pipe " << fileName << " failed with unexpected error " << ::strerror(errno)); } // The file didn't exist, so create a new FIFO for it, with permissions // for the current user only - if (::mkfifo(fileName.c_str(), S_IRUSR | S_IWUSR) == -1) { - LOG_ERROR(<< "Unable to create named pipe " << fileName << ": " - << ::strerror(errno)); + if (retrySyscallOnInterruptUnlessCancelled([&fileName]() { + return ::mkfifo(fileName.c_str(), S_IRUSR | S_IWUSR); + }) == -1) { + if (isCancelled.load() == false) { + LOG_ERROR(<< "Unable to create named pipe " << fileName << ": " + << ::strerror(errno)); + } return -1; } madeFifo = true; } + if (isCancelled.load()) { + return -1; + } + // The open call here will block if there is no other connection to the // named pipe - int fd = COsFileFuncs::open(fileName.c_str(), forWrite ? COsFileFuncs::WRONLY - : COsFileFuncs::RDONLY); + int fd{retrySyscallOnInterruptUnlessCancelled([&fileName, forWrite]() { + return COsFileFuncs::open(fileName.c_str(), forWrite ? COsFileFuncs::WRONLY + : COsFileFuncs::RDONLY); + })}; if (fd == -1) { - LOG_ERROR(<< "Unable to open named pipe " << fileName - << (forWrite ? " for writing: " : " for reading: ") - << ::strerror(errno)); + if (isCancelled.load() == false) { + LOG_ERROR(<< "Unable to open named pipe " << fileName + << (forWrite ? " for writing: " : " for reading: ") + << ::strerror(errno)); + } } else { // Write a test character to the pipe - this is really only necessary on // Windows, but doing it on *nix too will mean the inability of the Java // code to tolerate the test character will be discovered sooner. - if (forWrite && COsFileFuncs::write(fd, &TEST_CHAR, sizeof(TEST_CHAR)) <= 0) { - LOG_ERROR(<< "Unable to test named pipe " << fileName << ": " - << ::strerror(errno)); + if (forWrite && retrySyscallOnInterruptUnlessCancelled([fd]() { + return COsFileFuncs::write(fd, &TEST_CHAR, sizeof(TEST_CHAR)); + }) <= 0) { + if (isCancelled.load() == false) { + LOG_ERROR(<< "Unable to test named pipe " << fileName << ": " + << ::strerror(errno)); + } COsFileFuncs::close(fd); fd = -1; } diff --git a/lib/core/CNamedPipeFactory_Windows.cc b/lib/core/CNamedPipeFactory_Windows.cc index a41f7d717b..bb1c778ea4 100644 --- a/lib/core/CNamedPipeFactory_Windows.cc +++ b/lib/core/CNamedPipeFactory_Windows.cc @@ -19,59 +19,67 @@ namespace { //! fclose() doesn't check for NULL pointers, so wrap it for use as a shared_ptr //! deleter void safeFClose(FILE* file) { - if (file != 0) { + if (file != nullptr) { ::fclose(file); } } //! On Windows ALL named pipes are under this path -const std::string PIPE_PREFIX("\\\\.\\pipe\\"); +const std::string PIPE_PREFIX{"\\\\.\\pipe\\"}; } namespace ml { namespace core { // Initialise static -const char CNamedPipeFactory::TEST_CHAR('\n'); +const char CNamedPipeFactory::TEST_CHAR{'\n'}; -CNamedPipeFactory::TIStreamP CNamedPipeFactory::openPipeStreamRead(const std::string& fileName) { - TPipeHandle handle = CNamedPipeFactory::initPipeHandle(fileName, false); +CNamedPipeFactory::TIStreamP +CNamedPipeFactory::openPipeStreamRead(const std::string& fileName, + const std::atomic_bool& isCancelled) { + TPipeHandle handle{CNamedPipeFactory::initPipeHandle(fileName, false, isCancelled)}; if (handle == INVALID_HANDLE_VALUE) { - return TIStreamP(); + return TIStreamP{}; } using TFileDescriptorSourceStream = boost::iostreams::stream; - return TIStreamP(new TFileDescriptorSourceStream(boost::iostreams::file_descriptor_source( - handle, boost::iostreams::close_handle))); + return TIStreamP{new TFileDescriptorSourceStream(boost::iostreams::file_descriptor_source( + handle, boost::iostreams::close_handle))}; } -CNamedPipeFactory::TOStreamP CNamedPipeFactory::openPipeStreamWrite(const std::string& fileName) { - TPipeHandle handle = CNamedPipeFactory::initPipeHandle(fileName, true); +CNamedPipeFactory::TOStreamP +CNamedPipeFactory::openPipeStreamWrite(const std::string& fileName, + const std::atomic_bool& isCancelled) { + TPipeHandle handle{CNamedPipeFactory::initPipeHandle(fileName, true, isCancelled)}; if (handle == INVALID_HANDLE_VALUE) { - return TOStreamP(); + return TOStreamP{}; } using TFileDescriptorSinkStream = boost::iostreams::stream; - return TOStreamP(new TFileDescriptorSinkStream( - boost::iostreams::file_descriptor_sink(handle, boost::iostreams::close_handle))); + return TOStreamP{new TFileDescriptorSinkStream( + boost::iostreams::file_descriptor_sink(handle, boost::iostreams::close_handle))}; } -CNamedPipeFactory::TFileP CNamedPipeFactory::openPipeFileRead(const std::string& fileName) { - TPipeHandle handle = CNamedPipeFactory::initPipeHandle(fileName, false); +CNamedPipeFactory::TFileP +CNamedPipeFactory::openPipeFileRead(const std::string& fileName, + const std::atomic_bool& isCancelled) { + TPipeHandle handle{CNamedPipeFactory::initPipeHandle(fileName, false, isCancelled)}; if (handle == INVALID_HANDLE_VALUE) { - return TFileP(); + return TFileP{}; } - return TFileP(::fdopen(::_open_osfhandle(reinterpret_cast(handle), _O_RDONLY), "rb"), - safeFClose); + return TFileP{::fdopen(::_open_osfhandle(reinterpret_cast(handle), _O_RDONLY), "rb"), + safeFClose}; } -CNamedPipeFactory::TFileP CNamedPipeFactory::openPipeFileWrite(const std::string& fileName) { - TPipeHandle handle = CNamedPipeFactory::initPipeHandle(fileName, true); +CNamedPipeFactory::TFileP +CNamedPipeFactory::openPipeFileWrite(const std::string& fileName, + const std::atomic_bool& isCancelled) { + TPipeHandle handle{CNamedPipeFactory::initPipeHandle(fileName, true, isCancelled)}; if (handle == INVALID_HANDLE_VALUE) { - return TFileP(); + return TFileP{}; } - return TFileP(::fdopen(::_open_osfhandle(reinterpret_cast(handle), 0), "wb"), - safeFClose); + return TFileP{::fdopen(::_open_osfhandle(reinterpret_cast(handle), 0), "wb"), + safeFClose}; } bool CNamedPipeFactory::isNamedPipe(const std::string& fileName) { @@ -84,21 +92,26 @@ std::string CNamedPipeFactory::defaultPath() { } CNamedPipeFactory::TPipeHandle -CNamedPipeFactory::initPipeHandle(const std::string& fileName, bool forWrite) { +CNamedPipeFactory::initPipeHandle(const std::string& fileName, + bool forWrite, + const std::atomic_bool& isCancelled) { // Size of named pipe buffer - static const DWORD BUFFER_SIZE(4096); + static const DWORD BUFFER_SIZE{4096}; // If the name already exists, ensure it refers to a named pipe - HANDLE handle(CreateNamedPipe(fileName.c_str(), + HANDLE handle{CreateNamedPipe(fileName.c_str(), // Input pipes are opened as duplex so we can // write a test byte to them to work around // the Java security manager problem forWrite ? PIPE_ACCESS_OUTBOUND : PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, forWrite ? BUFFER_SIZE : 1, forWrite ? 1 : BUFFER_SIZE, - NMPWAIT_USE_DEFAULT_WAIT, 0)); + NMPWAIT_USE_DEFAULT_WAIT, 0)}; if (handle == INVALID_HANDLE_VALUE) { - LOG_ERROR(<< "Unable to create named pipe " << fileName << ": " << CWindowsError()); + if (isCancelled.load() == false) { + LOG_ERROR(<< "Unable to create named pipe " << fileName << ": " + << CWindowsError()); + } return INVALID_HANDLE_VALUE; } @@ -122,10 +135,10 @@ CNamedPipeFactory::initPipeHandle(const std::string& fileName, bool forWrite) { // write to the pipe to check whether it's still open on the remote side. // This means that all Java code that reads from Ml named pipes must // tolerate a test character appearing at the beginning of the data it - // receives. We use a newline character, as the named pipes carry lineified - // JSON and it's easy to make them tolerate blank lines. - bool sufferedShortLivedConnection(false); - DWORD attempt(0); + // receives. We use a newline character, as the named pipes carry ND-JSON + // and it's easy to make them tolerate blank lines. + bool sufferedShortLivedConnection{false}; + DWORD attempt{0}; do { ++attempt; // This call will block if there is no other connection to the named @@ -133,10 +146,12 @@ CNamedPipeFactory::initPipeHandle(const std::string& fileName, bool forWrite) { if (ConnectNamedPipe(handle, 0) == FALSE) { // ERROR_PIPE_CONNECTED means the pipe was already connected so // there was no need to connect it again - not a problem - DWORD errCode(GetLastError()); + DWORD errCode{GetLastError()}; if (errCode != ERROR_PIPE_CONNECTED) { - LOG_ERROR(<< "Unable to connect named pipe " << fileName << ": " - << CWindowsError(errCode)); + if (isCancelled.load() == false) { + LOG_ERROR(<< "Unable to connect named pipe " << fileName + << ": " << CWindowsError(errCode)); + } // Close the pipe (even though it was successfully opened) so // that the net effect of this failed call is nothing CloseHandle(handle); @@ -150,10 +165,16 @@ CNamedPipeFactory::initPipeHandle(const std::string& fileName, bool forWrite) { // Check that the other end of the pipe has not disconnected (which // relies on the Java side of all connections tolerating an initial // blank line) - DWORD bytesWritten(0); + DWORD bytesWritten{0}; if (WriteFile(handle, &TEST_CHAR, sizeof(TEST_CHAR), &bytesWritten, 0) == FALSE || bytesWritten == 0) { DisconnectNamedPipe(handle); + if (isCancelled.load()) { + // Close the pipe (even though it was successfully opened) so + // that the net effect of this failed call is nothing + CloseHandle(handle); + return INVALID_HANDLE_VALUE; + } sufferedShortLivedConnection = true; } else { sufferedShortLivedConnection = false; diff --git a/lib/core/CThread.cc b/lib/core/CThread.cc index ff47aa9aa2..9675201980 100644 --- a/lib/core/CThread.cc +++ b/lib/core/CThread.cc @@ -27,7 +27,7 @@ void noOpHandler(int /*sig*/) { //! Use SIGIO for waking up blocking calls. The same handler will be used in //! all threads, so there's an assumption here that having some other sort of //! handling for SIGIO is not important to any other thread in the process. -//! That will be true of Ml code. If a 3rd party library relied on SIGIO +//! That will be true of ML code. If a 3rd party library relied on SIGIO //! handling then we could change the signal we use in this class to another //! (maybe SIGURG). However, it's bad practice for reusable libraries to //! unconditionally install signal handlers, so unlikely to be a problem. diff --git a/lib/core/unittest/CNamedPipeFactoryTest.cc b/lib/core/unittest/CNamedPipeFactoryTest.cc index 74aa78be52..bd519d8b33 100644 --- a/lib/core/unittest/CNamedPipeFactoryTest.cc +++ b/lib/core/unittest/CNamedPipeFactoryTest.cc @@ -13,22 +13,24 @@ #include -#include +#include +#include + #ifndef Windows #include #endif namespace { -const uint32_t SLEEP_TIME_MS = 100; -const uint32_t PAUSE_TIME_MS = 10; -const size_t MAX_ATTEMPTS = 100; -const size_t TEST_SIZE = 10000; -const char TEST_CHAR = 'a'; +const std::uint32_t SLEEP_TIME_MS{100}; +const std::uint32_t PAUSE_TIME_MS{10}; +const std::size_t MAX_ATTEMPTS{100}; +const std::size_t TEST_SIZE{10000}; +const char TEST_CHAR{'a'}; #ifdef Windows -const char* const TEST_PIPE_NAME = "\\\\.\\pipe\\testpipe"; +const char* const TEST_PIPE_NAME{"\\\\.\\pipe\\testpipe"}; #else -const char* const TEST_PIPE_NAME = "testfiles/testpipe"; +const char* const TEST_PIPE_NAME{"testfiles/testpipe"}; #endif class CThreadDataWriter : public ml::core::CThread { @@ -106,21 +108,27 @@ class CThreadDataReader : public ml::core::CThread { class CThreadBlockCanceller : public ml::core::CThread { public: CThreadBlockCanceller(ml::core::CThread::TThreadId threadId) - : m_ThreadId(threadId) {} + : m_ThreadId{threadId}, m_HasCancelledBlockingCall{false} {} + + const std::atomic_bool& hasCancelledBlockingCall() { + return m_HasCancelledBlockingCall; + } protected: - virtual void run() { + void run() override { // Wait for the file to exist ml::core::CSleep::sleep(SLEEP_TIME_MS); // Cancel the open() or read() operation on the file + m_HasCancelledBlockingCall.store(true); CPPUNIT_ASSERT(ml::core::CThread::cancelBlockedIo(m_ThreadId)); } - virtual void shutdown() {} + void shutdown() override {} private: ml::core::CThread::TThreadId m_ThreadId; + std::atomic_bool m_HasCancelledBlockingCall; }; } @@ -149,14 +157,15 @@ CppUnit::Test* CNamedPipeFactoryTest::suite() { } void CNamedPipeFactoryTest::testServerIsCppReader() { - CThreadDataWriter threadWriter(TEST_PIPE_NAME, TEST_SIZE); + CThreadDataWriter threadWriter{TEST_PIPE_NAME, TEST_SIZE}; CPPUNIT_ASSERT(threadWriter.start()); - ml::core::CNamedPipeFactory::TIStreamP strm = - ml::core::CNamedPipeFactory::openPipeStreamRead(TEST_PIPE_NAME); + std::atomic_bool dummy{false}; + ml::core::CNamedPipeFactory::TIStreamP strm{ + ml::core::CNamedPipeFactory::openPipeStreamRead(TEST_PIPE_NAME, dummy)}; CPPUNIT_ASSERT(strm); - static const std::streamsize BUF_SIZE = 512; + static const std::streamsize BUF_SIZE{512}; std::string readData; char buffer[BUF_SIZE]; do { @@ -176,23 +185,24 @@ void CNamedPipeFactoryTest::testServerIsCppReader() { } void CNamedPipeFactoryTest::testServerIsCReader() { - CThreadDataWriter threadWriter(TEST_PIPE_NAME, TEST_SIZE); + CThreadDataWriter threadWriter{TEST_PIPE_NAME, TEST_SIZE}; CPPUNIT_ASSERT(threadWriter.start()); - ml::core::CNamedPipeFactory::TFileP file = - ml::core::CNamedPipeFactory::openPipeFileRead(TEST_PIPE_NAME); + std::atomic_bool dummy{false}; + ml::core::CNamedPipeFactory::TFileP file{ + ml::core::CNamedPipeFactory::openPipeFileRead(TEST_PIPE_NAME, dummy)}; CPPUNIT_ASSERT(file); - static const size_t BUF_SIZE = 512; + static const std::size_t BUF_SIZE{512}; std::string readData; char buffer[BUF_SIZE]; do { - size_t charsRead = ::fread(buffer, sizeof(char), BUF_SIZE, file.get()); - CPPUNIT_ASSERT(!::ferror(file.get())); + std::size_t charsRead{std::fread(buffer, sizeof(char), BUF_SIZE, file.get())}; + CPPUNIT_ASSERT(!std::ferror(file.get())); if (charsRead > 0) { readData.append(buffer, charsRead); } - } while (!::feof(file.get())); + } while (!std::feof(file.get())); CPPUNIT_ASSERT_EQUAL(TEST_SIZE, readData.length()); CPPUNIT_ASSERT_EQUAL(std::string(TEST_SIZE, TEST_CHAR), readData); @@ -203,15 +213,16 @@ void CNamedPipeFactoryTest::testServerIsCReader() { } void CNamedPipeFactoryTest::testServerIsCppWriter() { - CThreadDataReader threadReader(TEST_PIPE_NAME); + CThreadDataReader threadReader{TEST_PIPE_NAME}; CPPUNIT_ASSERT(threadReader.start()); - ml::core::CNamedPipeFactory::TOStreamP strm = - ml::core::CNamedPipeFactory::openPipeStreamWrite(TEST_PIPE_NAME); + std::atomic_bool dummy{false}; + ml::core::CNamedPipeFactory::TOStreamP strm{ + ml::core::CNamedPipeFactory::openPipeStreamWrite(TEST_PIPE_NAME, dummy)}; CPPUNIT_ASSERT(strm); - size_t charsLeft(TEST_SIZE); - size_t blockSize(7); + std::size_t charsLeft{TEST_SIZE}; + std::size_t blockSize{7}; while (charsLeft > 0) { if (blockSize > charsLeft) { blockSize = charsLeft; @@ -230,20 +241,22 @@ void CNamedPipeFactoryTest::testServerIsCppWriter() { } void CNamedPipeFactoryTest::testServerIsCWriter() { - CThreadDataReader threadReader(TEST_PIPE_NAME); + CThreadDataReader threadReader{TEST_PIPE_NAME}; CPPUNIT_ASSERT(threadReader.start()); - ml::core::CNamedPipeFactory::TFileP file = - ml::core::CNamedPipeFactory::openPipeFileWrite(TEST_PIPE_NAME); + std::atomic_bool dummy{false}; + ml::core::CNamedPipeFactory::TFileP file{ + ml::core::CNamedPipeFactory::openPipeFileWrite(TEST_PIPE_NAME, dummy)}; CPPUNIT_ASSERT(file); - size_t charsLeft(TEST_SIZE); - size_t blockSize(7); + std::size_t charsLeft{TEST_SIZE}; + std::size_t blockSize{7}; while (charsLeft > 0) { if (blockSize > charsLeft) { blockSize = charsLeft; } - CPPUNIT_ASSERT(::fputs(std::string(blockSize, TEST_CHAR).c_str(), file.get()) >= 0); + CPPUNIT_ASSERT(std::fputs(std::string(blockSize, TEST_CHAR).c_str(), + file.get()) >= 0); charsLeft -= blockSize; } @@ -256,19 +269,20 @@ void CNamedPipeFactoryTest::testServerIsCWriter() { } void CNamedPipeFactoryTest::testCancelBlock() { - CThreadBlockCanceller cancellerThread(ml::core::CThread::currentThreadId()); + CThreadBlockCanceller cancellerThread{ml::core::CThread::currentThreadId()}; CPPUNIT_ASSERT(cancellerThread.start()); - ml::core::CNamedPipeFactory::TOStreamP strm = - ml::core::CNamedPipeFactory::openPipeStreamWrite(TEST_PIPE_NAME); + ml::core::CNamedPipeFactory::TOStreamP strm{ml::core::CNamedPipeFactory::openPipeStreamWrite( + TEST_PIPE_NAME, cancellerThread.hasCancelledBlockingCall())}; CPPUNIT_ASSERT(strm == nullptr); CPPUNIT_ASSERT(cancellerThread.stop()); } void CNamedPipeFactoryTest::testErrorIfRegularFile() { - ml::core::CNamedPipeFactory::TIStreamP strm = - ml::core::CNamedPipeFactory::openPipeStreamRead("Main.cc"); + std::atomic_bool dummy{false}; + ml::core::CNamedPipeFactory::TIStreamP strm{ + ml::core::CNamedPipeFactory::openPipeStreamRead("Main.cc", dummy)}; CPPUNIT_ASSERT(strm == nullptr); } @@ -279,7 +293,7 @@ void CNamedPipeFactoryTest::testErrorIfSymlink() { // the file system LOG_DEBUG(<< "symlink test not relevant to Windows"); #else - static const char* const TEST_SYMLINK_NAME = "test_symlink"; + static const char* const TEST_SYMLINK_NAME{"test_symlink"}; // Remove any files left behind by a previous failed test, but don't check // the return codes as these calls will usually fail @@ -289,8 +303,9 @@ void CNamedPipeFactoryTest::testErrorIfSymlink() { CPPUNIT_ASSERT_EQUAL(0, ::mkfifo(TEST_PIPE_NAME, S_IRUSR | S_IWUSR)); CPPUNIT_ASSERT_EQUAL(0, ::symlink(TEST_PIPE_NAME, TEST_SYMLINK_NAME)); - ml::core::CNamedPipeFactory::TIStreamP strm = - ml::core::CNamedPipeFactory::openPipeStreamRead(TEST_SYMLINK_NAME); + std::atomic_bool dummy{false}; + ml::core::CNamedPipeFactory::TIStreamP strm{ + ml::core::CNamedPipeFactory::openPipeStreamRead(TEST_SYMLINK_NAME, dummy)}; CPPUNIT_ASSERT(strm == nullptr); CPPUNIT_ASSERT_EQUAL(0, ::unlink(TEST_SYMLINK_NAME)); diff --git a/lib/seccomp/unittest/CSystemCallFilterTest.cc b/lib/seccomp/unittest/CSystemCallFilterTest.cc index eebe1d3d3e..4c88dea4d2 100644 --- a/lib/seccomp/unittest/CSystemCallFilterTest.cc +++ b/lib/seccomp/unittest/CSystemCallFilterTest.cc @@ -21,15 +21,16 @@ #include #include +#include #include #include namespace { -const uint32_t SLEEP_TIME_MS = 100; -const size_t TEST_SIZE = 10000; -const size_t MAX_ATTEMPTS = 20; -const char TEST_CHAR = 'a'; +const std::uint32_t SLEEP_TIME_MS{100}; +const std::size_t TEST_SIZE{10000}; +const std::size_t MAX_ATTEMPTS{20}; +const char TEST_CHAR{'a'}; // CTestTmpDir::tmpDir() fails to get the current user after the system call // filter is installed, so cache the value early const std::string TMP_DIR{ml::test::CTestTmpDir::tmpDir()}; @@ -176,14 +177,15 @@ void CSystemCallFilterTest::testSystemCallFilter() { void CSystemCallFilterTest::openPipeAndRead(const std::string& filename) { - CNamedPipeWriter threadWriter(filename, TEST_SIZE); + CNamedPipeWriter threadWriter{filename, TEST_SIZE}; CPPUNIT_ASSERT(threadWriter.start()); - ml::core::CNamedPipeFactory::TIStreamP strm = - ml::core::CNamedPipeFactory::openPipeStreamRead(filename); + std::atomic_bool dummy{false}; + ml::core::CNamedPipeFactory::TIStreamP strm{ + ml::core::CNamedPipeFactory::openPipeStreamRead(filename, dummy)}; CPPUNIT_ASSERT(strm); - static const std::streamsize BUF_SIZE = 512; + static const std::streamsize BUF_SIZE{512}; std::string readData; readData.reserve(TEST_SIZE); char buffer[BUF_SIZE]; @@ -204,15 +206,16 @@ void CSystemCallFilterTest::openPipeAndRead(const std::string& filename) { } void CSystemCallFilterTest::openPipeAndWrite(const std::string& filename) { - CNamedPipeReader threadReader(filename); + CNamedPipeReader threadReader{filename}; CPPUNIT_ASSERT(threadReader.start()); - ml::core::CNamedPipeFactory::TOStreamP strm = - ml::core::CNamedPipeFactory::openPipeStreamWrite(filename); + std::atomic_bool dummy{false}; + ml::core::CNamedPipeFactory::TOStreamP strm{ + ml::core::CNamedPipeFactory::openPipeStreamWrite(filename, dummy)}; CPPUNIT_ASSERT(strm); - size_t charsLeft(TEST_SIZE); - size_t blockSize(7); + std::size_t charsLeft{TEST_SIZE}; + std::size_t blockSize{7}; while (charsLeft > 0) { if (blockSize > charsLeft) { blockSize = charsLeft; @@ -232,7 +235,7 @@ void CSystemCallFilterTest::openPipeAndWrite(const std::string& filename) { void CSystemCallFilterTest::makeAndRemoveDirectory(const std::string& dirname) { - boost::filesystem::path temporaryFolder(dirname); + boost::filesystem::path temporaryFolder{dirname}; temporaryFolder /= "test-directory"; boost::system::error_code errorCode; From b027c432305ed9f4bb1f5315b21c2d574dc2610a Mon Sep 17 00:00:00 2001 From: David Roberts Date: Wed, 17 Jun 2020 18:16:19 +0100 Subject: [PATCH 2/5] Visual Studio 2013 workaround --- bin/controller/CBlockingCallCancellerThread.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/controller/CBlockingCallCancellerThread.cc b/bin/controller/CBlockingCallCancellerThread.cc index ef183c42de..b26ab5b5fb 100644 --- a/bin/controller/CBlockingCallCancellerThread.cc +++ b/bin/controller/CBlockingCallCancellerThread.cc @@ -14,8 +14,8 @@ namespace controller { CBlockingCallCancellerThread::CBlockingCallCancellerThread(core::CThread::TThreadId potentiallyBlockedThreadId, std::istream& monitorStream) - : m_PotentiallyBlockedThreadId{potentiallyBlockedThreadId}, - m_MonitorStream{monitorStream}, m_Shutdown{false}, m_HasCancelledBlockingCall{false} { + : m_PotentiallyBlockedThreadId(potentiallyBlockedThreadId), + m_MonitorStream(monitorStream), m_Shutdown(false), m_HasCancelledBlockingCall(false) { } const std::atomic_bool& CBlockingCallCancellerThread::hasCancelledBlockingCall() const { From ca5557e8e1fe6de176a365b1a425503edaae5d54 Mon Sep 17 00:00:00 2001 From: David Roberts Date: Wed, 17 Jun 2020 20:22:28 +0100 Subject: [PATCH 3/5] Revert "Visual Studio 2013 workaround" This reverts commit b027c432305ed9f4bb1f5315b21c2d574dc2610a. --- bin/controller/CBlockingCallCancellerThread.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/controller/CBlockingCallCancellerThread.cc b/bin/controller/CBlockingCallCancellerThread.cc index b26ab5b5fb..ef183c42de 100644 --- a/bin/controller/CBlockingCallCancellerThread.cc +++ b/bin/controller/CBlockingCallCancellerThread.cc @@ -14,8 +14,8 @@ namespace controller { CBlockingCallCancellerThread::CBlockingCallCancellerThread(core::CThread::TThreadId potentiallyBlockedThreadId, std::istream& monitorStream) - : m_PotentiallyBlockedThreadId(potentiallyBlockedThreadId), - m_MonitorStream(monitorStream), m_Shutdown(false), m_HasCancelledBlockingCall(false) { + : m_PotentiallyBlockedThreadId{potentiallyBlockedThreadId}, + m_MonitorStream{monitorStream}, m_Shutdown{false}, m_HasCancelledBlockingCall{false} { } const std::atomic_bool& CBlockingCallCancellerThread::hasCancelledBlockingCall() const { From c80b3340d5f6230c9f9c25f122b6b4a6914ac216 Mon Sep 17 00:00:00 2001 From: David Roberts Date: Wed, 17 Jun 2020 20:53:58 +0100 Subject: [PATCH 4/5] Need to use atomic_t instead of std on 6.x Due to Visual Studio 2013 crapness... --- bin/controller/CBlockingCallCancellerThread.cc | 2 +- bin/controller/CBlockingCallCancellerThread.h | 8 ++++---- include/core/CLogger.h | 7 +++---- include/core/CNamedPipeFactory.h | 12 ++++++------ lib/api/CIoManager.cc | 6 +++--- lib/core/CLogger.cc | 8 ++++---- lib/core/CNamedPipeFactory.cc | 10 +++++----- lib/core/CNamedPipeFactory_Windows.cc | 10 +++++----- lib/core/unittest/CNamedPipeFactoryTest.cc | 18 +++++++++--------- lib/seccomp/unittest/CSystemCallFilterTest.cc | 6 +++--- 10 files changed, 43 insertions(+), 44 deletions(-) diff --git a/bin/controller/CBlockingCallCancellerThread.cc b/bin/controller/CBlockingCallCancellerThread.cc index ef183c42de..07d57c26ca 100644 --- a/bin/controller/CBlockingCallCancellerThread.cc +++ b/bin/controller/CBlockingCallCancellerThread.cc @@ -18,7 +18,7 @@ CBlockingCallCancellerThread::CBlockingCallCancellerThread(core::CThread::TThrea m_MonitorStream{monitorStream}, m_Shutdown{false}, m_HasCancelledBlockingCall{false} { } -const std::atomic_bool& CBlockingCallCancellerThread::hasCancelledBlockingCall() const { +const atomic_t::atomic_bool& CBlockingCallCancellerThread::hasCancelledBlockingCall() const { return m_HasCancelledBlockingCall; } diff --git a/bin/controller/CBlockingCallCancellerThread.h b/bin/controller/CBlockingCallCancellerThread.h index 66fc709268..bd7b3ea765 100644 --- a/bin/controller/CBlockingCallCancellerThread.h +++ b/bin/controller/CBlockingCallCancellerThread.h @@ -6,9 +6,9 @@ #ifndef INCLUDED_ml_controller_CBlockingCallCancellerThread_h #define INCLUDED_ml_controller_CBlockingCallCancellerThread_h +#include #include -#include #include namespace ml { @@ -40,7 +40,7 @@ class CBlockingCallCancellerThread : public core::CThread { CBlockingCallCancellerThread(core::CThread::TThreadId potentiallyBlockedThreadId, std::istream& monitorStream); - const std::atomic_bool& hasCancelledBlockingCall() const; + const atomic_t::atomic_bool& hasCancelledBlockingCall() const; protected: //! Called when the thread is started. @@ -58,11 +58,11 @@ class CBlockingCallCancellerThread : public core::CThread { std::istream& m_MonitorStream; //! Flag to indicate the monitoring thread should shut down - std::atomic_bool m_Shutdown; + atomic_t::atomic_bool m_Shutdown; //! Flag to indicate that an attempt to cancel blocking calls in the //! monitored thread has been made - std::atomic_bool m_HasCancelledBlockingCall; + atomic_t::atomic_bool m_HasCancelledBlockingCall; }; } } diff --git a/include/core/CLogger.h b/include/core/CLogger.h index 29cdec236e..d1a9dd647f 100644 --- a/include/core/CLogger.h +++ b/include/core/CLogger.h @@ -6,6 +6,7 @@ #ifndef INCLUDED_ml_core_CLogger_h #define INCLUDED_ml_core_CLogger_h +#include #include #include #include @@ -15,8 +16,6 @@ #include #include -#include - #include class CLoggerTest; @@ -82,7 +81,7 @@ class CORE_EXPORT CLogger : private CNonCopyable { //! should be cancelled. bool reconfigure(const std::string& pipeName, const std::string& propertiesFile, - const std::atomic_bool& isCancelled); + const atomic_t::atomic_bool& isCancelled); //! Tell the logger to log to a named pipe rather than a file. bool reconfigureLogToNamedPipe(const std::string& pipeName); @@ -90,7 +89,7 @@ class CORE_EXPORT CLogger : private CNonCopyable { //! As above, but with a flag to indicate named pipe connection attempts //! should be cancelled. bool reconfigureLogToNamedPipe(const std::string& pipeName, - const std::atomic_bool& isCancelled); + const atomic_t::atomic_bool& isCancelled); //! Tell the logger to reconfigure itself by reading a specified //! properties file, if the file exists. diff --git a/include/core/CNamedPipeFactory.h b/include/core/CNamedPipeFactory.h index ccace4379e..14b499e30d 100644 --- a/include/core/CNamedPipeFactory.h +++ b/include/core/CNamedPipeFactory.h @@ -6,11 +6,11 @@ #ifndef INCLUDED_ml_core_CNamedPipeFactory_h #define INCLUDED_ml_core_CNamedPipeFactory_h +#include #include #include #include -#include #include #include #include @@ -71,23 +71,23 @@ class CORE_EXPORT CNamedPipeFactory : private CNonInstantiatable { //! that can be used to read from it. Returns a NULL pointer on //! failure. static TIStreamP openPipeStreamRead(const std::string& fileName, - const std::atomic_bool& isCancelled); + const atomic_t::atomic_bool& isCancelled); //! Initialise and open a named pipe for writing, returning a C++ stream //! that can be used to write to it. Returns a NULL pointer on failure. static TOStreamP openPipeStreamWrite(const std::string& fileName, - const std::atomic_bool& isCancelled); + const atomic_t::atomic_bool& isCancelled); //! Initialise and open a named pipe for writing, returning a C FILE //! that can be used to read from it. Returns a NULL pointer on //! failure. static TFileP openPipeFileRead(const std::string& fileName, - const std::atomic_bool& isCancelled); + const atomic_t::atomic_bool& isCancelled); //! Initialise and open a named pipe for writing, returning a C FILE //! that can be used to write to it. Returns a NULL pointer on failure. static TFileP openPipeFileWrite(const std::string& fileName, - const std::atomic_bool& isCancelled); + const atomic_t::atomic_bool& isCancelled); //! Does the supplied file name refer to a named pipe? static bool isNamedPipe(const std::string& fileName); @@ -109,7 +109,7 @@ class CORE_EXPORT CNamedPipeFactory : private CNonInstantiatable { //! interface provides. static TPipeHandle initPipeHandle(const std::string& fileName, bool forWrite, - const std::atomic_bool& isCancelled); + const atomic_t::atomic_bool& isCancelled); }; } } diff --git a/lib/api/CIoManager.cc b/lib/api/CIoManager.cc index 6409c26787..b3205f739e 100644 --- a/lib/api/CIoManager.cc +++ b/lib/api/CIoManager.cc @@ -5,9 +5,9 @@ */ #include +#include #include -#include #include #include #include @@ -25,7 +25,7 @@ bool setUpIStream(const std::string& fileName, return true; } if (isFileNamedPipe) { - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; stream = core::CNamedPipeFactory::openPipeStreamRead(fileName, dummy); return stream != nullptr && !stream->bad(); } @@ -42,7 +42,7 @@ bool setUpOStream(const std::string& fileName, return true; } if (isFileNamedPipe) { - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; stream = core::CNamedPipeFactory::openPipeStreamWrite(fileName, dummy); return stream != nullptr && !stream->bad(); } diff --git a/lib/core/CLogger.cc b/lib/core/CLogger.cc index c37c68fa8a..02fd740e11 100644 --- a/lib/core/CLogger.cc +++ b/lib/core/CLogger.cc @@ -228,13 +228,13 @@ bool CLogger::setLoggingLevel(ELevel level) { } bool CLogger::reconfigure(const std::string& pipeName, const std::string& propertiesFile) { - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; return this->reconfigure(pipeName, propertiesFile, dummy); } bool CLogger::reconfigure(const std::string& pipeName, const std::string& propertiesFile, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { if (pipeName.empty()) { if (propertiesFile.empty()) { // Both empty is OK - it just means we keep logging to stderr @@ -246,12 +246,12 @@ bool CLogger::reconfigure(const std::string& pipeName, } bool CLogger::reconfigureLogToNamedPipe(const std::string& pipeName) { - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; return this->reconfigureLogToNamedPipe(pipeName, dummy); } bool CLogger::reconfigureLogToNamedPipe(const std::string& pipeName, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { if (m_Reconfigured) { LOG_ERROR(<< "Cannot log to a named pipe after logger reconfiguration"); return false; diff --git a/lib/core/CNamedPipeFactory.cc b/lib/core/CNamedPipeFactory.cc index f1f29b966a..b8d9e938c8 100644 --- a/lib/core/CNamedPipeFactory.cc +++ b/lib/core/CNamedPipeFactory.cc @@ -109,7 +109,7 @@ const char CNamedPipeFactory::TEST_CHAR('\n'); CNamedPipeFactory::TIStreamP CNamedPipeFactory::openPipeStreamRead(const std::string& fileName, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { TPipeHandle fd{CNamedPipeFactory::initPipeHandle(fileName, false, isCancelled)}; if (fd == -1) { return TIStreamP{}; @@ -122,7 +122,7 @@ CNamedPipeFactory::openPipeStreamRead(const std::string& fileName, CNamedPipeFactory::TOStreamP CNamedPipeFactory::openPipeStreamWrite(const std::string& fileName, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { TPipeHandle fd{CNamedPipeFactory::initPipeHandle(fileName, true, isCancelled)}; if (fd == -1) { return TOStreamP{}; @@ -135,7 +135,7 @@ CNamedPipeFactory::openPipeStreamWrite(const std::string& fileName, CNamedPipeFactory::TFileP CNamedPipeFactory::openPipeFileRead(const std::string& fileName, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { TPipeHandle fd{CNamedPipeFactory::initPipeHandle(fileName, false, isCancelled)}; if (fd == -1) { return TFileP{}; @@ -145,7 +145,7 @@ CNamedPipeFactory::openPipeFileRead(const std::string& fileName, CNamedPipeFactory::TFileP CNamedPipeFactory::openPipeFileWrite(const std::string& fileName, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { TPipeHandle fd{CNamedPipeFactory::initPipeHandle(fileName, true, isCancelled)}; if (fd == -1) { return TFileP{}; @@ -184,7 +184,7 @@ std::string CNamedPipeFactory::defaultPath() { CNamedPipeFactory::TPipeHandle CNamedPipeFactory::initPipeHandle(const std::string& fileName, bool forWrite, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { if (!SIGPIPE_IGNORED) { LOG_WARN(<< "Failed to ignore SIGPIPE - this process will not terminate " "gracefully if a process it is writing to via a named pipe dies"); diff --git a/lib/core/CNamedPipeFactory_Windows.cc b/lib/core/CNamedPipeFactory_Windows.cc index bb1c778ea4..6ff741c7bf 100644 --- a/lib/core/CNamedPipeFactory_Windows.cc +++ b/lib/core/CNamedPipeFactory_Windows.cc @@ -36,7 +36,7 @@ const char CNamedPipeFactory::TEST_CHAR{'\n'}; CNamedPipeFactory::TIStreamP CNamedPipeFactory::openPipeStreamRead(const std::string& fileName, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { TPipeHandle handle{CNamedPipeFactory::initPipeHandle(fileName, false, isCancelled)}; if (handle == INVALID_HANDLE_VALUE) { return TIStreamP{}; @@ -49,7 +49,7 @@ CNamedPipeFactory::openPipeStreamRead(const std::string& fileName, CNamedPipeFactory::TOStreamP CNamedPipeFactory::openPipeStreamWrite(const std::string& fileName, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { TPipeHandle handle{CNamedPipeFactory::initPipeHandle(fileName, true, isCancelled)}; if (handle == INVALID_HANDLE_VALUE) { return TOStreamP{}; @@ -62,7 +62,7 @@ CNamedPipeFactory::openPipeStreamWrite(const std::string& fileName, CNamedPipeFactory::TFileP CNamedPipeFactory::openPipeFileRead(const std::string& fileName, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { TPipeHandle handle{CNamedPipeFactory::initPipeHandle(fileName, false, isCancelled)}; if (handle == INVALID_HANDLE_VALUE) { return TFileP{}; @@ -73,7 +73,7 @@ CNamedPipeFactory::openPipeFileRead(const std::string& fileName, CNamedPipeFactory::TFileP CNamedPipeFactory::openPipeFileWrite(const std::string& fileName, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { TPipeHandle handle{CNamedPipeFactory::initPipeHandle(fileName, true, isCancelled)}; if (handle == INVALID_HANDLE_VALUE) { return TFileP{}; @@ -94,7 +94,7 @@ std::string CNamedPipeFactory::defaultPath() { CNamedPipeFactory::TPipeHandle CNamedPipeFactory::initPipeHandle(const std::string& fileName, bool forWrite, - const std::atomic_bool& isCancelled) { + const atomic_t::atomic_bool& isCancelled) { // Size of named pipe buffer static const DWORD BUFFER_SIZE{4096}; diff --git a/lib/core/unittest/CNamedPipeFactoryTest.cc b/lib/core/unittest/CNamedPipeFactoryTest.cc index bd519d8b33..358de70cf0 100644 --- a/lib/core/unittest/CNamedPipeFactoryTest.cc +++ b/lib/core/unittest/CNamedPipeFactoryTest.cc @@ -5,6 +5,7 @@ */ #include "CNamedPipeFactoryTest.h" +#include #include #include #include @@ -13,7 +14,6 @@ #include -#include #include #ifndef Windows @@ -110,7 +110,7 @@ class CThreadBlockCanceller : public ml::core::CThread { CThreadBlockCanceller(ml::core::CThread::TThreadId threadId) : m_ThreadId{threadId}, m_HasCancelledBlockingCall{false} {} - const std::atomic_bool& hasCancelledBlockingCall() { + const atomic_t::atomic_bool& hasCancelledBlockingCall() { return m_HasCancelledBlockingCall; } @@ -128,7 +128,7 @@ class CThreadBlockCanceller : public ml::core::CThread { private: ml::core::CThread::TThreadId m_ThreadId; - std::atomic_bool m_HasCancelledBlockingCall; + atomic_t::atomic_bool m_HasCancelledBlockingCall; }; } @@ -160,7 +160,7 @@ void CNamedPipeFactoryTest::testServerIsCppReader() { CThreadDataWriter threadWriter{TEST_PIPE_NAME, TEST_SIZE}; CPPUNIT_ASSERT(threadWriter.start()); - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; ml::core::CNamedPipeFactory::TIStreamP strm{ ml::core::CNamedPipeFactory::openPipeStreamRead(TEST_PIPE_NAME, dummy)}; CPPUNIT_ASSERT(strm); @@ -188,7 +188,7 @@ void CNamedPipeFactoryTest::testServerIsCReader() { CThreadDataWriter threadWriter{TEST_PIPE_NAME, TEST_SIZE}; CPPUNIT_ASSERT(threadWriter.start()); - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; ml::core::CNamedPipeFactory::TFileP file{ ml::core::CNamedPipeFactory::openPipeFileRead(TEST_PIPE_NAME, dummy)}; CPPUNIT_ASSERT(file); @@ -216,7 +216,7 @@ void CNamedPipeFactoryTest::testServerIsCppWriter() { CThreadDataReader threadReader{TEST_PIPE_NAME}; CPPUNIT_ASSERT(threadReader.start()); - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; ml::core::CNamedPipeFactory::TOStreamP strm{ ml::core::CNamedPipeFactory::openPipeStreamWrite(TEST_PIPE_NAME, dummy)}; CPPUNIT_ASSERT(strm); @@ -244,7 +244,7 @@ void CNamedPipeFactoryTest::testServerIsCWriter() { CThreadDataReader threadReader{TEST_PIPE_NAME}; CPPUNIT_ASSERT(threadReader.start()); - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; ml::core::CNamedPipeFactory::TFileP file{ ml::core::CNamedPipeFactory::openPipeFileWrite(TEST_PIPE_NAME, dummy)}; CPPUNIT_ASSERT(file); @@ -280,7 +280,7 @@ void CNamedPipeFactoryTest::testCancelBlock() { } void CNamedPipeFactoryTest::testErrorIfRegularFile() { - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; ml::core::CNamedPipeFactory::TIStreamP strm{ ml::core::CNamedPipeFactory::openPipeStreamRead("Main.cc", dummy)}; CPPUNIT_ASSERT(strm == nullptr); @@ -303,7 +303,7 @@ void CNamedPipeFactoryTest::testErrorIfSymlink() { CPPUNIT_ASSERT_EQUAL(0, ::mkfifo(TEST_PIPE_NAME, S_IRUSR | S_IWUSR)); CPPUNIT_ASSERT_EQUAL(0, ::symlink(TEST_PIPE_NAME, TEST_SYMLINK_NAME)); - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; ml::core::CNamedPipeFactory::TIStreamP strm{ ml::core::CNamedPipeFactory::openPipeStreamRead(TEST_SYMLINK_NAME, dummy)}; CPPUNIT_ASSERT(strm == nullptr); diff --git a/lib/seccomp/unittest/CSystemCallFilterTest.cc b/lib/seccomp/unittest/CSystemCallFilterTest.cc index 4c88dea4d2..146be62ad5 100644 --- a/lib/seccomp/unittest/CSystemCallFilterTest.cc +++ b/lib/seccomp/unittest/CSystemCallFilterTest.cc @@ -5,6 +5,7 @@ */ #include "CSystemCallFilterTest.h" +#include #include #include #include @@ -21,7 +22,6 @@ #include #include -#include #include #include @@ -180,7 +180,7 @@ void CSystemCallFilterTest::openPipeAndRead(const std::string& filename) { CNamedPipeWriter threadWriter{filename, TEST_SIZE}; CPPUNIT_ASSERT(threadWriter.start()); - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; ml::core::CNamedPipeFactory::TIStreamP strm{ ml::core::CNamedPipeFactory::openPipeStreamRead(filename, dummy)}; CPPUNIT_ASSERT(strm); @@ -209,7 +209,7 @@ void CSystemCallFilterTest::openPipeAndWrite(const std::string& filename) { CNamedPipeReader threadReader{filename}; CPPUNIT_ASSERT(threadReader.start()); - std::atomic_bool dummy{false}; + atomic_t::atomic_bool dummy{false}; ml::core::CNamedPipeFactory::TOStreamP strm{ ml::core::CNamedPipeFactory::openPipeStreamWrite(filename, dummy)}; CPPUNIT_ASSERT(strm); From 7a2b1029811365e8238b6e3c9da4a6f34fb72b46 Mon Sep 17 00:00:00 2001 From: David Roberts Date: Thu, 18 Jun 2020 09:33:20 +0100 Subject: [PATCH 5/5] More Visual Studio 2013 problems --- lib/core/unittest/CNamedPipeFactoryTest.cc | 1 + lib/seccomp/Makefile | 1 + lib/seccomp/unittest/CSystemCallFilterTest.cc | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/core/unittest/CNamedPipeFactoryTest.cc b/lib/core/unittest/CNamedPipeFactoryTest.cc index 358de70cf0..71d461ce4f 100644 --- a/lib/core/unittest/CNamedPipeFactoryTest.cc +++ b/lib/core/unittest/CNamedPipeFactoryTest.cc @@ -14,6 +14,7 @@ #include +#include #include #ifndef Windows diff --git a/lib/seccomp/Makefile b/lib/seccomp/Makefile index b84a1edabe..d4b256ff6f 100644 --- a/lib/seccomp/Makefile +++ b/lib/seccomp/Makefile @@ -7,6 +7,7 @@ include $(CPP_SRC_HOME)/mk/defines.mk TARGET=$(OBJS_DIR)/libMlSeccomp$(STATIC_LIB_EXT) +USE_BOOST=1 all: build diff --git a/lib/seccomp/unittest/CSystemCallFilterTest.cc b/lib/seccomp/unittest/CSystemCallFilterTest.cc index 146be62ad5..ecd8964860 100644 --- a/lib/seccomp/unittest/CSystemCallFilterTest.cc +++ b/lib/seccomp/unittest/CSystemCallFilterTest.cc @@ -22,6 +22,7 @@ #include #include +#include #include #include