We all know that C++ inherited unsafe semantics from C, but one would expect modern library features such as std::chrono to be carefully designed to avoid the old integer conversion bugs... right?

Not the case: it's very easy to silently cause truncation or overflow in correct-looking code, such as:


Try to get a compile-time diagnostic or at least a run-time error for this interface:

· · Web · 2 · 1 · 0

This is some background info on std::chrono:

At 27:00 there's a hint that one could handle overflows by just using a safeint type:


I don't think it's as simple as this slide hints: what are you going to do? Throw an exception at runtime? Saturate to the maximum representable value? Call abort()?

Constants that will certainly overflow should result in a compile-time error, just like in this case:

uint8_t byte{666};


@namark I just tried std::chrono::duration<boost::safe_numerics::safe<int32_t>> and immediately ran into trouble because duration_cast uses std::common_type, and oddly, Boost does not provide specializations for its safe types.

After defining a bunch of variants, I got the code to compile with exceptions. Then I tried switching to traps (since our embedded codebase is built with -fno-exceptions), and I hit another error cascade that I'm too tired to debug 😡

@namark Here's the code:

It won't compile in Godbolt because it needs Boost, and it won't compile with g++ or clang either, because of some weird error:

In template: type 'boost::safe_numerics::trap_exception' does not provide a call operator

@namark Oh wait, that's how they implemented the compile-time trap:

// emit compile time error if this is invoked.
struct trap_exception {
constexpr trap_exception() = default;
// error will occur on operator call.
// hopefully this will display arguments

Yeah, but it barfs a pageful of impenetrable template errors leading to this! I can't impose this horror on the whole team.

@codewiz you seemed to have a problem with the concept so that was an explanation and a proof of concept implementation. Pleasantly surprised it worked at all! If you care about it you should participate, cause as far as I know that is the most developed of any such concepts:

common_type trait sounds like a misnomer, but I imagine chrono didn't have anything better to use. safe_numeric may provide alternatives on that front, though it will likely never be standardized in it's current form. It's much more likely for a more generic numeric library to get in, that would also handle arbitrary precision and provide the safe_numerics functionality as its subset, and probably not called "safe" cause that's not a very good name either.

@namark Sorry if it sounded like I was shooting the messenger. I find it upsetting that modern C++ comes with a sophisticated type-safe library for time conversion, but then it actually overflows just like K&R C.

I found an issue for adding common_type specializations for safe_numerics, but it was closed 2 years ago. I added a comment asking to re-evaluate:

@codewiz the main point is that it's a nuanced issue out of scope for chrono. Any halfway solution would achieve very little and lower the quality of the library. The arithmetic bound checking is universally applicable, so it would be kind of silly to have something for durations that you couldn't use for other types. Also imposing any sort of compile-time, run-time or maintenance overhead any such checks would bring is nonsensical in a world where everyone in every other application of arithmetic is perfectly happy to just use a type that is assumed to be "large enough" to represent any value. Most just want to use a 64 bit int, and forget it can overflow, even at nanosecond precision, and some would vehemently argue that even on systems that don't have wide enough words, it should just be emulated in software.

Sign in to participate in the conversation

The social network of the future: No ads, no corporate surveillance, ethical design, and decentralization! Own your data with Mastodon!