2015-07-28

VS 2015 projects: "One or more errors occurred"

For the most part, I find that Visual Studio 2015 is awesome. However, it did ship with kinks that need to be worked out. Not least, it has crashed on me from time to time, while working on a large solution.

I recently experienced a problem where I couldn't open Visual C++ projects (.vcxproj) after I copied them to another location. When trying to open the projects, VS 2015 would give me nothing more than this "extremely useful" error:


That is some talent, right there. That must have taken a lot of work to get this right.

After trying various things, and having researched this without success for a few hours, I finally got the idea to try opening the projects in Visual Studio 2013, instead.

Behold: VS 2013 actually displayed a useful error, which informed me that my projects had Import dependencies that I forgot to move.

So, yeah. If VS 2015 helpfully tells you that "one or more errors occurred" — try VS 2013.

2015-07-26

Algorithm for selective archival or aggregation of records

Given the absurdity of the US patent system, it comes to mind that I should publish all technical ideas, no matter how inane, when I think of them — simply to provide a prior art reference, in case anyone claims that idea in a future patent.

The ideas I publish are arrived at independently, and based on publicly available information. This does not mean that existing and currently "valid" patents don't exist that cover parts of my ideas. It does, however, mean that such patents are obvious, and that the patent system is legalized enabling of extortion.

Without further ado, here's an idea for how to archive old log files to:
  • maintain required storage under a manageable threshold;
  • store the latest data, as well as older data in the event of undetected corruption;
  • avoid predictability to an attacker who might rely on a particular pattern of deletion.
We assume that log files are being archived in regular periods. This period may be an hour, a day, a week, or whatever works for an application.

We will store the log files in ranks, such that rank 0 are the most recent log files, and they get bumped to a higher rank as each rank fills. We allow for an unlimited number of ranks.

We define a maximum number of log files per rank. We call this M, and this number shall be 3 or more. It could be, for example, 4.

We determine the proportion of log files that we will keep each time as we move log files up the ranks. We call this number K, and it is a fraction between 0 and 1. A natural choice of K would be 1/2 or 1/3.

Each rank will start empty, and will with time become populated with log files.

When generated, every log file is first added to rank 0. Then, for each rank, starting with rank 0:
  • We test if the number of log files in that rank has reached M.
  • If it has:
    • We determine a subset S of log files in this rank that contains K*M of the oldest log files. If K is a fraction 1/N, e.g. 1/2, it would be natural to round the number of log files in the subset down to a multiple of N. For example: if K=0.5, S might contain 2 log files.
    • To avoid predictability of which log files are kept, we randomly discard a K proportion of log files in subset S. For example, if K = 1/2, we randomly discard one of the two log files. If predictability is desired, we discard instead based on a predetermined rule. For example, we could discard every other log file.
    • We graduate the log files in S that have not been discarded to the next rank. By this, I mean that we remove them from the current rank, and add them to the next.
We repeat this process with each rank, until we reach one that is empty.

This process keeps around the most recent log files; keeps around the older ones, going all the way back to origin; randomizes which log files are discarded; and uses O(log(T)) storage.

This process works not only for log files, but for any other kind of historical data storage. Instead of discarding information when graduating records from each rank, information can also be aggregated, while reducing the number of records. For example, when selecting the subset of records S that will be graduated to the next rank, instead of deleting a K proportion of records, all the records in S could be aggregated into a single record, which is then propagated to the next rank.

This would allow storage of information such as statistics and totals that is more granular for recent information, and more sparse for older information - yet does not lose information about overall totals.

A natural extension of the above principles is to define ranks to match natural periods of time. For example, rank 0 could be days, rank 1 could be weeks, rank 2 could be months, rank 3 could be years. The maximum number of records per rank, M; and the proportion of records kept between ranks, K; would then be rank-dependent.

Exceptions in destructors and Visual Studio 2015

If you're migrating code to Visual Studio 2015, you may have run into the following warning:
warning C4297: 'A::~A': function assumed not to throw an exception but does
note: destructor or deallocator has a (possibly implicit)
    non-throwing exception specification
