Discussion:
C++ exceptions are broken.
(too old to reply)
Mr Flibble
2016-03-08 12:31:12 UTC
Permalink
C++ exceptions are broken.

As it currently stands a more serious std::logic_error exception can be
downgraded into a less serious std::runtime_error exception if an
exception is thrown whilst evaluating the throw expression. This is a
nonsense.

Fix: if an exception is thrown whilst evaluating a throw expression then
std::terminate() is called.

/Flibble
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James K. Lowden
2016-03-09 14:25:52 UTC
Permalink
On Tue, 8 Mar 2016 06:31:12 CST
Post by Mr Flibble
As it currently stands a more serious std::logic_error exception can
be downgraded into a less serious std::runtime_error exception if an
exception is thrown whilst evaluating the throw expression.
Could you be more specific, please? logic_error is mentioned in my
copy of the C++ only in section 19.2.1 (per the index), and I don't
find any mention of "downgrading". I also don't understand how it
*could* happen, since the compiler generates exception-handling
instructions, and the language per se doesn't define logic_error.

Why do you say logic_error is "more serious" than runtime_error?
Semantically that's not true, insofar as seriousness is not defined
by the library. I guess you mean that -- assuming they're used as
intended -- a logic error could have been avoided by the programmer,
whereas a runtime error could not. Depending on the situation, though,
either one can leave the user high and dry.

--jkl
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Elias Salomão Helou Neto
2016-03-12 12:28:15 UTC
Permalink
Post by James K. Lowden
Why do you say logic_error is "more serious" than runtime_error?
Semantically that's not true, insofar as seriousness is not defined
by the library. I guess you mean that -- assuming they're used as
intended -- a logic error could have been avoided by the programmer,
whereas a runtime error could not. Depending on the situation, though,
either one can leave the user high and dry.
I agree that there is a semantic problem in saying that a logic error is
more serious. But still, having a logic_error exception turned into a
runtime_error exception seems wrong to me. However, it sounds like one
should actually not write throw expressions that can throw another
exception. This is what should be considered bad practice, IMO.

The solution? Write simple throw expressions that cannot themselves
throw an exception. Am I right, wrong, or is this impossible altogether?

Best,
Elias.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mr Flibble
2016-03-12 20:46:06 UTC
Permalink
Post by James K. Lowden
On Tue, 8 Mar 2016 06:31:12 CST
Post by Mr Flibble
As it currently stands a more serious std::logic_error exception can
be downgraded into a less serious std::runtime_error exception if an
exception is thrown whilst evaluating the throw expression.
Could you be more specific, please? logic_error is mentioned in my
copy of the C++ only in section 19.2.1 (per the index), and I don't
find any mention of "downgrading". I also don't understand how it
*could* happen, since the compiler generates exception-handling
instructions, and the language per se doesn't define logic_error.
Typically when constructing an exception derived from std::logic_error a

std::string object is created for the exception message which can cause
std::bad_alloc (a std::runtime_error exception) to be thrown replacing
the originally intended exception.
Post by James K. Lowden
Why do you say logic_error is "more serious" than runtime_error?
Semantically that's not true, insofar as seriousness is not defined
by the library. I guess you mean that -- assuming they're used as
intended -- a logic error could have been avoided by the programmer,
whereas a runtime error could not. Depending on the situation, though,
either one can leave the user high and dry.
In general std::logic_error is more serious then std::runtime_error
because you can often recover from a std::runtime_error but a
std::logic_error exception is often a sign that something is seriously
screwed and the only safe course of action is to terminate the process.
I treat std::logic_error based exceptions as fatal conditions because
of this.

/Flibble
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Hergen Lehmann
2016-03-12 22:50:46 UTC
Permalink
Post by Mr Flibble
In general std::logic_error is more serious then std::runtime_error
because you can often recover from a std::runtime_error but a
std::logic_error exception is often a sign that something is seriously
screwed and the only safe course of action is to terminate the
process.

I don't see any basis for that assumption.

std::logic_error includes stuff like std::domain_error (which is not
even used by the STL) or std::invalid_argument, which might be some
completely harmless rejection of input data.
On the other hand, std::runtime_error includes std::system_error, which
might be quite hazardous depending on which system operation did fail.

Hergen
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James K. Lowden
2016-03-13 21:55:36 UTC
Permalink
This post might be inappropriate. Click to display it.
Gareth Owen
2016-03-15 14:45:17 UTC
Permalink
Post by James K. Lowden
Oh, so you mean that the programmer may do something in handling the
exception to convert logic_error to runtime_error. Sure.
No, the problem is

throw std::logic_error("I've made a terrible mistake");

calls the constructor

std::logic_error(const std::string&);

which has to construct a string, which might throw std::bad_alloc
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Bo Persson
2016-03-15 18:22:07 UTC
Permalink
Post by Gareth Owen
Post by James K. Lowden
Oh, so you mean that the programmer may do something in handling the
exception to convert logic_error to runtime_error. Sure.
No, the problem is
throw std::logic_error("I've made a terrible mistake");
calls the constructor
std::logic_error(const std::string&);
which has to construct a string, which might throw std::bad_alloc
There is also a constructor

explicit logic_error(const char*);

which doesn't have to call a string constructor.



Bo Persson
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Alf P. Steinbach
2016-03-17 12:43:54 UTC
Permalink
Post by Bo Persson
There is also a constructor
explicit logic_error(const char*);
which doesn't have to call a string constructor.
Oh, it has to allocate memory dynamically for the string if it exceeds
some buffer size, because there is no requirement that the actual
argument points to a string that will outlive the exception object.

Most probably any particular implementation delegates the dynamic
allocation job to `std::string`.

However, considering that `what` is virtual function that produces a
`char const*`, it's not difficult at all to create a derived exception
class that doesn't do dynamic allocation.


Cheers!,

- Alf
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Paavo Helde
2016-03-17 12:43:44 UTC
Permalink
Post by Bo Persson
Post by Gareth Owen
Post by James K. Lowden
Oh, so you mean that the programmer may do something in handling the
exception to convert logic_error to runtime_error. Sure.
No, the problem is
throw std::logic_error("I've made a terrible mistake");
calls the constructor
std::logic_error(const std::string&);
which has to construct a string, which might throw std::bad_alloc
There is also a constructor
explicit logic_error(const char*);
which doesn't have to call a string constructor.
The const char* argument is not guaranteed to be a static string so it
still needs to be copied over, allocating an arbitrarily large amount of
memory.

The standard also says:

logic_error(const char* what_arg);
4 Effects: Constructs an object of class logic_error.
5 Postcondition: strcmp(what(), what_arg) == 0.

The post-condition makes it illegal to ignore or truncate the argument
string, thus leaving an exception as the only conforming way to cope
with memory exhaustion.

It is interesting to note that MSVC implementation for example appears
to be not standard conforming and just ignores the argument if the
memory allocation fails.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Gareth Owen
2016-03-15 14:44:44 UTC
Permalink
Post by Mr Flibble
std::string object is created for the exception message which can
cause std::bad_alloc (a std::runtime_error exception) to be thrown
replacing the originally intended exception.
std::bad_alloc is not a runtime_error (needing a string constructor
would be particularly idiotic for bad_alloc), but the point still holds.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Continue reading on narkive:
Loading...