Besides the many out-of-the-box checkers that Codesonar presents for detecting a wide range of coding errors, there are several mechanisms provided for defining your own checkers.

The most powerful is the Codesonar Plugin API, which is available in either  Scheme or C.

When active, your checkers behave just like any other Codesonar checker: they execute during Codesonar’s normal analysis phase, detected cases are listed along with the built in checkers, and they produce warning reports using the same source code annotations. In summary they become indistinguishable from Codesonar’s own built in checks.

A custom checker comprises boiler-plate code and user defined sections. For brevity, below is the user defined part of a checker that simply counts the number of return statements and generates a warning if they exceed a predefined limit.

1 static void check_if_return(cs_pdg pdg, void *ctx)

2{

3               int retCount = 0;

4               cs_pdg_kind pdgKind;

5               cs_result r;

6               cs_string procName;

7               cs_const_string procType;

8               cs_size_t procSize, nu;

9               cs_const_pdg_vertex_set pdgVertexSet;

10            cs_pdg_vertex firstPdgVertex, pdgVertex;

11            cs_pdg_vertex_set_iter pdgVertexSetIterator;

12            pdgKind = cs_pdg_get_kind(pdg);

// we only want user defined procedure types to be considered; ignore 3rd party API’s

14            if (pdgKind != cs_pdg_kind_user_defined)

15                              return;

// lines 16 – 19 get the human readable name of the function the analysis is currently sat on

16            r = cs_pdg_kind_name(pdgKind, &procType);

17            r = cs_pdg_friendly_name(pdg, NULL, procSize, &procSize);

18            procName = malloc(procSize * sizeof(char));

19            r = cs_pdg_friendly_name(pdg, procName, procSize, &nu);

// lines 20 – 21 get the sequence of vertices (program statements) for the current function and provide an iterator

20            r =  cs_pdg_vertices ( pdg, &pdgVertexSet);

21            r = cs_pdg_vertex_set_iter_first (pdgVertexSet, &firstPdgVertex, &pdgVertexSetIterator );

// lines 22 – 28 check if the current vertex is a return statement, incrementing a simple global count for each one detected.

22            if (cs_pdg_vertex_kind(firstPdgVertex) == cs_vertex_kind_return)

23                              retCount++;

24            while (cs_pdg_vertex_set_iter_next (&pdgVertex, &pdgVertexSetIterator) != CS_OUT_OF_ELEMENTS)

25            {

26                              if (cs_pdg_vertex_kind(pdgVertex) == cs_vertex_kind_return)

27                                                retCount++;

28            }

29            cs_pdg_vertex_set_iter_close(&pdgVertexSetIterator);

// lines 30 – 39 are responsible for checking whether the return count for this function has been exceed, and if so, create and issue a warning

30            if (retCount > MAXRETURNS)

31            {

32                              cs_pdg_vertex entryVertex;

33                              char * buf;

34                              r =  cs_pdg_entry_vertex (pdg, &entryVertex);

35                              buf = malloc(strlen(procName) + 4 + strlen(“%s contains %d return statement(s)”));

36                              sprintf(buf, “%s contains %d return statement(s)”, procName, retCount);

37                              csonar_report_warning(entryVertex, upvar, buf, csrf_none, NULL, NULL);

38                              free(buf);

39            }

40  free(procName);

41 }

Having compiled and copied the resulting library to the Codesonar installation directory, here’s how an instance of this warning would be listed in the set of detected warnings:

1

And when clicking into the above “Too many Return statements” warning, here is how Codesonar would present the annotated source code:

2

Note, how and what annotations are included is dictated by how the custom checker is authored; in this case the above was deemed sufficient.