In his Trimming cost and size: The software side of the story article Benjamin Brosgol from AdaCore delves into the subject matter with his usual gusto. If you’ve done any kind of software development, you’ll know that the cheapest bugs to fix are those found before the product is launched and this even more so for embedded software, where it can be a real pain to update the devices. Brosgol does a good job of describing these issues:
For several reasons, buggy software is especially acute in embedded applications. First, an embedded system typically monitors or controls some external device, so in critical applications an error or vulnerability could compromise safety, security or both; lives could be lost, and substantial assets could be at risk.
Second, debugging embedded software is harder than debugging native software. For example, embedded systems generally involve concurrency and real-time constraints, which introduce opportunities for errors such as deadlock, missed deadlines and corrupted data. Because some of these bugs are timing dependent and not easily reproduced, they could go undetected until the software is fielded. With perhaps thousands or even millions of systems in use, even a bug with low probability of being triggered will occur eventually.
Third, correcting a defect in an embedded product already in service is complex and expensive. Solutions that involve wireless uploads raise serious security issues that are just beginning to be addressed in equipment ranging from medical devices to automotive systems.
One solution to help programmers produce fewer bugs is design by contract or contract-based programming, and halfway down Brosgol introduce us to the contract features of Ada 2012, specifically the pre- and postconditions for subprograms:
Other language technologies treat contracts as run-time constructs. A recent example is Ada 2012, in which contracts take the form of Boolean conditions that are supplied in contexts such as invariants for types and preconditions and/or postconditions for subprograms. The programmer can control whether the software generates code to check these conditions at run-time; a failed check raises an exception. In this way, the specified contracts can be used either as formal comments that document the program’s intent or as run-time checks that are part of a testing regimen.
Next Brosgol goes on to talk about the extensive restrictions programmers can utilize in Ada to tailor the run-time requirements to their exact needs, using the Restrictions pragma. The entire article is a very nice and informative read, so be sure not to miss it.