diff --git a/CMakeLists.txt b/CMakeLists.txt index 49c3686..46a9712 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ set(HEADER_FILES io/copy.h io/inifile.h io/path.h + io/catchiofailure.h math/math.h misc/memory.h misc/random.h @@ -45,6 +46,7 @@ set(SRC_FILES io/bitreader.cpp io/inifile.cpp io/path.cpp + io/catchiofailure.cpp math/math.cpp misc/random.cpp tests/testutils.cpp diff --git a/README.md b/README.md index 89f52a2..f8826fd 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,8 @@ The repository [PKGBUILDs](https://github.com/Martchus/PKGBUILDs) contains files PKGBUILD files to build for Windows using the Mingw-w64 compiler are also included. ### Notes -* Because of [GCC Bug 66145](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66145) usage of the new libstdc++ ABI - is currently disabled. Linking against cppunit built using new libstdc++ ABI isn't possible. +* There is a workaround for [GCC Bug 66145](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66145) provided + in io/catchiofailure.h. ## TODO - remove unused features diff --git a/cmake/modules/BasicConfig.cmake b/cmake/modules/BasicConfig.cmake index ad62540..1ff6f5a 100644 --- a/cmake/modules/BasicConfig.cmake +++ b/cmake/modules/BasicConfig.cmake @@ -43,8 +43,11 @@ configure_file( include_directories("${CMAKE_CURRENT_BINARY_DIR}") # disable new ABI (can't catch ios_base::failure with new ABI) -add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) -message(STATUS "Forcing usage of old CXX11 ABI to be able to catch std::ios_base::failure.") +set(FORCE_OLD_ABI "no" CACHE STRING "specifies whether usage of old ABI should be forced") +if(${FORCE_OLD_ABI} STREQUAL "yes") + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) + message(STATUS "Forcing usage of old CXX11 ABI.") +endif() # enable debug-only code when doing a debug build if(CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/io/binaryreader.cpp b/io/binaryreader.cpp index 8eeb969..7079ca9 100644 --- a/io/binaryreader.cpp +++ b/io/binaryreader.cpp @@ -137,7 +137,6 @@ string BinaryReader::readString(size_t length) string BinaryReader::readTerminatedString(byte termination) { stringstream ss(ios_base::in | ios_base::out | ios_base::binary); - // thrown ios_base::failure when badbit or failbit is set ss.exceptions(ios_base::badbit | ios_base::failbit); m_stream->get(*ss.rdbuf(), termination); // delim byte is not extracted from the stream m_stream->seekg(1, ios_base::cur); // "extract" delim byte manually @@ -175,7 +174,6 @@ string BinaryReader::readTerminatedString(size_t maxBytesToRead, byte terminatio string BinaryReader::readMultibyteTerminatedStringBE(uint16 termination) { stringstream ss(ios_base::in | ios_base::out | ios_base::binary); - // thrown ios_base::failure when badbit or failbit is set ss.exceptions(ios_base::badbit | ios_base::failbit); char *delimChars = m_buffer, *buff = m_buffer + 2; ConversionUtilities::BE::getBytes(termination, delimChars); @@ -196,7 +194,6 @@ string BinaryReader::readMultibyteTerminatedStringBE(uint16 termination) string BinaryReader::readMultibyteTerminatedStringLE(uint16 termination) { stringstream ss(ios_base::in | ios_base::out | ios_base::binary); - // thrown ios_base::failure when badbit or failbit is set ss.exceptions(ios_base::badbit | ios_base::failbit); char *delimChars = m_buffer, *buff = m_buffer + 2; ConversionUtilities::LE::getBytes(termination, delimChars); diff --git a/io/bitreader.cpp b/io/bitreader.cpp index 8d38b22..1dc6031 100644 --- a/io/bitreader.cpp +++ b/io/bitreader.cpp @@ -1,4 +1,5 @@ #include "./bitreader.h" +#include "./catchiofailure.h" using namespace std; @@ -21,7 +22,7 @@ void BitReader::skipBits(std::size_t bitCount) m_bitsAvail -= bitCount; } else { if((m_buffer += 1 + (bitCount -= m_bitsAvail) / 8) >= m_end) { - throw ios_base::failure("end of buffer exceeded"); + throwIoFailure("end of buffer exceeded"); } m_bitsAvail = 8 - (bitCount % 8); } diff --git a/io/catchiofailure.cpp b/io/catchiofailure.cpp new file mode 100644 index 0000000..b7e593a --- /dev/null +++ b/io/catchiofailure.cpp @@ -0,0 +1,36 @@ +// ensure the old ABI is used +// TODO: add condition for GCC version if GCC Bug 66145 is fixed +#define _GLIBCXX_USE_CXX11_ABI 0 + +#include "./catchiofailure.h" + +#include + +using namespace std; + +namespace IoUtilities { + +/*! + * \brief Provides a workaround for GCC Bug 66145. + * \returns Returns the error message. + * \throws Throws the current exception if it is not std::ios_base::failure. + */ +const char *catchIoFailure() +{ + try { + throw; + } catch(const ios_base::failure &e) { + return e.what(); + } +} + +/*! + * \brief Throws a std::ios_base::failure with the specified message. + */ +void throwIoFailure(const char *what) +{ + throw ios_base::failure(what); +} + +} + diff --git a/io/catchiofailure.h b/io/catchiofailure.h new file mode 100644 index 0000000..e2f2522 --- /dev/null +++ b/io/catchiofailure.h @@ -0,0 +1,15 @@ +#ifndef IOUTILITIES_CATCHIOFAILURE_H +#define IOUTILITIES_CATCHIOFAILURE_H + +#include "../application/global.h" + +#include + +namespace IoUtilities { + +LIB_EXPORT const char *catchIoFailure(); +LIB_EXPORT void throwIoFailure(const char *what); + +} + +#endif // IOUTILITIES_CATCHIOFAILURE_H diff --git a/io/inifile.cpp b/io/inifile.cpp index cc2972f..6c6cfab 100644 --- a/io/inifile.cpp +++ b/io/inifile.cpp @@ -1,4 +1,5 @@ #include "./inifile.h" +#include "./catchiofailure.h" #include @@ -135,13 +136,14 @@ void IniFile::parse(std::istream &inputStream) break; } } - } catch (const ios_base::failure &) { + } catch(...) { + const char *what = catchIoFailure(); if(inputStream.eof()) { // we just reached the end of the file // don't forget to save the last key/value pair finishKeyValue(); } else { - throw; + throwIoFailure(what); } } } diff --git a/tests/iotests.cpp b/tests/iotests.cpp index f67c028..0ae240b 100644 --- a/tests/iotests.cpp +++ b/tests/iotests.cpp @@ -6,6 +6,7 @@ #include "../io/path.h" #include "../io/inifile.h" #include "../io/copy.h" +#include "../io/catchiofailure.h" #include #include @@ -57,17 +58,27 @@ void IoTests::tearDown() /*! * \brief Tests for GCC Bug 66145. * \sa https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66145 + * \remarks Using workaround now; hence testing workaround instead. */ void IoTests::testFailure() { - fstream stream; - stream.exceptions(ios_base::failbit | ios_base::badbit); - CPPUNIT_ASSERT_THROW(stream.open("path/to/file/which/does/not/exist", ios_base::in), ios_base::failure); + //fstream stream; + //stream.exceptions(ios_base::failbit | ios_base::badbit); + //CPPUNIT_ASSERT_THROW(stream.open("path/to/file/which/does/not/exist", ios_base::in), ios_base::failure); // check other exceptions used by my applications, too vector testVec; map testMap; CPPUNIT_ASSERT_THROW(testVec.at(1), out_of_range); CPPUNIT_ASSERT_THROW(testMap.at("test"), out_of_range); + + // check workaround + try { + fstream stream; + stream.exceptions(ios_base::failbit | ios_base::badbit); + stream.open("path/to/file/which/does/not/exist", ios_base::in); + } catch(...) { + catchIoFailure(); + } } /*! diff --git a/tests/testutils.cpp b/tests/testutils.cpp index 09f7d3a..34c4c43 100644 --- a/tests/testutils.cpp +++ b/tests/testutils.cpp @@ -2,6 +2,7 @@ #include "../application/failure.h" #include "../conversion/stringconversion.h" +#include "../io/catchiofailure.h" #include #include @@ -13,6 +14,7 @@ using namespace std; using namespace ApplicationUtilities; using namespace ConversionUtilities; +using namespace IoUtilities; /*! * \brief Contains classes and functions utilizing creating of test applications. @@ -193,7 +195,8 @@ string TestApplication::workingCopyPath(const string &name) const workingCopy.open(path, ios_base::out | ios_base::binary | ios_base::trunc); workingCopy << origFile.rdbuf(); return path; - } catch(const ios_base::failure &) { + } catch(...) { + catchIoFailure(); cerr << "Unable to create working copy for \"" << name << "\": an IO error occured." << endl; } return string();