Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++ exceptions are broken.

178 views
Skip to first unread message

Mr Flibble

unread,
Mar 7, 2016, 5:07:34 PM3/7/16
to
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

Öö Tiib

unread,
Mar 8, 2016, 2:29:28 AM3/8/16
to
On Tuesday, 8 March 2016 00:07:34 UTC+2, Mr Flibble wrote:
> C++ exceptions are broken.

These are not broken. Also calling virtual functions from
constructor or destructor are not broken. Those may behave in not
intuitive way for everybody but that does not make them 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.

Code of some people often does something that other people consider nonsense. Destructor is implicitly 'noexcept(true)' unless destructor of any bases
or members is 'noexcept(false)'. So a throw from 'noexcept(true)'
destructor is transformed into call of 'std::terminate()' because there are
no mechanism of stack unwinding.

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

That 'std::teminate()' is more typically called because of throwing from
'noexcept(true)' functions by mine experiences.

see.my....@gmail.com

unread,
Mar 8, 2016, 2:42:59 AM3/8/16
to

> 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: don't create throw expressions that are so complex that they might throw on their own.

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

Nonsense. There is no difference between this:

throw VERY-COMPLEX-EXPRESSION;

and this:

const my_exception_class & ex = VERY-COMPLEX-EXPRESSION;
throw ex;

In that second case (which can be further decoupled in space and time, if needed for the sake of argument) there is no way for the compiler to tell that it is the exception expression that is being evaluated and that it deserves special attention.

Just to feed the discussion - the exception system might be based on something different than regular objects. For example in Ada exceptions are separate entities, which are declared, but not evaluated at run-time, and they are not "thrown" in the sense of passing some values around, but rather "signaled". Of course, it is still possible to mess the program up with exceptions popping out from destructors during stack unwinding. Then you can think about exception chaining (like in Java) as a possible solution to both problems above, etc., but then again you will have to face other problems like physical lack of memory for ever-growing exception objects, and so on. There is no universally good solution for this, with the exception (pun intended) of perhaps writing programs without exceptions at all. There is a reason why they are forbidden in some of the safety critical coding standards.

--
Maciej Sobczak * http://www.inspirel.com

Juha Nieminen

unread,
Mar 8, 2016, 4:20:09 AM3/8/16
to
Mr Flibble <flibbleREM...@i42.co.uk> wrote:
> Fix: if an exception is thrown whilst evaluating a throw expression then
> std::terminate() is called.

You need to be able to re-throw exceptions.

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Mr Flibble

unread,
Mar 8, 2016, 7:40:14 AM3/8/16
to

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! ]

woodb...@gmail.com

unread,
Mar 8, 2016, 10:11:08 AM3/8/16
to
On Tuesday, March 8, 2016 at 6:40:14 AM UTC-6, Mr Flibble wrote:
> 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


Maybe you should give asserts another shot.

Brian
Ebenezer Enterprises
http://webEbenezer.net

Scott Lurndal

unread,
Mar 8, 2016, 12:26:43 PM3/8/16
to
woodb...@gmail.com writes:
>On Tuesday, March 8, 2016 at 6:40:14 AM UTC-6, Mr Flibble wrote:
>> 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
>
>
>Maybe you should give asserts another shot.
>

The use of assert is forbidden in my current project as
far too draconian. Instead, we'll attempt to recover and
if not possible, will log a message and disable or reset the
subsystem affected and continue the simulation.

James K. Lowden

unread,
Mar 9, 2016, 9:30:21 AM3/9/16
to

On Tue, 8 Mar 2016 06:31:12 CST
Mr Flibble <flibbleREM...@i42.co.uk> wrote:

> 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

Mr Flibble

unread,
Mar 12, 2016, 2:12:00 PM3/12/16
to
On 09/03/2016 14:25, James K. Lowden wrote:
>
> On Tue, 8 Mar 2016 06:31:12 CST
> Mr Flibble <flibbleREM...@i42.co.uk> wrote:
>
>> 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.

>
> 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

Mr Flibble

unread,
Mar 12, 2016, 4:00:18 PM3/12/16
to

