Skip to content

Latest commit

 

History

34 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IAR C-RUN Walkthrough

IAR C-RUN is a runtime analysis tool fully integrated into the IAR platform. It automatically instruments your C and C++ code to help you quickly spot runtime errors, ensuring improved code quality for your applications.

This quick walkthrough will guide you through the runtime error checking capabilities offered by IAR C-RUN. Refer to C-RUN runtime error checking for more information.

Software requirements

For evaluating C-RUN using this guide, fulfill the following requirements:

Product Minimum version Recommended version
IAR Embedded Workbench for Arm 8.11.1 10.10.1 or later
IAR Embedded Workbench for Renesas RX 5.10.1 5.20.1 or later

Note

IAR C-RUN is included with the IAR Platform subscription. Alternatively, it is available for evaluation of the supported products.

Exploring C-RUN

A number of example projects, created as demonstrations of the feature set offered by C-RUN, can be found in this repository.

To run the examples:

  1. Clone this repository -or- download (and extract) its .zip archive.
  2. Launch the IAR Embedded Workbench IDE.
  3. Open the corresponding Workspace.eww file for the desired target architecture (arm -or- rx).
  4. If offered, allow the IDE to upgrade the workspace projects.

Upgrade projects

This workspace contains 5 projects:

Workspace-overview

The following sections will present detailed instructions for each of these projects, enabling you to take full control of the feature set offered by IAR C-RUN.

Arithmetic Checking

The first example explores the most straightforward functionality in C-RUN: the Arithmetic checks.

To run this example, do this:

  1. Make sure the Arithmetic project is set as active.

  2. Choose Project → Options (Alt+F7) → Runtime Checking → C-RUN and make sure it is enabled.

  3. Make sure the following checks are enabled:

crun-arith-checks-enabled

  1. Click OK to close the Project Options dialog box.

  2. Choose Debug → Download and Debug (Ctrl+D) to start executing the application.

  3. The C-SPY Debugger will hit a breakpoint at main(). Press F5 to resume the program execution.

The execution will Stop, with the following line of code highlighted:

image

During the debug session, every time the application hits a statement causing a runtime error, C-RUN will halt the execution.

crun-messages-arith

In addition, the C-RUN Messages window (View → C-RUN → Messages) will show detailed information about the root cause alongside the associated call stack. Clicking on the call stack will help you to navigate throughout the application's source code.

  1. Press F5 repeatedly to resume the program execution and examine the remaining detected C-RUN messages until the execution ends.

crun-messages-arith-all

  1. Stop the debug session (Ctrl+Shift+D).

Fine-tuning arithmetic checks

There are programing situations in which taking advantage of the wraparound property of overflown unsigned integers is beneficial and efficient. In such cases, specific checks can simply be deselected. Disabling the checks you do not need in your application will generally reduce the code size used by the instrumentation and execute faster.

In the project's options, disable the following C-RUN checks:

  • Including unsigned
  • Including explicit casts
  • Including unsigned shifts

Rebuild the application, Download and Debug (Ctrl+D), and inspect the changes in the error detection.

Tweaking the rules

By default, C-RUN stops at each detected error. In the C-RUN Messages window, the Default action can be switched to Log or to Ignore.

C-RUN Messages can also be filtered by rules. For details, refer to Creating rules for messages.

Bounds checking

The second example explores the Bounds Checking capabilities provided by C-RUN.

To run this example, do this:

  1. With a right-click, set the Bounds-checking project as active.

set-project-as-active

  1. Choose Debug → Download and Debug (Ctrl+D) to start executing the application.

  2. After the execution reaches the breakpoint in the main() function, resume the execution (F5).

Note how the application finishes executing (exit()) without any apparent errors of any kind.

  1. Stop the debug session (Ctrl+Shift+D).

  2. Choose Project → Options (Alt+F7) → Runtime Checking → C-RUN and Enable bounds checking:

bounds-checking

  1. Rebuild and run the project.

image

Note that now C-RUN highlighted an out-of-bounds access for *(ap+2). However, the execution stopped earlier, at the first printf() statement. The reason is that the compiler determines that pointer addresses used as parameters for those printf() calls are related and, with that, C-RUN efficiently can test them in one go.

  1. Press F5 to resume the execution and inspect the remaining C-RUN Message:

image

The program will stop at the last statement, indicating that the assignment is performed out of bounds. From a bounds-checking perspective, dynamically allocated memory is no different from local pointers, static buffers, or buffers on the stack.

Optimizing the Global Bounds Table

When performing bounds checking, pointers accessed through other pointers must have information in a global bounds table stored in memory. The table size is defined by the Number of entries field.

Caution

Make sure to set the Number of entries. Leaving this field empty will result in a table with 4000 entries.

Tip

The number of entries you need to keep in the table is often fairly low, so you might want to experiment with shrinking it in your own project. Shrinking the table will result in reduced code size required by the C-RUN instrumentation in your application. Whenever the chosen Number of entries is too low, C-RUN will warn you that "the global bounds table is running out of slots".

  1. Choose Project → Options (Alt+F7) → Runtime Checking → C-RUN.

  2. Under Bounds checking verify the Number of entries field.

  3. Set the Number of entries to 1 and close the Project Options dialog box.

  4. Rebuild the aplication then Download and Debug (Ctrl+D).

Since there is only one pointer in this example, a single entry in the global bounds table is enough.

Bounds checking and libraries

In scenarios where the main project relies on pre-built (third-party) libraries, bounds checking requires extra consideration for shared pointers.

The project Bounds-checking+libs is a modified version of the Bounds-checking project. The functionality available from the IntMax.c file was moved to a Library project that produced a static library named MaxLib.a, pre-built with no C-RUN bounds-checking instrumentation, typical for third-party libraries where the code cannot be changed.

When you use pointers and pointer arguments between the instrumented application code and the non-instrumented library code, you must inform the compiler (and linker) that functions in the library code do not have bounds-checking information. The best way to do so is to use the #pragma default_no_bounds directive when including a library header, to inform the compiler that the library was not built with C-RUN Bounds-checking information:

image

Building without pointer checking from non-instrumented code

In most cases, returned pointers will not be equipped with bounds-checking instrumentation but will have associated bounds that are always "large enough" to accommodate them. In other words, this means that pointers originating from your code will be checked, but not pointers from the library. Under normal circunstances this should be perfectly acceptable. The process is non-intrusive in terms of code changes.

To run this example's build configuration, do this:

  1. Set the Bounds-checking+libs project as active.
  2. Use the Workspace selector and choose the "DoNotCheckPointersFromNonInstrumentedCode" build configuration.
image
  1. Choose Project → Options (Alt+F7) → Runtime Checking → C-RUN and confirm these settings:

image

  1. Close the Project Options dialog box, and choose Debug → Download and Debug (Ctrl+D) to start executing the application.

You should get no C-RUN errors, or any other indications that something is wrong. In the DoNotCheckPointersFromNonInstrumentedCode build configuration, turning off bounds-checking information for library headers worked well.

  1. Stop the debug session (Ctrl+Shift+D).

Building with pointer checking from non-instrumented code

The CheckPointersFromNonInstrumentedCode build configuration demonstrates a situation where it is desirable to have bounds checking for pointers and returned pointers defined in the library code.

To run this example's build configuration, do this:

  1. Make sure the Bounds-checking+libs project is set as active.
  2. Switch to the CheckPointersFromNonInstrumentedCode build configuration.
image
  1. Choose Project → Options (Alt+F7) → Runtime Checking → C-RUN and confirm these settings:
image
  1. Build the application and run it again. This time you should see one C-RUN message for the third printf() statement.

Read the source code and compare the use of __as_make_bounds() for the pointer ap to how the bounds are set for the pointer used in the next printf() statement. We have also defined a project-specific macro to control the use of __as_make_bounds(). This built-in function is used when the returned pointer must be given sensible bounds. If no bounds are given for returned pointers, a bounds error will be generated on the first access made to the pointer. Note that this build configuration defines a preprocessor symbol called CONFIG that conditionally compiles with __as_make_bounds() calls to give pointers sensible bounds.

  1. Comment out one of the calls to the CRUN_MAKE_BOUNDS() macro, rebuild and run.

❔ Did it change the output in the C-RUN Messages window?

Heap checking capabilities

C-RUN can check for errors in how heap memory is being used. Heap checking can catch when the application tries to use already freed memory, non-matching deallocation attempts, and leaked heap blocks.