You may not have seen this warning with GCC or Clang, so you may think VS 2015 is just bothering you. Wrong! GCC should be warning you even more so than Visual Studio (I'll explain why), but it does not.

You may also think that throwing an exception from a destructor in C++ is inherently undefined behavior. Wrong! Throwing an exception from a destructor in C++ is extremely well defined.

In C++03, throwing an exception from a destructor works as follows:
  • If there is no exception in flight, it means the destructor is being called through forward progress. In this case an exception in the destructor causes the beginning of unwinding — backward progress — just as if the exception was thrown anywhere else. The object whose destructor threw continues to be orderly destroyed, all the subobject destructors are still called, and operator delete is still called if the object's destruction was triggered by the delete keyword.
  • If there is an exception in flight, a destructor can still throw. However, an exception thrown from a destructor cannot meet with the exception in flight. It can still pass out of a destructor and be caught by another destructor if the throwing destructor was called recursively. However, C++ does not support exception aggregation. If the two exceptions meet, such that they would have to be joined to unwind together, the program is instead terminated abnormally.
In C++11 and later:
  • Everything exactly the same as above, except that destructors now have an implicit noexcept declaration, which is deduced to be the same as the destructor that the compiler would generate. This means that a user defined destructor is noexcept(true) by default, unless it is explicitly declared noexcept(false), and unless a base class or an aggregated object declares a destructor explicitly as noexcept(false).
  • If an exception leaves a noexcept(true) destructor, the C++ standard now requires std::terminate to be called. GCC does this; Clang does this; Visual Studio 2015 does this unless you enable optimization — which of course you will for production code. If you enable optimization, then against the spec, Visual Studio 2015 appears to ignore noexcept, and allows the exception to pass through.
Even though, like other compilers, GCC will call std::terminate if an exception leaves a noexcept destructor; and even though GCC will do so more consistently than VS 2015 — the behavior doesn't go away with -O2; GCC produces absolutely no warnings about this, even with -Wall.

In this case, therefore, we have Visual Studio 2015 producing a useful warning which exposes code incorrectness, which GCC does not produce.

Why the change in C++11?

Mostly, move semantics and containers. Exceptions from destructors in stack-allocated objects are usually not problematic, assuming the destructor checks std::uncaught_exception to see if it can throw. However, because C++ supports neither exception aggregation, nor a relocatable object property, a throwing move constructor or destructor make it next-to-impossible to provide a strong exception safety guarantee when e.g. resizing a vector.

It is possible that relocatable may be supported in the future, allowing objects to be moved via trivial memcpy instead of move construction + destruction. This would make it possible to safely resize a vector containing objects whose destructors may throw. But that leaves the question of what to do when multiple destructors throw when destroying or erasing the vector. That would require exception aggregation, which in turn would be ineffective without making developers aware; and at this time, that seems not to be feasible.

It seems likely we may get relocatable some time, but probably not multi-exceptions any time soon. Planning for the next 10 years, it's best to design your code to have noexcept destructors.

What to do?

If you have code that currently throws from destructors, plausible things to do are:
  1. Band-aid to restore C++03 behavior: declare destructors noexcept(false). Not only those that trigger the warning, but also those that may call throwing code. This addresses the VS 2015 warning, and fixes behavior with compilers that should issue a warning, but do not. This is safe to do if destructors are checking std::uncaught_exception before throwing.
  2. Destructor redesign: you can comply with the spirit of C++11, and change destructors to not throw. Any errors encountered by destructors should then be logged using some logging facility, perhaps a C-style global handler. The destructor must either call only noexcept code, or must catch exceptions from throwing code.
Long-term, option 2 is more consistent with current C++ direction. In this case, the following macro may come in handy, to ensure that any code called from destructors is noexcept:
#define NoExcept(EXPR) \
    ([&]() { static_assert(noexcept(EXPR), "Expression can throw"); }, (EXPR))
This is unfortunately necessary because otherwise, you have to resort to extensive code duplication. When used as an operator, noexcept returns a boolean, so you have to test it like this:
static_assert(noexcept(INSERT_VERY_LONG_EXPRESSION), "Can throw");
INSERT_VERY_LONG_EXPRESSION;

2015-07-22

The main asset of the US is its value system

And what the US is doing, with respect to spying and whistleblowing, compromises it.

I was following a thread discussing the benefits of having the NSA and CIA, when they didn't even stop the Chattanooga shooter — who shot four marines, but not before writing about Islam on a public blog. Discussion evolved to that maybe the benefits are economic. That maybe these agencies don't stop most bad things from happening, but the US reaps benefits from stealing secrets from other countries.

I find it disturbing to talk about stealing as something acceptable just because it's done between countries instead of between people.

How would stealing from other countries benefit the people of the US? To make use of what you've stolen, you have to give it to some company. Does that really help the average American, or just tycoons with ties to spooks?

To the extent that the US is doing things right, it has been, and should continue to be, the country to be stolen from; not a country that needs to resort to stealing. If you have to steal from other countries, it means you're behind.

There's no reason to steal from various countries around the world if you can just be a nice country into which smart people all want to immigrate, and live there. You don't get to be that with an intrusive, spying government.

A principal contributor to the US being great has been attracting smart people with integrity and constructive values. Einstein, Schwarzenegger, Tesla — born in Europe. Elon Musk — born in South Africa. Sergey Brin — born in Moscow.

You may not like some of them, but these are examples of millions of capable individuals, who would not have come to the US if the US was just like Russia. These people, and their parents, were attracted to the US because of its value system; because it's not like oppressive regimes abroad. And they go on to build the country.

Don't be victim to Dunning Kruger effect, and think that without them, you would do just as well.

The more you adopt a value system of a mediocre country, the more this engine will stop, and the more you'll become mediocre yourselves. For countries as much as individuals, stealing costs; it's short-term gain for long-term loss.

See my previous post on this topic: Whistleblowing policy proposal

2015-07-21

Whistleblowing policy proposal

We face the problem of what to do with people like Assange, Manning, and Snowden, to encourage justified whistleblowing, and yet for secrecy to still be available to projects that really need it. (And let's be mindful here that many projects that believe they need secrecy, really do not.)

I propose that any act of whistleblowing done demonstrably out of idealism, and in good faith, should be protected and given immunity for, one time in a person's life. People who have used this card should lose their career, and no longer be employable in this or any other career that requires clearance. But they should be able blow the whistle one time.

Everyone currently employed in careers that require clearance would have to have this card still available to them — to avoid someone stacking a team full of people who've already been made to spend their card on purpose.

Everyone in powerful positions would then expect that everyone around them has this one-time get-out-of-jail-free card to report truly problematic issues, at cost of irrevocable career loss.

All secret projects would then be highly concerned with making sure that what they're doing is not against the inner conscience of anyone involved.

To the extent that we can also make sure that careers requiring confidentiality do not, and cannot, employ psychopaths, we would have people with a conscience at all levels of government, making sure that even when something is done in secret, it is being done in line with the wider society's values.

And, perhaps quite rightfully — this would lead to many fewer secret projects.

SFTP and OpenSSH's "do as we please"

It bugs me that OpenSSH pull all the same crap that Microsoft was vilified for years ago.

They sabotaged the SFTP standardization process. They are "embracing and extending" as they please, and leveraging their market share in unilateral decisions that ignore the needs of other implementations.

Their quality is also not as awesome as their contributors sometimes seem to believe. They seem to be doing better recently — but historically, they have a nice long list of security issues. This is not to mention bugs that are just bugs, and require workarounds. Just the latest of these is an SFTP data stream corruption if there are commands producing output in .bashrc; because you know, it makes sense for OpenSSH to launch their SFTP subsystem in a way that runs .bashrc; and it makes sense to send garbage output from .bashrc like it was part of the SFTP session to the client. ;)

So that's one workaround we're adding in our next Bitvise SSH Client version.

But this is not to say that OpenSSH are the worst. That would be certainly unfair. There are other implementations (recently, coughciscocough; years ago, coughipswitchcough) which have given us much more trouble. OpenSSH at least does care about fixing stuff that's unambiguously broken, which is more than I can say for some vendors.

So my beef with OpenSSH isn't the quality. It's how they pull the same crap Internet Explorer did; but no one blinks an eye. They avoid responsibility and custodianship that would be expected of a private project with their market share, because they're held to a different standard.

A decade ago, they made a public announcement that they're not going to support SFTP versions higher than version 3: for the simple reason that their interest is BSD and Linux, and they just don't care to implement extensions needed by other platforms. Since they're the major implementation, this stopped SFTP standardization in its tracks. We therefore now have SFTP version 3, implemented by OpenSSH; and then we have SFTP version 6, implemented by most reasonable people.

Because of this, we also remain without an SFTP RFC. Instead, de facto standards are past drafts:
But it wasn't enough for OpenSSH to refuse to support SFTP versions that address the needs of other platforms. Instead, when they need functionality specified by SFTPv6 — they implement their own extensions to SFTPv3.

Just the latest instance that I found today is OpenSSH's decision to not implement the space-available extension in SFTPv6; and instead to implement statvfs@openssh.com.

Fine. That's okay. We'll implement statvfs@openssh.com to accommodate a client that expects it. But geez, if only OpenSSH didn't act quite like Microsoft, fifteen years ago.

"We are a world unto ourselves, self-sufficient. We do not care for the needs of others."

2015-07-19

Aggregated exceptions: Proposal summary

Based on my previous post about errors in destructors and aggregated exceptions, I first made a Reddit thread, and then a proposal in the ISO C++ Future Proposals group. Based on feedback I've received, the proposal has evolved, and would benefit from a page where its current state is published.

I summarize the proposal's state. I will update this if I get further feedback prompting change.

Justification

There is a problem which I believe is limiting C++ in its potential for powerful expression. The problem is the single-exception policy, and its direct consequence: the marginalization of destructors, exemplified in recent years by how they're now marked by default noexcept.

I believe this problem is currently viewed incorrectly by many, and I wish to propose a solution. The solution is aggregated exceptions. I contend these are conceptually simple; resolve the Gordian Knot of destructor exceptions; are backward compatible, and straightforward to implement. :-)

