Introduction to runtime error checking
Runtime error checking
Runtime error checking is a way of detecting erroneous code constructions when your application is running. This is done by instrumenting parts of the code in the application, or by replacing C/C++ library functionality with a dedicated library that contains support for runtime error checking.
Runtime error checking uses different methods for implementing the checks, depending on the type of your application and in what environment it should run.
Instrumenting the code to perform checks makes the code larger and slower. Variants of library functions with checks will also, in general, be larger and slower than the corresponding functions without checks.
Runtime error checking using C-RUN
C-RUN supports three types of runtime error checking:
Arithmetic checking, which includes checking for integer overflow and underflow, erroneous shifts, division by zero, value-changing conversions, and unhandled cases in switch statements. Normally, the overhead of arithmetic checking is not particularly high, and arithmetic checking can be enabled or disabled on a module by module basis with no complications.
Bounds checking, which checks whether accesses via pointers are within the bounds of the object pointed to. Bounds checking involves instrumenting the code to track pointer bounds, with relatively high costs in both code size and speed. A global table of bounds for indirectly accessed pointers is also needed. You can disable tracking, or just checking, per module or function, but any configuration where pointer bounds are not tracked by all code will usually require some source code adaption.
Heap checking using a checked heap, which checks for errors in the use of heap memory. Heap checking can find incorrect write accesses to heap memory, double free, non-matching allocation and deallocation, and, with explicit calls, leaked heap blocks. Using the checked heap increases the memory size for each heap block, which might mean that you must increase your heap size, and heap operations can take significantly longer than with the normal heap. It also checks only when heap functions are called, which means that it will not catch all heap write errors.
All checks that C-RUN can perform can be used for both C and C++ source code.
You can enable several types of C-RUN checks at the same time. Each type of check that you enable will increase, sometimes very slightly, execution time and code size.
Sometimes, the compiler might merge several checks into one, or move a check out of a loop, in which case the problem may be detected well in advance of the actual access. In these cases, the C-RUN message will display the problem source location (or locations) as separate from the current location.
Before you perform any C-RUN runtime checks, make sure to use all the compiler’s facilities for finding problems:
Do not use Kernighan & Ritchie function declarations—use the prototyped style instead. See ‑‑require_prototypes.
Make sure to pay attention to any compiler warnings before you perform any runtime checking. The compiler will not, in most cases, emit code to check for a problem it has already warned about. For example:
unsigned char ch = 1000; /* Warning: integer truncation */Even when integer conversion checking is enabled, the emitted code will not contain any check for this case, and the code will simply assign the value 232 (1000 & 255) to
ch.
Note
C-RUN depends on the Arm semi-hosting interface (the library function __iar_ReportCheckFailed will communicate with C-SPY via the semihosting interface). It is only in non-interactive mode that you can use another low-level I/O interface. See Using C-RUN in non-interactive mode.
For information about how to detect the errors, see Detecting various runtime errors.
The checked heap provided by the library
The library provides a replacement checked heap that you can use for checking heap usage. The checked heap will insert guard bytes before and after the user part of a heap block, and will also store some extra information (including a sequential allocation number) in each block to help with reporting.
Each heap operation will normally check each involved heap block for changes to the guard bytes, or to the contents of newly allocated heap memory. At certain times (either triggered by a specific call, or after a configurable number of heap operations) a heap integrity check will be performed which checks the entire heap for problems.
It is important to know that the checked heap cannot find erroneous read accesses, like reading from a freed heap block, or reading outside the bounds of an allocated heap block. Bounds checking can find these, as well as many erroneous write accesses that might be missed by the checked heap because they do not write to a guard byte or an otherwise checked byte. The checked heap also checks only when a heap operation is used, and not at the actual point of access.
Using C-RUN in the IAR Embedded Workbench IDE
C-RUN is fully integrated in the IAR Embedded Workbench IDE and it offers:
Detailed error information with call stack information provided for each found error and code correlation and graphical feedback in editor windows on errors
Error rule management to stop the execution, log, or ignore individual runtime errors, either on project level, file level, or at specific code locations. It is possible to load and save filter setups.
A bookmark in the editor window for each message which makes it easy to navigate between the messages (using
F4).
In the IDE, C-RUN provides these windows:
The C-RUN Messages window, which lists all messages that C-RUN generates. Each message contains a message type (reflecting the check performed), a text that describes the problem, and a call stack. The corresponding source code statements will be highlighted in the editor window. See C-RUN Messages window.
The C-RUN Message Rules window, which lists all rules. See C-RUN Messages Rules window. The rules determine which messages that are displayed in the C-RUN Messages window.
Using C-RUN in non-interactive mode
You can run C-RUN checked programs using cspybat—C-SPY in batch mode. cspybat can use rules and other setup configured in the Workbench IDE. C-RUN messages in cspybat are by default reported to the host stdout, but you can redirect them to a file.
If you instead want to use your own communication channel between your application and the host for C-RUN messages, replace the function __iar_ReportCheckFailed (uses the semihosting interface for the communication) with your own version and you can use any communication interface you like. In the source file ReportCheckFailedStdout.c (arm\src\lib\crun) you can find a variant that reports to the application’s stdout. To use your own report function instead of the semihosting one, use the linker option ‑‑redirect __iar_ReportCheckFailed=__iar_ReportCheckFailedStdout.
Note
If the module for the report function is inserted into the project, the module should not be compiled with any C-RUN source code options.
The output from __iar_ReportCheckFailedStdout is not in user-readable form, because it only contains the raw data. You can use cspybat with the simulator driver to transform the raw text into something very similar to normal C-RUN messages. For more information, see ‑‑rtc_raw_to_txt.
Use the option ‑‑rtc_enable to enable C-RUN in cspybat. Note that all cspybat options for C-RUN all begin with ‑‑rtc_*. For more information about these options, see cspybat options for C-RUN.
Requirements for runtime error checking
To perform runtime error checking you need C-RUN, which is an add-on product to IAR Embedded Workbench.