On 09/03/2016 14:25, James K. Lowden wrote:
>
> On Tue, 8 Mar 2016 06:31:12 CST
> Mr Flibble <flibbleREM...@i42.co.uk> wrote:
>
>> 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.

>
> 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


Hergen Lehmann

unread,
Mar 12, 2016, 6:00:19 PM3/12/16
to

Am 12.03.2016 um 21:46 schrieb 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

Öö Tiib

unread,
Mar 12, 2016, 6:05:43 PM3/12/16
to
On Saturday, 12 March 2016 21:12:00 UTC+2, Mr Flibble wrote:

Leigh, can you please check why your posts appear twice in comp.lang.c++?

> On 09/03/2016 14:25, James K. Lowden wrote:
> >
> > On Tue, 8 Mar 2016 06:31:12 CST
> > Mr Flibble <flibbleREM...@i42.co.uk> wrote:
> >
> >> 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.

That is indeed so, but 'bad_alloc' is also typically unrecoverable
fatal and on border of 'logic_error'. It can be that platform was picked
that is incapable of handling the task under hand or input was accepted
that is outside of capabilities of platform or software is leaking
resources so it will run out sooner or later. The reason why it is
'runtime_error' is perhaps because the system might be ran out of
resources because of some other software did exhaust the available
memory. Also that situation is not recoverable by software on its own.

>
> >
> > 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.

Yes but if you threat 'bad_alloc' as 'logic_error' too then no harm done?

James K. Lowden

unread,
Mar 13, 2016, 5:00:10 PM3/13/16
to

On Sat, 12 Mar 2016 14:46:06 CST
Mr Flibble <flibbleREM...@i42.co.uk> wrote:

> > 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.

Oh, so you mean that the programmer may do something in handling the
exception to convert logic_error to runtime_error. Sure.

The programmer also has control over that. If it's important to pass
logic_error up the stack unmolested, do not allocate any objects in the
handler, or wrap that logic in its own try block. I've heard that in
some shops it's standard practice to use only static strings in
handlers to avoid the situation you describe.

>From my point of view, if std::string triggers bad_alloc, you're hip
deep in alligators because your heap is corrupted. Likely is the
logic_error is itself spurious, a knock-on effect of your pointers
spending their spring break in Fort Lauderdale. So, yeah, grap
__FILE__ and __LINE__, and head for the exit as soon as possible.

--jkl

Gareth Owen

unread,
Mar 15, 2016, 9:50:25 AM3/15/16
to

Mr Flibble <flibbleREM...@i42.co.uk> writes:

> 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.

Gareth Owen

unread,
Mar 15, 2016, 9:50:25 AM3/15/16
to

"James K. Lowden" <jklo...@speakeasy.net> writes:

> 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

Bo Persson

unread,
Mar 15, 2016, 1:30:17 PM3/15/16
to

On 2016-03-15 15:45, Gareth Owen wrote:
>
> "James K. Lowden" <jklo...@speakeasy.net> writes:
>
>> 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

woodb...@gmail.com

unread,
Mar 15, 2016, 2:28:39 PM3/15/16
to
On Tuesday, March 15, 2016 at 12:30:17 PM UTC-5, Bo Persson wrote:
> On 2016-03-15 15:45, Gareth Owen wrote:
> >
> > 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
>

What's the point of std::logic_error? Asserting has
already been defended and I agree with those who say to
use asserts. Recent threads, including this one, have
pointed out dangers and snares associated with
std::logic_error. IMO C++ would be better off without it.

Alf P. Steinbach

unread,
Mar 17, 2016, 7:50:14 AM3/17/16
to

On 15.03.2016 19:22, Bo Persson wrote:
>
> 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

Paavo Helde

unread,
Mar 17, 2016, 7:50:14 AM3/17/16
to

On 15.03.2016 20:22, Bo Persson wrote:
>
> On 2016-03-15 15:45, Gareth Owen wrote:
>>
>> "James K. Lowden" <jklo...@speakeasy.net> writes:
>>
>>> 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.
0 new messages