How to catch I/O exception (exactly I/O, not std::exception) - c++

I tried the example program from here (with mingw-w64). The program crashed. So I edited it:
#include <iostream> // std::cerr
#include <fstream> // std::ifstream
int main()
{
std::ifstream file;
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
file.open("not_existing.txt");
while (!file.eof())
file.get();
file.close();
}
catch (std::ifstream::failure e) {
std::cerr << "Exception opening/reading/closing file\n";
}
catch (const std::exception& e) {
std::cerr << "should not reach this";
}
return 0;
}
Now it runs, but prints should not reach this, while I was expecting it to print Exception opening/reading/closing file.
Why is my expectation wrong?
EDIT:
since this seems to be an important point, here's the exact version om my compiler: mingw-w64 version "x86_64-6.2.0-posix-sjlj-rt_v5-rev1" , i.e. GCC version 6.2

This may be a MingW bug. I get the expected result using MacOS Clang 802.0.42. The expected output being:
Exception opening/reading/closing file
This might be a known regression: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66145

Related

throw statement is showing error when i don't use invalid_argument [duplicate]

I do a simple throw "TEST THROW" and it isn't caught in my catch (std::exception& e). Is it because I'm catching an std::exception& e? I mean, are only exception classes derived from std::exception caught? If not, am I doing something wrong or is it normal? By the way, none of the two catch blocks caught the throw exception.
int main()
{
try
{
throw "TEST THROW"; // TEST
Core core;
core.Init();
core.Load();
while (!core.requestCloseWindow)
{
core.HandleInput();
core.Update();
core.Draw();
}
core.Unload();
core.window->close();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
try
{
time_t rawTime;
struct tm* timeInfo;
char timeBuffer [80];
time(&rawTime);
timeInfo = localtime(&rawTime);
strftime(timeBuffer, 80, "%F %T", timeInfo);
puts(timeBuffer);
std::ofstream ofs; // Pas besoin de close, car le destructeur le fait.
ofs.exceptions(std::ofstream::failbit | std::ofstream::badbit);
ofs.open("log.txt", std::ofstream::out | std::ofstream::app);
ofs << e.what() << std::endl;
}
catch (std::exception& e)
{
std::cerr << "An error occured while writing to a log file!" << std::endl;
}
}
return 0;
}
Another reason people may hit this issue, especially if they've been writing Java recently, is that they may be throwing a pointer to the exception.
/* WARNING WARNING THIS CODE IS WRONG DO NOT COPY */
try {
throw new std::runtime_error("catch me");
} catch (std::runtime_error &err) {
std::cerr << "exception caught and ignored: " << err.what() << std::end;
}
/* WARNING WARNING THIS CODE IS WRONG DO NOT COPY */
will not catch the std::runtime_error* you threw. It'll probably die with a call to std::terminate for the uncaught exception.
Don't allocate the exception with new, just throw the constructor by-value, e.g.
try {
/* note: no 'new' here */
throw std::runtime_error("catch me");
} catch (std::runtime_error &err) {
std::cerr << "exception caught and ignored: " << err.what() << std::end;
}
You're throwing a const char*. std::exception only catches std::exception and all derived classes of it. So in order to catch your throw, you should throw std::runtime_error("TEST THROW") instead. Or std::logic_error("TEST THROW"); whatever fits better. The derived classes of std::exception are listed here.
You can add a
catch (...)
block to get it.
This also may happen when you throw an exception of a an inherted type but the inhertence is private
Since this is not a MCVE (what is Core?), I can't address explicitly the problem, but you are surely missing to
#include <exception>
Actually, GCC compiles even without the inclusion, but exception won't be caught and you will end up with
terminate called after throwing an instance of 'std::exception'
what(): std::exception
./{program}: {PID} Aborted (core dumped)

Why don't exceptions work with gcc7 and -static-libgcc on OSX?

If I compile this simple program with gcc-7, -static-libstdc++, and -static-libgcc; then run on OSX
#include <exception>
#include <iostream>
int main() try {
throw std::runtime_error{"abc123"};
return 0;
} catch (const std::runtime_error& e) {
std::cout << e.what() << "\n";
return 0;
}
it fails with error code 134.
Why doesn't it print "abc123" as it does when compiled with the same options on linux?
Fixed(-ish) in GCC8; see update to PR86215 and the related PR80556.

catch an open exception