When you use heap checking, each memory block is expanded with bookkeeping information and a buffer area, so that the blocks as seen by the application are not located side-by-side.

The various checker functions examine the bookkeeping information and the buffer areas and report violations of correct heap usage.

To run this example, do this:

  1. Set the Heap project as active.

  2. Choose Project → Options (Alt+F7) → Runtime Checking → C-RUN.

  3. Make sure that Use checked heap is enabled:

image
  1. Choose Debug → Download and Debug (Ctrl+D) to start executing the application.

  2. Examine the source code comments for each reported error.

image
  1. Stop the debug session (Ctrl+Shift+D).

Note

  • Using heap checking makes it much easier to find heap usage errors, but it is not fail-safe.
  • Heap checking and bounds checking can complement each other in identifying dynamic memory usage errors. However, because of the potential impact in terms of performance and overhead, you are advised not to enable both at the same time.
  • The function HeapFunc3() in Heap.c can be enabled by uncommenting the CRUN_FULL_EDITION macro definition. Including the function exceeds the code size limitation in the trial mode. For unlocking such a limitation, contact us.

Using C-RUN in non-interactive mode

There are scenarios in which might not be possible to debug an application built with C-RUN information directly from the IDE. Below you will find some examples on how to use C-RUN in non-interactive mode.

C-RUN Runtime Analysis from the command line

The IAR C-SPY Command Line Utility (CSpyBat) can run applications directly from the command line. This utility is suitable for non-interactive debugging and can be used in conjunction with IAR C-RUN where runtime analysis is desired. One typical scenario for considering CSpyBat is within automated tests from a continuous integration environment.

  1. Close the IDE, launch a terminal and change to the project directory (e.g., arm):
cd /path/to/crun-walkthrough/arm

Tip

The IDE automatically generates scripts for running CSpyBat under the settings/ sub-directory. In the latest IDE version, the relevant files are:

File Description
launch.json JSON file with launch configurations for all projects in the workspace.
<project>.<cfg>.cspy_launch_json.{bat|ps1|sh} Scripts for launching CSpyBat from the corresponding terminal/shell.

These scripts inherits your project settings. They are ready to run with C-RUN from the command line.

  1. Execute the script corresponding to your terminal. For example, on Linux Bash, execute:
$ ./settings/Heap.Debug.cspy_launch_json.sh

     IAR C-SPY Command Line Utility V9.5.3.2051
     Copyright 2026 IAR Systems AB.

Heap usage error @ 0x2222 Core: 0
The address 0x20001249 does not appear to be the start of a heap block.
Call Stack:
    HeapFunc1 in "/home/user/crun-walkthrough/common/Heap.c", 32:3 - 32:10
    main in "/home/user/crun-walkthrough/common/Heap.c", 101:3 - 101:13
    [_call_main + 0xd]
Heap usage error @ 0x2228 Core: 0
The address 0x20001208 does not appear to be the start of a heap block.
Call Stack:
    HeapFunc1 in "/home/user/crun-walkthrough/common/Heap.c", 34:3 - 34:10
    main in "/home/user/crun-walkthrough/common/Heap.c", 101:3 - 101:13
    [_call_main + 0xd]
Heap usage error @ 0x222e Core: 0
The address 0x20001249 does not appear to be the start of a heap block.
Call Stack:
    HeapFunc1 in "/home/user/crun-walkthrough/common/Heap.c", 35:1 - 35:1
    main in "/home/user/crun-walkthrough/common/Heap.c", 101:3 - 101:13
    [_call_main + 0xd]
Out of heap space @ 0x223a Core: 0
There is no more heap space to allocate.
A request for 4120 bytes could not be satisfied.
A total of 36 bytes have been allocated in 1 heap blocks.
Call Stack:
    HeapFunc2 in "/home/user/crun-walkthrough/common/Heap.c", 44:3 - 44:9
    main in "/home/user/crun-walkthrough/common/Heap.c", 102:3 - 102:13
    [_call_main + 0xd]

     CSpyBat terminating.

Issues

For technical support contact IAR Customer Support.

For questions or suggestions related to this tutorial: try the wiki or check earlier issues. If those don't help, create a new issue with detailed information.