Provide workaround for GCC Bug 66145

This commit is contained in:
Martchus 2016-06-14 22:53:19 +02:00
parent 79ce6e9aa6
commit 980794066b
10 changed files with 84 additions and 14 deletions

View File

@ -23,6 +23,7 @@ set(HEADER_FILES
io/copy.h io/copy.h
io/inifile.h io/inifile.h
io/path.h io/path.h
io/catchiofailure.h
math/math.h math/math.h
misc/memory.h misc/memory.h
misc/random.h misc/random.h
@ -45,6 +46,7 @@ set(SRC_FILES
io/bitreader.cpp io/bitreader.cpp
io/inifile.cpp io/inifile.cpp
io/path.cpp io/path.cpp
io/catchiofailure.cpp
math/math.cpp math/math.cpp
misc/random.cpp misc/random.cpp
tests/testutils.cpp tests/testutils.cpp

View File

@ -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. PKGBUILD files to build for Windows using the Mingw-w64 compiler are also included.
### Notes ### Notes
* Because of [GCC Bug 66145](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66145) usage of the new libstdc++ ABI * There is a workaround for [GCC Bug 66145](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66145) provided
is currently disabled. Linking against cppunit built using new libstdc++ ABI isn't possible. in io/catchiofailure.h.
## TODO ## TODO
- remove unused features - remove unused features

View File

@ -43,8 +43,11 @@ configure_file(
include_directories("${CMAKE_CURRENT_BINARY_DIR}") include_directories("${CMAKE_CURRENT_BINARY_DIR}")
# disable new ABI (can't catch ios_base::failure with new ABI) # disable new ABI (can't catch ios_base::failure with new ABI)
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) set(FORCE_OLD_ABI "no" CACHE STRING "specifies whether usage of old ABI should be forced")
message(STATUS "Forcing usage of old CXX11 ABI to be able to catch std::ios_base::failure.") 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 # enable debug-only code when doing a debug build
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_BUILD_TYPE STREQUAL "Debug")

View File

@ -137,7 +137,6 @@ string BinaryReader::readString(size_t length)
string BinaryReader::readTerminatedString(byte termination) string BinaryReader::readTerminatedString(byte termination)
{ {
stringstream ss(ios_base::in | ios_base::out | ios_base::binary); 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); ss.exceptions(ios_base::badbit | ios_base::failbit);
m_stream->get(*ss.rdbuf(), termination); // delim byte is not extracted from the stream 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 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) string BinaryReader::readMultibyteTerminatedStringBE(uint16 termination)
{ {
stringstream ss(ios_base::in | ios_base::out | ios_base::binary); 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); ss.exceptions(ios_base::badbit | ios_base::failbit);
char *delimChars = m_buffer, *buff = m_buffer + 2; char *delimChars = m_buffer, *buff = m_buffer + 2;
ConversionUtilities::BE::getBytes(termination, delimChars); ConversionUtilities::BE::getBytes(termination, delimChars);
@ -196,7 +194,6 @@ string BinaryReader::readMultibyteTerminatedStringBE(uint16 termination)
string BinaryReader::readMultibyteTerminatedStringLE(uint16 termination) string BinaryReader::readMultibyteTerminatedStringLE(uint16 termination)
{ {
stringstream ss(ios_base::in | ios_base::out | ios_base::binary); 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); ss.exceptions(ios_base::badbit | ios_base::failbit);
char *delimChars = m_buffer, *buff = m_buffer + 2; char *delimChars = m_buffer, *buff = m_buffer + 2;
ConversionUtilities::LE::getBytes(termination, delimChars); ConversionUtilities::LE::getBytes(termination, delimChars);

View File

@ -1,4 +1,5 @@
#include "./bitreader.h" #include "./bitreader.h"
#include "./catchiofailure.h"
using namespace std; using namespace std;
@ -21,7 +22,7 @@ void BitReader::skipBits(std::size_t bitCount)
m_bitsAvail -= bitCount; m_bitsAvail -= bitCount;
} else { } else {
if((m_buffer += 1 + (bitCount -= m_bitsAvail) / 8) >= m_end) { 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); m_bitsAvail = 8 - (bitCount % 8);
} }

36
io/catchiofailure.cpp Normal file
View File

@ -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 <ios>
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);
}
}

15
io/catchiofailure.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef IOUTILITIES_CATCHIOFAILURE_H
#define IOUTILITIES_CATCHIOFAILURE_H
#include "../application/global.h"
#include <string>
namespace IoUtilities {
LIB_EXPORT const char *catchIoFailure();
LIB_EXPORT void throwIoFailure(const char *what);
}
#endif // IOUTILITIES_CATCHIOFAILURE_H

View File

@ -1,4 +1,5 @@
#include "./inifile.h" #include "./inifile.h"
#include "./catchiofailure.h"
#include <iostream> #include <iostream>
@ -135,13 +136,14 @@ void IniFile::parse(std::istream &inputStream)
break; break;
} }
} }
} catch (const ios_base::failure &) { } catch(...) {
const char *what = catchIoFailure();
if(inputStream.eof()) { if(inputStream.eof()) {
// we just reached the end of the file // we just reached the end of the file
// don't forget to save the last key/value pair // don't forget to save the last key/value pair
finishKeyValue(); finishKeyValue();
} else { } else {
throw; throwIoFailure(what);
} }
} }
} }

View File

@ -6,6 +6,7 @@
#include "../io/path.h" #include "../io/path.h"
#include "../io/inifile.h" #include "../io/inifile.h"
#include "../io/copy.h" #include "../io/copy.h"
#include "../io/catchiofailure.h"
#include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestFixture.h> #include <cppunit/TestFixture.h>
@ -57,17 +58,27 @@ void IoTests::tearDown()
/*! /*!
* \brief Tests for GCC Bug 66145. * \brief Tests for GCC Bug 66145.
* \sa https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66145 * \sa https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66145
* \remarks Using workaround now; hence testing workaround instead.
*/ */
void IoTests::testFailure() void IoTests::testFailure()
{ {
fstream stream; //fstream stream;
stream.exceptions(ios_base::failbit | ios_base::badbit); //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); //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 // check other exceptions used by my applications, too
vector<int> testVec; vector<int> testVec;
map<string, string> testMap; map<string, string> testMap;
CPPUNIT_ASSERT_THROW(testVec.at(1), out_of_range); CPPUNIT_ASSERT_THROW(testVec.at(1), out_of_range);
CPPUNIT_ASSERT_THROW(testMap.at("test"), 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();
}
} }
/*! /*!

View File

@ -2,6 +2,7 @@
#include "../application/failure.h" #include "../application/failure.h"
#include "../conversion/stringconversion.h" #include "../conversion/stringconversion.h"
#include "../io/catchiofailure.h"
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
@ -13,6 +14,7 @@
using namespace std; using namespace std;
using namespace ApplicationUtilities; using namespace ApplicationUtilities;
using namespace ConversionUtilities; using namespace ConversionUtilities;
using namespace IoUtilities;
/*! /*!
* \brief Contains classes and functions utilizing creating of test applications. * \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.open(path, ios_base::out | ios_base::binary | ios_base::trunc);
workingCopy << origFile.rdbuf(); workingCopy << origFile.rdbuf();
return path; return path;
} catch(const ios_base::failure &) { } catch(...) {
catchIoFailure();
cerr << "Unable to create working copy for \"" << name << "\": an IO error occured." << endl; cerr << "Unable to create working copy for \"" << name << "\": an IO error occured." << endl;
} }
return string(); return string();