Understanding volatile access warnings

Every now and then, an interesting compiler warning will pop that make developers scratch their head in wonder. One such warning is the

” undefined behavior: the order of volatile accesses is undefined in this statement”

Road Sign - Warning

An example of this warning pops up in a FreeRTOS port using the IAR Workbench toolchain in a statement similar to

if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )

All that is happening here is two identifiers are being checked for equivalence. So what exactly is going on here? What is the undefined behavior? The problem is that on both sides of the relational operator (==) are volatile identifiers. The order of evaluation of volatiles is undefined in C! The compiler doesn’t know if it should process  uxCurrentNumberOfTasks or listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) first.

In this example a developer might decide that it doesn’t matter but there could be cases where reading a register causes a flag to be reset elsewhere which could affect the state of the system. The order of evaluation, right-to-left or left-to-right has the potential to change the result of the statement. (PC-Lint users may recognize this as message 564 ‘Symbol’ depends on order of evaluation).

Resolving this type of warning is relatively simple in most cases. The primary solution is to not evaluate and/or modify multiple volatile variables in the same statement. For example, rather than evaluate uxCurrentNumberOfTasks and listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) in one statement, two local variables can be created to store their value and those variables can be compared. The code changes from:

if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )

to:

unsigned portBASE_TYPE ListCurrentLength = listCURRENT_LIST_LENGTH( &xSuspendedTaskList);
unsigned portBASE_TYPE CurrentNumberOfTasks = uxCurrentNumberOfTasks;

if( ListCurrentLength == CurrentNumberOfTasks)

What the change does is it allows the programmer to decide on the order in which the volatile variables will be evaluated. In the above case  listCURRENT_LIST_LENGTH( &xSuspendedTaskList) is evaluated first and then uxCurrentNumberOfTasks. Recompiling the code verifies that indeed the warning of ” undefined behavior: the order of volatile accesses is undefined in this statement” is no longer an issue.

Solving the mystery of the warning required a little bit of extra work but in the end we have an application that consists of only defined behavior and the potential for one less bug that can come back and bite us later.

 

(Thanks to Dan Smith for his insights and discussion related to this interesting warning message!)

 

Share >

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.