主要内容

Implement Exceptions in User-Defined Defects

In constructing user-defined defects, you can define exceptions to defects. An exception is a circumstance where the conditions for the defect are satisfied, but you do not want the defect to be reported. Such exceptions can make your defect more relevant for your use cases and make it easier to review results. This topic shows how you can add an exception to your defect. For more information on developing user-defined defects:

User-Defined Defect with False Positive Result

Consider a user-defined defect return_not_checked that checks if the return value of a function is immediately discarded and not explicitly cast to void:

defect return_not_checked =
when
     Cpp.CallSite.is(&CS)
	and CS.immediatelyDiscarded()
	and not CS.explicitlyCastToVoid()
	and CS.toString(&name)
raise "Return value immediately discarded: \"{name}\""
on CS
This defect reports all such functions. For example, in this code, the defect is reported six times:
#include <iostream>

#define DEBUG_MODE true

int getValue() { return 42; }  
int compute() { return 100; } 
int calculate() { return 200; } 
int debugLog(const char *msg)
{
    std::cout << msg << std::endl; //defect
    return 0;
}

struct Math
{
    int add(int a, int b) { return a + b; }
    int multiply(int a, int b) { return a * b; }
};

int main()
{
    Math m;
    // Discarded function calls
    getValue(); //defect
    compute(); //defect
    m.add(5, 10); //defect
    m.multiply(3, 4); //defect
    // Explicitly cast to void
    (void)calculate();
    (void)m.add(1, 2);
    // Assigned to variables
    int result = getValue();
    int sum = m.multiply(2, 3);
    // Debug function - return value SHOULD be discarded
    if (DEBUG_MODE)
    {
        debugLog("Debug message"); //defect
    }
    return 0;
}
The defect is reported on all functions with return values that are not checked. Some functions in the preceding code are called to make use of their side-effects and their return value is not useful. For example, the function debugLog is used for debugging and always returns 0. To exclude such functions from your result, implement an exception to the in the defect definition.

Define Exception

Use the except statement to create an exception for the defect:

defect inside_compound_check =
when
     Cpp.CallSite.is(&CS)
	and CS.immediatelyDiscarded()
	and not CS.explicitlyCastToVoid()
	and CS.toString(&name)
	except returnNotImportant(CS)
raise "Return value immediately discarded: \"{name}\""
on CS
The exception is triggered when the predicate returnNotImportant is satisfied:
predicate returnNotImportant(Cpp.CallSite.CallSite CS){
	return CS.callee(&f) and f.name(&name) and name.startsWith("debug")
}
This predicate evaluates to true if the invoked function has a name that stars with the string debug. After running a an analysis with this defect, the violation on debugLog() is no longer reported.

See Also

Topics