I have this code and just wondered why it's not throwing an exception (or in which case it should do).
From cplusplus.com :
If the function fails to open a file, the failbit state flag is set for the stream (which may throw ios_base::failure if that state flag was registered using member exceptions).
#include <fstream>
#include <exception>
#include <iostream>
int main() {
std::ofstream fs;
try {
fs.open("/non-existing-root-file");
} catch (const std::ios_base::failure& e) {
std::cout << e.what() << std::endl;
}
if (fs.is_open())
std::cout << "is open" << std::endl;
else
std::cout << "is not open" << std::endl;
return 0;
}
You did not follow the rabbit trail all of the way down
You need to tell it you want exceptions by using std::ios::exceptions. Without doing this, it indicates failure through the failbit state flag.
// ios::exceptions
#include <iostream> // std::cerr
#include <fstream> // std::ifstream
int main () {
std::ifstream file;
///next line tells the ifstream to throw on fail
file.exceptions ( std::ifstream::failbit | std::ifstream::badbit );
try {
file.open ("test.txt");
while (!file.eof()) file.get();
file.close();
}
catch (std::ifstream::failure e) {
std::cerr << "Exception opening/reading/closing file\n";
}
return 0;
}
You would need to register the failbit flag using std::ios::exceptions() for it to throw, which you haven't done.
I dont think fstream throws an exception on failure to open file. you have to check that with bool fstream::is_open().

How to get error message when ifstream open fails

ifstream f;
f.open(fileName);
if ( f.fail() )
{
// I need error message here, like "File not found" etc. -
// the reason of the failure
}
How to get error message as string?
Every system call that fails update the errno value.
Thus, you can have more information about what happens when a ifstream open fails by using something like :
cerr << "Error: " << strerror(errno);
However, since every system call updates the global errno value, you may have issues in a multithreaded application, if another system call triggers an error between the execution of the f.open and use of errno.
On system with POSIX standard:
errno is thread-local; setting it in one thread does not affect its
value in any other thread.
Edit (thanks to Arne Mertz and other people in the comments):
e.what() seemed at first to be a more C++-idiomatically correct way of implementing this, however the string returned by this function is implementation-dependant and (at least in G++'s libstdc++) this string has no useful information about the reason behind the error...
You could try letting the stream throw an exception on failure:
std::ifstream f;
//prepare f to throw if failbit gets set
std::ios_base::iostate exceptionMask = f.exceptions() | std::ios::failbit;
f.exceptions(exceptionMask);
try {
f.open(fileName);
}
catch (std::ios_base::failure& e) {
std::cerr << e.what() << '\n';
}
e.what(), however, does not seem to be very helpful:
I tried it on Win7, Embarcadero RAD Studio 2010 where it gives "ios_base::failbit set" whereas strerror(errno) gives "No such file or directory."
On Ubuntu 13.04, gcc 4.7.3 the exception says "basic_ios::clear" (thanks to arne)
If e.what() does not work for you (I don't know what it will tell you about the error, since that's not standardized), try using std::make_error_condition (C++11 only):
catch (std::ios_base::failure& e) {
if ( e.code() == std::make_error_condition(std::io_errc::stream) )
std::cerr << "Stream error!\n";
else
std::cerr << "Unknown failure opening file.\n";
}
Following on #Arne Mertz's answer, as of C++11 std::ios_base::failure inherits from system_error (see http://www.cplusplus.com/reference/ios/ios_base/failure/), which contains both the error code and message that strerror(errno) would return.
std::ifstream f;
// Set exceptions to be thrown on failure
f.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
f.open(fileName);
} catch (std::system_error& e) {
std::cerr << e.code().message() << std::endl;
}
This prints No such file or directory. if fileName doesn't exist.
You can also throw a std::system_error as shown in the test code below. This method seems to produce more readable output than f.exception(...).
#include <exception> // <-- requires this
#include <fstream>
#include <iostream>
void process(const std::string& fileName) {
std::ifstream f;
f.open(fileName);
// after open, check f and throw std::system_error with the errno
if (!f)
throw std::system_error(errno, std::system_category(), "failed to open "+fileName);
std::clog << "opened " << fileName << std::endl;
}
int main(int argc, char* argv[]) {
try {
process(argv[1]);
} catch (const std::system_error& e) {
std::clog << e.what() << " (" << e.code() << ")" << std::endl;
}
return 0;
}
Example output (Ubuntu w/clang):
$ ./test /root/.profile
failed to open /root/.profile: Permission denied (system:13)
$ ./test missing.txt
failed to open missing.txt: No such file or directory (system:2)
$ ./test ./test
opened ./test
$ ./test $(printf '%0999x')
failed to open 000...000: File name too long (system:36)
The std::system_error example above is slightly incorrect. std::system_category() will map the error codes from system's native error code facility. For *nix, this is errno. For Win32, it is GetLastError(). ie, on Windows, the above example will print
failed to open C:\path\to\forbidden: The data is invalid
because EACCES is 13 which is the Win32 error code ERROR_INVALID_DATA
To fix it, either use the system's native error code facility, eg on Win32
throw new std::system_error(GetLastError(), std::system_category(), "failed to open"+ filename);
Or use errno and std::generic_category(), eg
throw new std::system_error(errno, std::generic_category(), "failed to open"+ filename);

