int32_t ticks; // 100ths of a second
which overflows in 248 days, a particularly unfortunate amount of time because it doesn't show up during testing.Although it would be a good engineering choice, a formal verifier would say that:
int64_t ticks; // 100ths of a second
is also incorrect, since it also overflows (after 10^9 years).In a hard real time system,
mpz_t ticks; // 100ths of a second, infinite precision libgmp type
is still formally incorrect, since as the the number grows in size it will eventually exceed a time limit or memory (after 10^10^9 years)The overall lesson from formal methods is that it's impossibly to write formally correct useful programs. So programmers just muddle through.
I would go with uint64_t
as it documents "ticks" as a variable that can not hold negative values and also doubles its range of positive values.
uint64_t ticksOfDuration10ms; // No comment necessary
You'll almost always have a global variable, preprocessor define... or something similar to get the frequency (or time increase per tick), which you should use whenever you have to convert "ticks" to actual physical units. If the actual effective tick rate is visible at many places in your code, both as a symbol name or as a comment, you are most certainly doing something wrong.
(then you'd know it was safe)
int64_t elapsed = (int64_t)(t1 - t0);
And it's very easy to cause disaster with: if ((t1 - t0) > 50) ...
which also succeeds if t1<t0.While it's theoretically possible, using all 64 bits is tricky and very hard to test.
The "can not hold negative values" argument is also weak because a uint does not prevent generating negative values - it only prevents you from knowing that you've generated negative values. Such a state is a bug.
Using a uint only serves to make it harder to test when your system is in an invalid state.
Nothing. Built in arithmetic will do the job nicely.
If the algorithms really depend on an always monotonously increasing tick-counter (which I doubt), the solution is quite easy: After 2^30 ticks set a flag which raises the "service needed" light in the cockpit, taking the plane out of service until it's power cycled. By this you explicitly state that your device cannot be used longer than 120 days continuously.
Then the simple "raise service-needed signal" would be a valid workaround and easily testable local change for the next two years until the extensively fixed-algorithm went through testing and certification.
What made this bug dangerous is that nobody knew about it, that's the main problem that needs to be solved.
uint32_t t1 = ...;
uint32_t t2 = ...;
if ((uint32_t)(t2 - t1) >= UINT32_C(0x80000000)) {
// t2 is before t1
} else {
// t2 is after or equal to t1
}
What this gives us is that if the difference of the actual times (not these uint32 representations which are ambiguous modulo 2^32) is less than 2^31 units (plus minus one maybe..), this check will give the expected result. This does allow a correct system that never fails if the timing/duration of the events is suitably limited.For example you time events at a fixed time interval, and it will keep going forever in spite of clock roll-over.
uint32_t next_time = now();
while (1) {
while ((uint32_t)(now() - next_time) >= UINT32_C(0x80000000));
printf("Shoot\n");
next_time += interval;
}
The timing events also need to be processed quickly enough of course (that printf shouldn't block for longer than about 2^31).This is a scary-ass bug in a codebase that was supposed to be authored to strict professional standards.
http://lxr.free-electrons.com/source/include/linux/jiffies.h...
but I would suspect Boeing used something better than C.
Invariably, cost. SPARK Ada is demonstrably superior to C for safety-critical development (I can't cite the sources for this, but a major company developing safety-critical software has shown this to be the case).
But, SPARK Ada requires a lot of highly skilled manpower and it's slow to develop. C gets the job done, albeit with lots of bugs.
Realistically, it seems to me that avionics etc. will be written in C for a very long time to come. It all comes down to the cost and availability of programmers.