There is a widespread belief, held passionately by many, which I believe is conceptually in error. This is that destructors are supposed to be nothing more than little cleanup fairies. That they should only:
  • quietly release resources, and
  • kindly shut up about any errors.
I find this a limiting and restrictive view, which does not permit full expression of destructors as a way to:
  1. schedule code for execution;
  2. determine the order of execution; but
  3. not dictate the exact trigger for execution to take place.
I propose that the limiting view of destructors is not inherently obvious, but is an accidental ideology. It arises not because we freely choose it, but because of a flaw that has plagued C++ since the introduction of exceptions. This flaw is the single-exception policy. This has prevented answers to questions such as:
  • What to do when a destructor throws, and an exception is already in flight?
  • What to do if we're destroying (part of) a container, and destructors throw for 2 or more of the contained objects?
I propose that we should not have to cope with not having answers for these questions in this day and age; and that support for unlimited aggregated exceptions answers them straightforwardly.

The support I propose:
  • Is conceptually simple.
  • Legitimizes exceptions in destructors.
  • Provides means for containers to handle, aggregate, and relay such exceptions.
  • Imposes no costs on applications that do not use this.
  • Provides a way for destructors to report errors. This is something for which there is currently no solid language support, outside of std::terminate.
  • Emancipates destructors as a way to schedule code for execution. This is to say any code; even code that may throw. This is a frequent usage pattern e.g. in database libraries, whose destructors must rollback; and rollback may involve exceptions.
The use of destructors for general execution scheduling, rather than only cleanup, is recognized as something the language reluctantly needs to support. C++ has always supported throwing from destructors. Even in the latest C++ versions, you can do so by declaring them noexcept(false). However, you better not throw if an exception is already in flight; and you better not store these objects in containers. My proposal addresses this in a more profound way that the noexcept approach does not.

Proposal

Core changes:
  1. In a running program, the internal representation of an exception in flight is changed from a single exception to a list of exceptions. Let's call this the exception-list.
  2. std::exception_ptr now points to the beginning of the exception-list, rather than a single exception. Methods are added to std::exception_ptr allowing a catch handler, or a container in the process of aggregating exceptions, to walk and manage the exception-list.
  3. When the stack is being unwound due to an exception in flight; and a destructor exits with another exception; instead of calling std::terminate, the new exception is simply added to the end of the exception-list. Execution continues as it would if the destructor exited normally.

Catch handlers

Traditional catch handlers:
  • To maintain the meaning of existing programs as much as possible, a traditional catch handler cannot receive an exception-list that contains more than one exception. If an aggregated exception meets a traditional catch handler, then to preserve current behavior, std::terminate must be called. This means we need a new catch handler to handle multi-exceptions.
  • Notwithstanding the above, catch (...) must still work. This is often used in finalizer-type patterns that catch and rethrow, and do not care what they're rethrowing. This type of catch handler should therefore be able to catch and rethrow exception-lists with multiple exceptions. It also provides a method to catch and handle an exception-list as a whole. This can be done via std::current_exception, and new methods added to std::exception_ptr.