Catching all unhandled C++ exceptions?

Is there some way to catch exceptions which are otherwise unhandled (including those thrown outside the catch block)?
I'm not really concerned about all the normal cleanup stuff done with exceptions, just that I can catch it, write it to log/notify the user and exit the program, since the exceptions in these casese are generaly fatal, unrecoverable errors.
something like:
global_catch()
{
MessageBox(NULL,L"Fatal Error", L"A fatal error has occured. Sorry for any inconvience", MB_ICONERROR);
exit(-1);
}
global_catch(Exception *except)
{
MessageBox(NULL,L"Fatal Error", except->ToString(), MB_ICONERROR);
exit(-1);
}
This can be used to catch unexpected exceptions.
catch (...)
{
std::cout << "OMG! an unexpected exception has been caught" << std::endl;
}
Without a try catch block, I don't think you can catch exceptions, so structure your program so the exception thowing code is under the control of a try/catch.
Check out std::set_terminate()
Edit: Here's a full-fledged example with exception matching:
#include <iostream>
#include <exception>
#include <stdexcept>
struct FooException: std::runtime_error {
FooException(const std::string& what): std::runtime_error(what) {}
};
int main() {
std::set_terminate([]() {
try {
std::rethrow_exception(std::current_exception());
} catch (const FooException& e) {
std::cerr << "Unhandled FooException: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Unhandled exception: " << e.what() << std::endl;
} catch (...) {
std::cerr << "Unhandled exception of unknown type" << std::endl;
}
std::abort();
});
throw FooException("Bad things have happened.");
// throw std::runtime_error("Bad things have happened.");
// throw 9001;
}
You can use SetUnhandledExceptionFilter on Windows, which will catch all unhandled SEH exceptions.
Generally this will be sufficient for all your problems as IIRC all the C++ exceptions are implemented as SEH.
Without any catch block, you won't catch any exceptions. You can have a catch(...) block in your main() (and its equivalent in each additional thread). In this catch block you can recover the exception details and you can do something about them, like logging and exit.
However, there are also downside about a general catch(...) block: the system finds that the exception has been handled by you, so it does not give any more help. On Unix/Linux, this help would constitute creating a CORE file, which you could load into the debugger and see the original location of the unexcepted exception. If you are handling it with catch(...) this information would be already lost.
On Windows, there are no CORE files, so I would suggest to have the catch(...) block. From that block, you would typically call a function to resurrect the actual exception:
std::string ResurrectException()
try {
throw;
} catch (const std::exception& e) {
return e.what();
} catch (your_custom_exception_type& e) {
return e.ToString();
} catch(...) {
return "Ünknown exception!";
}
}
int main() {
try {
// your code here
} catch(...) {
std::string message = ResurrectException();
std::cerr << "Fatal exception: " << message << "\n";
}
}
Update: This covers c++98 only.
From More Effective C++ by Meyers (pg 76), you could define a function that gets called when a function generates an exception that is not defined by its exception specification.
void convertUnexpected()
{
// You could redefine the exception here into a known exception
// throw UnexpectedException();
// ... or I suppose you could log an error and exit.
}
In your application register the function:
std::set_unexpected( convertUnexpected );
Your function convertUnexpected() will get called if a function generates an exception that is not defined by its exception specification... which means this only works if you are using exception specifications. ;(
Provided that C++11 is available, this approach may be used (see example from: http://en.cppreference.com/w/cpp/error/rethrow_exception):
#include <iostream>
#include <exception>
void onterminate() {
try {
auto unknown = std::current_exception();
if (unknown) {
std::rethrow_exception(unknown);
} else {
std::cerr << "normal termination" << std::endl;
}
} catch (const std::exception& e) { // for proper `std::` exceptions
std::cerr << "unexpected exception: " << e.what() << std::endl;
} catch (...) { // last resort for things like `throw 1;`
std::cerr << "unknown exception" << std::endl;
}
}
int main () {
std::set_terminate(onterminate); // set custom terminate handler
// code which may throw...
return 0;
}
This approach also allows you to customize console output for unhandled exceptions: to have something like this
unexpected exception: wrong input parameters
Aborted
instead of this:
terminate called after throwing an instance of 'std::logic_error'
what(): wrong input parameters
Aborted
This is what I always do in main()
int main()
{
try
{
// Do Work
}
catch(std::exception const& e)
{
Log(e.what());
// If you are feeling mad (not in main) you could rethrow!
}
catch(...)
{
Log("UNKNOWN EXCEPTION");
// If you are feeling mad (not in main) you could rethrow!
}
}
Use catch (...) in all of your exception barriers (not just the main thread). I suggest that you always rethrow (...) and redirect standard output/error to the log file, as you can't do meaningful RTTI on (...). OTOH, compiler like GCC will output a fairly detailed description about the unhandled exception: the type, the value of what() etc.