|
Data Flow Analysis - Usage and LimitationsHandling of Data TypesStructs and unions in C/C++ along with classes in C++ together make up a set of symbol types called aggregate variables. Several of the Task Flow Check reports have options to control how these aggregate variables are reported. If you include the Container Summary through the report options, then any member of an aggregate variable can contribute to the container variable summary. For example, if one member of a struct is set in one task and a different member of the same struct is set in another task, then no members will showing up in the Variables Set in Multiple Tasks report but the containing struct variable will.On the other hand, arrays are treated as single variables by these reports. This is because array indices can be dynamic expressions. Therefore, generally it is not possible to distinguish which array component has been assigned. Through the "Analyze Union/Bitfield Members Separately" option, you control how the analysis will treat members that are part of a union or bitfield. When enabled, union members are tracked as separate independent variables like they would be in a struct. When disabled, the members are considered to be the same variable, as with an array. In the latter case, an assignment to a union member un.member1 is translated into assignments to all union members, such as un.member2, etc. This option also applies to bitfields. In typical computer architectures, assigning a bitfield requires updating the whole word or byte in memory. The assignment could therefore impact the other neighboring bitfields if there is concurrent assignment to another bitfield from another task. As much as is feasible via static analysis, these reports track which objects are referenced by pointers. Pointers or reference parameters track their actual parameter variables and derive potential changes that way. Pointers set to an array and used to index through an array cause the array to be modified. These reports assume "clean" pointer usage, i.e. pointers are set to a certain variable and operate just on that variable but don't use side effects to access independent variables which are allocated in neighboring memory areas.
Handling of Function PointersWhen analyzing source code that uses function pointers to make calls, these reports track all possible assignments to that pointer throughout the whole program. They then assume that for any call through a function pointer, any one of the possible functions found in the global analysis could be called. This will most likely extend the scope of any reports beyond what actual results would be. For example, if function pointer variable fp is set to func1 in one task, then called, then set to func2 in another task and called, these reports assume that both func1 and func2 are called in both tasks. Hence, any global variables set in either func1 or func2 will show up under both tasks. This generalization of calls through function pointers applies to all reports where function pointers play a role:
Note that with the exception of the Useless Assignments report, these extraneous reported instances are false positives but the reports would not miss any true negatives.
In tracking calls through function pointers, the default behavior of the source code analyzer is to only record assignments to pointers that have a function pointer type. Sometimes, an application will also use "void *" pointers to store function pointers. In such cases, you can add the source analyzer option
Analysis MessagesCertain of the Flow Check reports may contain the warning:
Statement or partial statement in file.x line xx not reachable and eliminated from analysisThese warnings do not indicate a problem with the data flow analysis. They simply flag any lines of code which are not reachable, in case that is an unintended situation. The unreachable lines are also the focus of the Unreachable Statements report, and occur in the following cases:
The warning message would be issued for the indicated lines in this example:
#define TRUE 1 #define TEST TRUE void funcA () { int condition1, condition2; if (TEST) { funcB(); } else { not_reached_due_to_condition(); /* flagged as unreachable */ } while (condition1) { if (condition2) return; else continue; occurs_after_control_transfer(); /* flagged as unreachable */ } return; } Memory RequirementsAnalyzing data flow within function control logic and across function boundaries, the Flow Check Reports are very compute intensive. Both time and memory consumption can be large, even for medium-sized programs.Memory requirements can extend beyond the 2 or 4 GB limitation of a 32-bit operating system. To handle larger projects, it's recommended that you use of 64-bit versions of Imagix 4D on 64-bit operating systems and assign 16 GB of virtual memory, with at least 8 GB and preferably 16 GB of physical memory. In addition, Imagix 4D data flow engine includes its own virtual memory system. Memory used for the data flow analysis is paged to a hard drive. This is described in more detail in Project Resources.
|