We introduce the following new catch handler type:
catch* (<exception-type>) {
We call this a "catch-any" handler. It has the following characteristics:
  • It matches every occurrence of a matching exception in an exception-list. This means it can be called repeatedly, multiple times per scope, if there are multiple matches. We cannot do multiple calls to traditional handlers, because traditional handlers are not necessarily multi-exception aware, and do not expect to be called multiple times in a row.
  • All catch-any handlers must appear before any traditional catch handlers in same scope. This is because the catch-any handlers filter the list of exceptions, and can be executed multiple times and in any order, whereas the traditional catch handler will be the ultimate handler if it matches. Also, the traditional handler will std::terminate if it encounters an exception-list with more than one exception remaining.
  • If there are multiple catch-any handlers in the same scope, they will be called potentially repeatedly, and in an order that depends on the order of exceptions in the exception-list.
  • If a catch-any handler throws or re-throws, the new exception is placed back into the list of exceptions currently being processed, at the same position as the exception that triggered the handler. If there remain exceptions in the list, the search of catch-any handlers continues, and the same catch-any handler might again be executed for another exception in the list.
  • If a catch-any handler exits without exception, the exception that matched the handler is removed from exception-list. If this was the last exception, forward progress resumes outside of catch handlers. If more exceptions are in list, other catch-any handlers at current scope are tested; then any catch handlers at current scope are tested; and if there's no match, unwinding continues at the next scope.

Exception aggregation with try-aggregate and try-defer

For handling and aggregation of exceptions, we introduce two constructs: try-aggregate and try-defer.
  • Try-aggregate starts a block in which there can be one or more try-defer statements that aggregate exceptions.
  • At the end a try-aggregate block, any accumulated exceptions are thrown as a group.
  • If there are no aggregated exceptions, execution continues.
Example.

The following code is currently unsafe if the A::~A() destructor is declared noexcept(false):
struct D
{
    A *a1, *a2;
    ~D() { dispose(a1); dispose(a2); }
}; 

template <typename T> void dispose(T* ptr) 
{ 
    ptr->~T();
    remove_from_siblings(ptr); 
    Allocator::dealloc(ptr); 
}
Problems with this code are as follows:
  • dispose() does not use SFINAE to require that T is std::is_nothrow_destructible. Therefore, dispose() must take exceptions from T::~T() into account — and it does not.
  • The D::~D() destructor makes two calls to dispose(), which is a function that may throw. If disposal of the first member throws, the second member will not be properly disposed.
To allow this type of code to work, C++11 pushes to make destructors noexcept. But this leaves a hole where a destructor can still be declared noexcept(false), and then the above code will not work.

With exception aggregation, the above situation can be handled using try-aggregate and try-defer. To avoid introducing contextual keywords, I use try* for try-aggregate, and try+ for try-defer:
struct D {
    A *a1, *a2;
    ~D() {
        try* {
            try+ { dispose(a1); }
            try+ { dispose(a2); }
        }
    }
}; 

template <typename T> void dispose(T* ptr) 
{
    try* {
        try+ { ptr->~T(); }
        remove_from_siblings(ptr); 
        Allocator::dealloc(ptr);
    }
}
This performs all aspects of destruction properly, while catching and forwarding any errors in a controlled and orderly manner. The syntax is clear, and easy to use.

Containers

With this support, a container can now handle any number of destructor exceptions gracefully. If a container is destroying 1000 objects, and 10 of them throw, the container can aggregate those exceptions using try* and try+, relaying them seamlessly once the container's task has completed.

Since containers are written with templates, this does not need to impose any cost on users that use noexcept destructors. If the element uses a noexcept destructor, exception aggregation can be omitted. This can be done currently using SFINAE, or in the future with a static_if — assuming one is introduced.

Users who previously stored objects with throwing destructors in containers were doing so unsafely. With aggregated exceptions, and containers that support them, such types of use become safe.

What are the uses?

  • Simple resource-freeing destructors can now throw; as opposed to being coerced, via lack of support, to either abort the program or ignore errors.
  • Destructors are now suitable for complex error mitigation, such as database or installation rollback. Currently, it is unsafe to use a destructor to trigger rollback. It forces you to either ignore rollback errors, or abort if one happens — even if there are actions you would want to take instead of aborting.
  • You can now run any number of parallel tasks, and use exceptions as a mechanism to collect and relay errors from them. Under a single-exception policy, you have to rely on ad-hoc mechanisms to collect and relay such errors.

Limited memory environments

Implementation of an aggregated exception-list will most likely require dynamic memory. This poses the question of what to do if memory runs out. In this case, I support that std::terminate should be called when memory for exception aggregation cannot be secured.

For applications that need to guarantee that exception unwinding will succeed in all circumstances, we can expose a function to pre-reserve a sufficient amount of memory. For example:
bool std::reserve_exception_memory(size_t max_count, size_t max_bytes);
If this is a guarantee that your program must have:
  1. You analyze the program to find the maximum number of exceptions it may need to handle concurrently.
  2. You add a call to the above function to reserve memory at start.
I do not see this as much different than reserving a large enough stack — a similar problem that limited memory applications must already consider.

For applications that cannot make an estimate, or are not in a position to pre-allocate, we also introduce the following:
template <typename T> bool std::can_throw();
With aggregated exceptions, this provides similar functionality that std::uncaught_exception() provides currently. It provides destructors with a way to detect a circumstance where throwing an exception would result in std::terminate(); and in that case, allows the destructor to adapt.

When std::reserve_exception_memory() has been called with parameters appropriate for the program, std::can_throw<T>() would always return true. It would also always return true outside of destructors.

A program that doesn't wish to use any of this could also continue to use existing mechanics with no change in behavior. A program can still use noexcept destructors. If it uses destructors that are noexcept(false), it can still call std::uncaught_exception() and not throw if an exception is in progress. To avoid aggregated exceptions from containers, the program can still avoid using containers to store objects whose destructors are noexcept(false) — which is currently the only safe option.

If the program adheres to all the same limitations that we have in place today, it will experience no shortcomings. However, a function like std::reserve_exception_memory() would make it safe to use aggregated exceptions in limited memory environments.

Examples

Q. If you have some class Derived : Base, and the destructor of Derived throws an exception, what do you do with Base?

This is supported by C++ as-is, and remains unchanged in this proposal. If Derived throws an exception, the Base destructor is still called. If this is a heap-allocated object, being destroyed via delete, then operator delete is still called.


Q. Every destructor call is going to have to check for these deferred exceptions. Aren't you adding a bunch of conditional branch instructions to a lot of code?

When a destructor is called, this conditional branching is already there. Currently, it calls std::terminate. With multi-exceptions, it would call something like std::aggregate_exceptions.


Q. Suppose I have struct A, whose destructor always throws. Then I have struct B { A a1, a2 }. What happens when B is destroyed?
  1. a2.~A() is called, and throws. If B is being destroyed due to an exception in progress, the exception from ~A() is added to the existing exception-list. If there is no exception in progress, a new exception-list is created, and holds this first exception.
  2. a1.~A() is called. This throws, and its exception is appended to the existing exception-list.

Q. Suppose I have struct A, whose destructor always throws "whee!". Then I call a function void F() { A a; throw 42; }. What happens?
  1. throw 42 is called, creating an exception-list with a single exception, int = 42.
  2. a.~A() is called, which throws, and appends its exception to the existing exception-list. The exception-list now has two exceptions: (1) int = 42; and (2) char const[] = "whee!".


What's wrong with noexcept?

Forcing destructors to be noexcept is a kludge. It is an architectural misunderstanding — a patch to cover up a defect.

There is no reason the language can't handle multiple exceptions in stack unwinding. Just add them to a list, and require catch-any handlers to process them all. If any single exception remains, it can be handed to a traditional catch handler. All code can now safely throw. Containers can aggregate exceptions.

This is a focused change that fixes the problem at a fundamental level, emancipates destructors, and allows handling of parallel exceptions. Any number of errors can be handled seamlessly, from the same thread or multiple, and there's no longer code that can't throw.

Instead of fixing a hole in the road, forcing destructors to be noexcept is a sign that says: "Avoid this hole!" Instead of fixing the road, so it can be traveled on, noexcept creates a bottleneck in traffic, and blocks an entire lane from use.

2015-07-16

Errors in destructors: C++ and the case for aggregate exceptions

See update in my following post:
Aggregated exceptions: Proposal summary



In a recent post, I suggested that when a destructor detects a cleanup error, throwing an exception is an acceptable way to report it. I argued that reporting problems is always preferable to ignoring them, so if a destructor does detect a problem, throwing is better than doing nothing. In the worst case, it will cause a whole program abort, which in unexpected circumstances is yet better than no reporting.

It turns out that, with C++11, the language committee took the opposite stance on the issue. Quite simply, all destructors are now declared noexcept(true) unless you go to the trouble of declaring them noexcept(false) - in which case, you are on your own, and the STL doesn't like you.

In Visual C++ 2010 and 2013, support for noexcept is not implemented, so behavior remains as in C++03. However, if you compile the following with g++ -std=gnu++11:

struct A { ~A() { throw "all good"; } };

int main()
{
    try { A a; }
    catch (char const* z) { std::cout << z << std::endl; }
}

... the result of running this won't be "all good"; it will be a call to std::terminate(). Furthermore, even with -Wall, GCC will not warn you about this behavior. (VS 2015 does.)

Exceptions and categories of errors

When programs encounter unexpected conditions, ways of handling them can be categorized thusly:
  1. It may not make sense for the program to continue. The response is whole program abort. In most cases, no cleanup is necessary. Resources will be cleaned up by the operating system.
  2. It may not make sense for part of a program to continue, but other parts should. An example is a server that handles connections from many clients. The response is to throw an exception. Unwind the part that cannot continue, report the error, but let the rest of the program run.
  3. The program may have encountered an unexpected condition, but can continue. The program does not need to throw or abort; it can proceed after reporting the error.
It may be useful to define a small program as one in which category 2 errors do not exist. There is a school of thought which says that a program that can have category 2 errors is too big, and should be broken up into smaller processes. Erlang and traditional Unix are examples of this approach. Applications consist of many small processes which can individually abort, yet the system continues.

Breaking up an application into processes, however, creates difficulties for communication between them. What would previously be a function call, now requires some kind of RPC protocol. Issues arise with security and efficiency of these communications. Unless you have infrastructure like Erlang that solves these problems for you, a tradeoff arises between simplicity and efficiency on the one hand, and resilience on the other. Most developers will choose what looks simpler and less work; so that's how you end up with monolithic applications, in which exceptions are especially useful.

Limitations of C++ exceptions

The whole problem with exceptions in destructors is that C++ exceptions are inherently not designed to handle multiple concurrent errors. This isn't by necessity; it is by choice. Language designers had the following reasonable options:
  1. No exceptions. C chose this option.
  2. One exception at a time. C++ chose this option.
  3. Unlimited exceptions. An option that C++ can still choose.

How could C++ support unlimited exceptions?

Instead of std::exception, with its basic char const* what(), you'd have an exception class that can have child exceptions attached to it — something similar to std::nested_exception. If an exception causes you to destroy a container with 1000 objects; and 10 of those destructors throw; you can catch those exceptions, attach them to the parent exception you're handling, and allow that exception to grow as you go. By the time the exception reaches its ultimate handler, it consists of one primary exception, and any number of other exceptions attached to it. That is fine, and you can report and handle them all.

But what if the exception is bad_alloc, and there's no memory for secondary exceptions?

The program should wait for memory to become available.

In 20 years, I have never seen bad_alloc on Windows unless the program requested an unreasonable amount of memory. In all of these cases, normal-sized allocations could still continue.

Windows will go to extreme lengths to avoid failing a reasonable memory request. I argue that this is what an operating system should do. If a program finds itself in a position where it cannot allocate a small amount of memory, it should spin with Sleep(), and wait for memory to become available. If the memory is being exhausted by another process or thread, it will eventually finish or be killed, and other processes can continue. If the memory is being exhausted by the same thread, then the program is in a borked state, and might as well hang, so someone can attach to it with a debugger. In this case, the program needs to be fixed.

We should not design exception handling as if the typical case is going to be a low-memory condition in which operator new fails for reasonable allocations. For reasonable use, operator new should never fail. If we're allocating memory for an exception, the allocator should succeed or wait indefinitely.

When the human economy runs out of something vital, our go-to response is to queue for it. There's no reason a program shouldn't wait if it needs something vital — such as a small amount of memory to proceed with exception handling.

Can we support exception aggregation manually?

What would have been nice would be if all exceptions inherited from something like std::nested_exception; and that if an exception occurred in a destructor while another is being handled, instead of the program calling std::terminate, the new exception would be simply attached to the old one.

Sadly, this functionality does not exist. There are things in C++11 that are similar at first sight, like std::current_exception and std::throw_with_nested — but they can only be called from inside a catch handler, not from a destructor that's being called as the stack unwinds.

Even if you implement a custom container to gracefully handle multiple exceptions in destructors of objects it contains, this will only work if the container catches the first exception. If your container's destructor is being called during stack unwinding, you can aggregate exceptions within the container as much as you like — but there's no way to attach them to the first exception that's being handled.

In short — it looks like no, this is a fundamental shortcoming of the language. You can't join an exception to another in flight.

What options do we currently have?

You can throw from destructors if you declare them noexcept(false), and check std::uncaught_exception() before throwing. This doesn't allow for exception aggregation, but it allows you to report cleanup errors if another exception isn't already in flight. If an exception is already in flight, you're on your own; the language doesn't have a solution. If an object that throws this way is used in a container, issues like resource leaks may arise. A resource leak is usually still better than not reporting an error.

You can also submit to intentions of language designers, and not throw from destructors ever. That leaves you with error reporting options that avoid exceptions:
  • Whole program abort. You can treat cleanup failure as a critical error. The error may, or may not, in fact be critical. For example, something like CloseHandle could fail because you've called it already, or due to some kind of network connectivity error. In the former case, the error could be critical; in the latter case, your application should be resilient.
  • Report and continue. You can use some kind of non-exception facility to report the error, and then continue as though nothing happened. This can be the wrong thing to do if the cleanup error is of a kind that the program should, in fact, unwind partially.

What should the language do?

A future version of C++ should support unlimited concurrent exceptions. If an exception is in flight, any additional exceptions in destructors should be aggregated to the main exception automatically.

Consider that we now develop for systems where desktops have 16+, and mobiles have 2+ GiB of memory. We do not lack the resources to handle multiple exceptions gracefully.

For container implementors, some syntactic sugar would be most welcome:

class container_type {
    ...
    ~container_type() {
        try aggregate {  // Aggregates and re-throws exceptions in contained "try defer"
            for (size_type i=0; i!=size(); ++i)
                try defer { delete m_objects[i]; }  // Must be within "try aggregate"
            delete[] m_objects;
        }
    }
};

The above suggests two contextual keywords, "try aggregate" and "try defer", largely equivalent to:

class container_type {
    ...

    ~container_type() {
        std::exception_ptr eptr;

        for (size_type i=0; i!=size(); ++i)
            try { delete m_objects[i]; }
            catch (std::exception const&) {
                if (!eptr)
                    eptr = std::current_exception();
                else
                    eptr->aggregate_current();  // Not supported currently
            }

        delete[] m_objects;

        if (eptr)
            std::rethrow_exception(eptr);  // Join to in-flight exception
    }                                      // not supported currently
};

This is already almost possible currently - the main obstacle being join to in-flight exceptions.

How would this affect catch handlers?

It would not. The only difference would be that any exception you catch can have aggregated exceptions attached to it, which you can investigate.

For example, suppose your mail delivery subsystem throws Smtp::TemporaryDeliveryFailure. During stack unwinding for this exception, a destructor calls closesocket, and it returns an error.

In current C++, you have no good options for what to do with that. Most developers will ignore it, so you lose information that closesocket failed. If you don't want to ignore it, passing the error somehow from a library to a using application requires some ad hoc process, involving C-style global error handler hooks, instead of using a C++ language feature.

With the above proposal, the destructor can throw Socket::Error, and it will be aggregated to Smtp::TemporaryDeliveryFailure. Your catch handler will still catch the delivery failure, and can ignore any aggregated exceptions — with same result as if the destructor that calls closesocket did not throw.

However, your catch handler can also process the aggregated exceptions. It can inspect them, decide they're innocuous, it can log them, or it can re-throw them. Standard language mechanisms can be used to relay information which is currently very hard to relay while retaining a clean architecture.

What's the impact on noexcept?

It strikes me that the main usage case of noexcept is as a kludge — to compensate for the language's inability to handle multiple exceptions. It basically creates two languages in one. It stratifies all code into (1) code that throws, and (2) code that doesn't.

If we add multi-exception support, it may just be that noexcept loses its main usage case. It would remain useful for domain-specific code that wants to ensure that no exceptions happen while it's executing. However, that seems like a minor niche compared to its current use as a kludge in destructors.

Code as concise expression of thought

At risk of coming across like Jaden Smith, let me wax philosophical about programming.

All code is thought, and development is unfolding of a thought process using the computer as external infrastructure in which to hang thoughts that don't all concurrently fit in your head. Therefore, the current state of your code reflects your current understanding of the problem you're solving. This understanding has to improve over time, but it usually does not radically change. Being good at development means being good at expressing your current state of mind in code; writing it so it's a true reflection of your thinking, rather than a muddled one.

Therefore, when you write code in a way that it's in harmony with your thought, changing your thought in a small way will produce a similarly small change in code. If changing your thought in a minor way causes large changes in code, it means you're expressing yourself poorly.

2015-07-14

Your production code should assert

If you have C or C++ experience, you're familiar with asserts. Here's just one example use case in a Visual Studio 2013 include file:

bool _HasCapturedContext() const
{
    _ASSERTE(_M_context._M_captureMethod != _S_captureDeferred);
    return (_M_context._M_pContextCallback != nullptr);
}

Pretty normal, right? Let's see how _ASSERTE is defined.

#ifndef _DEBUG
...
#ifndef _ASSERTE
#define _ASSERTE(expr) ((void)0)
#endif  /* _ASSERTE */
...
#else  /* _DEBUG */
...
#ifndef _ASSERTE
#define _ASSERTE(expr)  _ASSERT_EXPR((expr), _CRT_WIDE(#expr))
#endif  /* _ASSERTE */
...
#endif  /* _DEBUG */

This is good, right? Perform checks while testing; then, when most bugs have been weeded out, omit the tests for production, to reap major performance benefits. So speed! Such performance! Wheeee!

No. This is wrong. Do not do this.

First of all: assert checks are nearly free. In most applications - i.e. anywhere outside of algorithms that do hard core, cache-optimized data crunching - the CPU is not tied up by instructions, it's tied up with memory access. The instruction cost of the assert check is therefore nearly zero. The assert branch is never taken, and provides easy work for the CPU's branch prediction.

On the other hand, you're paying by not doing the assert as follows:
  • You will fail to detect bugs that your testing failed to exercise until your program crashes in production. You will then have a jolly old time debugging without the benefit of asserts.
  • Better yet - the bug might not be detected at all, and may result in silent corruption of data.
  • If your code is public, anyone with access to it can look at your asserts, and use them literally as a guidebook for exploits. Each assert corresponds to a weakness in production!
You're introducing diagnostic issues, data corruption, and making your program exploitable - all for the awesome benefit of a few CPU cycles! Wheeeee!

Keep your asserts in production

The cost is negligible, and the benefits are many. You should nearly always keep your asserts.

In fact - just to make sure no one thinks these checks should be removed in Release mode - I have stopped calling them "asserts" at all. I call them "ensures". In my latest code, this is how I define them:

// By default, an interactive EnsureAbortHandler is set. The interactive handler will output
// information about an Ensure failure either to STDOUT (if available), or otherwise, using
// an interactive dialog box.
//
// If the application is running non-interactively, call this to set an EnsureAbortHandler
// that will output information about any ensure failures to the Application section of the
// Windows Event Log.

void SetEnsureAbortHandler_EventLog(wchar_t const* sourceName, DWORD eventId);


struct OnFail { enum E { Throw, Abort }; };

struct InternalInconsistency : public std::exception {};

// Handles an Ensure failure:
// - if running under a debugger, always causes a debug breakpoint;
// - otherwise, if onFail == OnFail::Throw, and there is no uncaught exception,
//   throws an exception deriving from InternalInconsistency;
// - otherwise, if onFail == OnFail::Abort, or there is an uncaught exception,
//   calls the registered EnsureAbortHandler.

void EnsureFailure(OnFail::E onFail, char const* test, char const* funcorfile, uint line);

#define EnsureThrow(TEST) \
  ((TEST) ? 0 : (At::EnsureFailure(OnFail::Throw, #TEST, __FUNCSIG__, __LINE__), 0))

#define EnsureAbort(TEST) \
  ((TEST) ? 0 : (At::EnsureFailure(OnFail::Abort, #TEST, __FUNCSIG__, __LINE__), 0))
There are two types of ensures because there are two types of unexpected conditions: those you can recover from, and those you can't.

You can recover from an Ensure failure if you detect it before damage has taken place. In this case, you call EnsureThrow, which throws an InternalInconsistency exception, which isn't caught until it reaches a fairly base-level exception handler. An Ensure failure is an unexpected condition, so it means you must stop and potentially restart that part of your program which encountered it, in order to restore your program to a known state. In a server program, an appropriate thing to do is to terminate any worker thread or client connection or session related to the Ensure failure, but allow the rest of the server to run if you believe it to be in a good state.

You cannot recover from an Ensure failure if you detect it after damage has taken place. If you detect that a pointer is pointing somewhere it shouldn't, that memory might have been written to incorrectly - you should call EnsureAbort. This version does its best to report the problem - either via standard output, via dialog box, or via Windows Event Log - and then ends the program. If data may be at risk, the program shouldn't continue to run. It's better to have a denial of service than corruption.

Why I use "SomeObj const&", not "const SomeObj&"

This is a minor point of style, but it's important to me.

For some reason, the widely accepted C++ style is to put const in front of things:

void Function(const std::vector<int>& v)
{
    const int i = 123;
    ...
}

I pronounce this a bad choice. There's another legal way to use const, and I prefer it:

void Function(std::vector<int> const& v)
{
    int const i = 123;
    ...
}

This is why:

const void* const* const p = ...;    // Not so clear and consistent
void const* const* const p = ...;    // Clear and consistent

void Method() const;                 // const comes after Method

When a pointer is const, the keyword comes after the asterisk. When a method is const, the keyword comes after the method. When a type is const, putting const after the type is always consistent.

Putting const in front, as per the usual style, makes things like:

const void* const* const p = ...;

... kinda confusing.

Reporting errors in destructors

July 17, 2015:

My below suggestions are not good for C++11 in GCC, Clang, and probably VS 2015 and later.

See my follow-up post:

Errors in destructors: C++ and the case for aggregate exceptions



I'm having an argument with someone who thinks Effective C++ is the end-all and be-all of all things. Specifically: The book has a chapter on how exceptions in destructors are tricky. The guy appeals to this as an authority, and concludes you should never throw exceptions in destructors, ever.

Now, Effective C++ is a good book. I would recommend it to a beginner. If you're at a point where you need to read Effective C++, please do read it, get 3-5 more years of experience, and then give me a ring.

Shortly, though, the guy is wrong. All code has to be aware of exceptions. All code has to get them right. Destructors are just somewhat trickier, because they have to be more aware of them.

This doesn't mean you shouldn't throw from destructors. In fact, you should. The following code:

~SomeClass() noexcept(false)
{
    if (!CloseHandle(someHandle) && !std::uncaught_exception())
        throw SomeException(GetLastError());
}

... is much better, more solid, and more useful than this:

~SomeClass() { CloseHandle(someHandle); }

The former will detect problems when closing the handle, and will cause them to be known if opportunity permits. The latter will just ignore them.

But you shouldn't just throw willy-nilly. The following:

&& !std::uncaught_exception()

... is absolutely crucial. You shouldn't throw that exception if one is already in progress. If you do, your program will most likely abort. (But that is - by the way - not always a bad thing.)

The bugaboo about never throwing exceptions from destructors is harmful. You should throw from destructors. However, you need be aware of what you're doing.



July 16, 2015:

Unfortunately, since C++11, the language standard committee disagrees. Since C++11, with compilers that implement this, destructors that throw have to be explicitly marked noexcept(false). If not, the object has to inherit from, or contain another object with a destructor explicitly marked so. This is the case even if the destructor has obvious throw statements! With GCC 4.9.2, the following code:

struct A { ~A() { throw "all good"; } };

int main()
{
    try { A a; }
    catch (char const* z) { std::cout << z << std::endl; }
}

... compiles with no errors and no warnings with -std=gnu++11 (or 14) and -Wall, but results in std::terminate() being called.

Visual Studio 2013 does not support noexcept, so the above code outputs "all good". I have not tested 2015. In GCC, and I believe also Clang, any throwing destructors must be declared noexcept(false).

2015-07-13

C++ should support temporary objects as lvalues

Microsoft Visual C++ has long implemented an extension to C++ that the standard language does not permit: temporary objects can be assigned to non-const references (lvalues).

I find this extension useful, allowing for some elegant constructs that standard C++ does not permit.



Example 1:

void StrCvtCp(Seq in, Str& out, UINT inCp, UINT outCp, Vect<wchar_t>& convertBuf);

Here I have a function that converts a string from one code page into another, using MultiByteToWideChar and WideCharToMultiByte internally. The function needs to use a conversion buffer. For callers that might call this function many times in a row, it is more efficient to keep reusing the same conversion buffer than to reallocate it in every call to the function. More occasional callers, however, don't want the inconvenience of having to instantiate the buffer, and just want one to be created by default.

In MSVC, solving this is easy:

void StrCvtCp(Seq in, Str& out, UINT inCodePage, UINT outCodePage,
    Vect<wchar_t>& convertBuf = Vect<wchar_t>());

But in standard C++, I must do this:

void StrCvtCp(Seq in, Str& out, UINT inCp, UINT outCp, Vect<wchar_t>& convertBuf);

inline void StrCvtCp(Seq in, Str& out, UINT inCp, UINT outCp)
    { Vect<wchar_t> convertBuf; StrCvtCp(in, out, inCp, outCp, convertBuf); }

Ugh. So much more typing, and more opportunity for error.



Example 2:

In MSVC, I can do this:

smtpMsg->f_content.Reserve(1000 + plainContent.Len());
imfMsg.Write(Imf::MsgWriter(smtpMsg->f_content));

But in standard C++, I must do this:

smtpMsg->f_content.Reserve(1000 + plainContent.Len());
Imf::MsgWriter msgWriter(smtpMsg->f_content);
imfMsg.Write(msgWriter);

Why? Just... why? I have no reason to name that temporary.



Example 3:

I have a class Console, which defines this:

struct Console
{
    ...

    template <Device D>
    struct WriteOnDestroy : Str
    {
        WriteOnDestroy() = default;
        ~WriteOnDestroy()
            { if (!std::uncaught_exception() && !Empty()) Console::Write(D, *this); }
    private:
        WriteOnDestroy(WriteOnDestroy const&) = delete;
        void operator=(WriteOnDestroy const&) = delete;
    };

    using Out = WriteOnDestroy<StdOut>;
    using Err = WriteOnDestroy<StdErr>;
};

I want to use it like this:

Console::Out()
    << e.what() << "\r\n"
       "\r\n"
       "Usage:\r\n"
       "- Run without parameters to start service in console\r\n"
       "- Use parameter 'register' or 'unregister' to register/unregister service\r\n";

In MSVC, this works because the line Console::Out() instantiates a temporary object, which derives from Str, and can be passed to operator << overloads like this one:
inline Str& operator<< (Str& s, char const* z) { return s.Add(z); }

There's a substantial reason I want to use this temporary object: by concatenating strings and deferring the write until the temporary object's destructor, I provide implicit thread safety by only making one call to the Console::Write method.

In standard C++, this doesn't work, because the temporary object cannot be used as an lvalue. I must instead define the following monstrosity:

template <typename T>
Console::Out const& operator<< (Console::Out const& x, T&& a)
    { ((Str&) x) << std::forward<T>(a); return x; }

This works, but Jesus, look at the abuse it's doing.

Discussion

When I proposed the above on Reddit, the most popular response was that it's to prevent this problem:

void increment(long& foo) { foo += 1; }
int main() {
    int x = 123;
    increment(x);      // Temporary created
    assert(x == 124);  // Oops!
}

But this is a strawman. MSVC does not accept this:

error C2664: 'void increment(long &)' : cannot convert argument 1 from 'int' to 'long &'

Even though it does support temporary objects as rvalues, the temporary object has to be explicit.

I haven't been able to cause a problem like this with classes, either. As far as I can tell, MSVC won't implicitly create a temporary to assign to a non-const ref. However, an explicitly created temporary works.

I see no reason it shouldn't work in standard C++.