CodeSonar C++ API
[For improved navigation, enable JavaScript.]
Comparison: C++ API vs C API

Table of Contents

This section compares and contrasts the C and C++ Plug-In APIs for CodeSonar.

Its main expected audience is users who have previously used the C API and are considering switching to the C++ API.

Users who plan to use the C++ API and have not previously used the C API do not need to read this page.

Comparison Factors

There are several primary factors that make the C++ API more convenient and safer than the C API.

If you avoid the following, it should be difficult to cause crashes in a C++ plug-in.

It is possible to cause uncaught exceptions, stack overflow, OOM, division by zero, and problems stemming from STL.

Code Examples

Task C++ C equivalent
Get the procedure containing a program point.
 
procedure container = pnt.get_procedure();
cs_result r;
cs_pdg container;
r = cs_pdg_vertex_pdg( pnt, &container );
if( r != CS_SUCCESS ) abort();

Invoke any function that returns a string
 
cout << "ast pretty prints as " << node.pretty_print() << endl;
// Common usage mistakes:
// null pointer derefs, buffer overruns, forgetting to check return
// codes for errors, leaking the buffer, uninitialized variable,
// use after free, double free, other memory management issues
size_t bn;
cs_result r;
char *buf = NULL;
r = cs_ast_pretty_print(node, NULL, 0, &bn);
if( r == CS_TRUNCATED )
{
buf = malloc( bn );
if( !buf ) abort();
}
else if( r != CS_SUCCESS )
abort();
r = cs_ast_pretty_print(node, buf, bn, &bn);
if( r != CS_SUCCESS ) abort();
printf( "ast pretty prints as %s\n", buf );
free(buf);

Invoke any function that returns a vector
 
std::vector<ast_field> vec = node.children();
size_t bn;
cs_result r;
cs_ast_field *buf = NULL;
r = cs_ast_children(node, NULL, 0, &bn);
if( r == CS_TRUNCATED )
{
buf = malloc( bn );
if( !buf ) abort();
}
else if( r != CS_SUCCESS )
abort();
r = cs_ast_children(node, buf, bn, &bn);
if( r != CS_SUCCESS ) abort();
free(buf);

Create and use an AST pattern that matches "x + K" for any integer literal K. Print K.
 
// Make it static so we only compile it once. Could be in top-level scope.
static ast_pattern pat("(c:+ :2 (c:integer-value :value ?K))");
ast_bindings bs = pat.match_with_bindings(node);
if( !bs ) cout << "No match!" << endl;
else cout << "Matched; K=" << bs["K"].as_int32() << endl;
cs_ast_pattern *pat;
cs_result r;
const char *err, *err_location;
cs_ast_binding bindings[1];
r = cs_ast_pattern_compile( "(c:+ :2 (c:integer-value :value ?K))", &pat, &err, &err_location );
if( r != CS_SUCCESS )
{
fprintf( stderr, "oops: %s near `%s'\n", err, err_location );
fflush(NULL);
abort();
}
r = cs_ast_match( node, pat, bindings, sizeof(bindings), &bn );
switch( r )
{
case CS_SUCCESS:
if( bn == sizeof(bindings) && bindings[0].f.type == csft_int32 )
printf( "Matched; K=%d\n", bindings[0].f._.int32 );
else
printf( "Type not int32?\n" );
break;
case CS_ELEMENT_NOT_PRESENT:
printf( "No match!\n" );
break;
default: abort();
}

Use an iterator
 
for( ast_iterator it = root_node.begin(); !it.at_end(); ++it )
{
ast node = *it;
// do stuff with node
}
cs_result r;
cs_ast_traverse_iter it;
for( r = cs_ast_iter_first( root_node, csatf_normal, &node, &it );
r == CS_SUCCESS;
r = cs_ast_iter_next( csatd_normal, &node, &it ) )
{
// do stuff with node
}
if( r != CS_OUT_OF_ELEMENTS ) abort();
r = cs_ast_iter_close( &it );
if( r != CS_SUCCESS ) abort();

Forward slice from main
 
cout << "Size is "
<< project::current().find_procedure("foo").points().forward_slice().size()
<< endl;
cs_pdg proc;
cs_result r;
cs_pdg_vertex_set vs, rs;
r = cs_pdg_find( "foo", &proc );
if( r != CS_SUCCESS ) abort();
r = cs_pdg_vertices( proc, &vs );
if( r != CS_SUCCESS ) abort();
r = cs_s_forward_slice( vs, cs_pdg_edge_kind_datacontrol, &rs );
if( r != CS_SUCCESS ) abort();
printf( "Size is %d\n", (int)cs_pdg_vertex_set_cardinality(rs) );

Links