JavaScript is not currently enabled, but is required for full CodeSonar manual search and browse functionality.
If you are viewing this file in your hub's Web GUI, enable JavaScript in your browser: you will also need it for GUI functionality.
If you opened this file directly from disk, your browser may be directly suppressing JavaScript functionality: certain browsers perform this suppression on local files (but not files delivered by web servers) for security reasons.
| CodeSonar® 9.0p0 Hot Tips | CONFIDENTIAL | CodeSecure Inc |
This tutorial example uses the CodeSonar C++ API to construct a check for expressions of const type being cast to non-const types using an AST Pattern.
CodeSonar SaaS Note: If you want to use your own custom plug-ins with CodeSonar SaaS, contact CodeSecure support for assistance. The installation instructions provided in this page are not sufficient to make plug-ins available to SaaS analyses.
File UnsafeCast_plugin.cpp is reproduced below.
// // Copyright (c) 2023, an unpublished work by CodeSecure, Inc. // ALL RIGHTS RESERVED // // Copyright (c) 2017-2023, an unpublished work by GrammaTech, Inc. // ALL RIGHTS RESERVED // // This software is furnished under a license and may be used and // copied only in accordance with the terms of such license and the // inclusion of the above copyright notice. This software or any // other copies thereof may not be provided or otherwise made // available to any other person. Title to and ownership of the // software is retained by CodeSecure, Inc. // // UnsafeCast_plugin.cpp // // A small example plugin that reports casts from const to non-const // types. // Must precede #include "csonar_api.hpp". #define CS_CPP_IMPL // Include the entire CodeSonar C++ API. #include "csonar_api.hpp" // for std::cout #include <iostream> // badcast is a new \warning class \ defined by this plug-in. It must be created in the // top level scope or in cs_plug_main(). static cs::warningclass badcast = cs::analysis::create_warningclass( "Cast from const to non-const", "", 1, cs::warningclass_flags::WARNING_POINT_IS_START_POINT, cs::warning_significance::SECURITY); // Visitors should be at the finest granularity that is appropriate // for the check: in this case, we are checking the AST associated // with a point. class check_cast: public cs::visitor<cs::point> { cs::ast_pattern *pattern; public: // The \AST pattern-matching functionality \ in the C++ API uses ast_pattern // objects, with the pattern specification passed as an // argument to the ast_pattern constructor. Note // that the pattern specification uses variables instead of // concrete values for the classes of the ASTs in the respective // :pointed-to fields: this check is not concerned with the exact // types involved in the cast, only in whether or not they are // consts. // The pattern can be broken down as follows: // (c:cast a normalized AST representing a cast... // :2 (?e ...of something... // :type (c:pointer ...that is a pointer... // :pointed-to (?c :is-const #t))) ...to some const type // :type (c:pointer and it's being cast to a pointer... // :pointed-to (?k :is-const #f))) ...to some non-const type // // Set up the pattern in the check_cast default constructor. check_cast(void): cs::visitor<cs::point>(){ try { pattern = new cs::ast_pattern( "(c:cast" " :2 (?e" " :type (c:pointer" " :pointed-to (?c :is-const #t)))" " :type (c:pointer" " :pointed-to (?k :is-const #f)))" ); } catch ( const cs::ast_pattern_compilation_error &e ) { std::cout << "*** problem compiling ast pattern" << std::endl; std::cout << "*** - pattern: " << e.get_pattern() << std::endl; std::cout << "*** - error: " << e.as_string() << std::endl; return; } } // Clean up the pattern in the check_cast destructor. ~check_cast(void){ delete pattern; } // CodeSonar will invoke this function on every program point in // the program. void operator()(cs::point pt) { try{ // Retrieve the procedure that contains pt. cs::procedure proc = pt.get_procedure(); // cs::point::get_procedure() // Check if the procedure was authored by the user. If not, // don't produce warnings about this code, since the user // probably isn't interested about warnings internal to // library models or synthesized procedures. if (proc.get_kind() != cs::procedure_kind::USER_DEFINED){ // cs::procedure::get_kind() return; } // Get the \normalized C/C++ AST\ associated with pt. If there isn't one // (for whatever reason), there is no point in proceeding. if (!pt.has_ast(cs::ast_family::C_NORMALIZED)) { // cs::point::has_ast() std::cout << "point has no normalized C/C++ AST" << std::endl; return; } cs::ast ptast = pt.get_ast(cs::ast_family::C_NORMALIZED); // cs::point::get_ast() // An offending cast might be nested inside other // expressions, so we need to check every subtree of ptast // against our pattern. for ( cs::ast_iterator it=ptast.traverse(); !it.at_end(); ++it){ // cs::ast::traverse() if (this->pattern->match(*it)){ // cs::ast_pattern::match() badcast.report(pt, "unsafe cast"); // cs::warningclass::report() return; } } } catch( const cs::result &r ) { std::cout << "*** check_cast_visitor exception: " << r << std::endl; } } }; // Create an instance of check_cast, and add it as a point visitor. // Visitors must be added either in the top-level scope or in // cs_plug_main(). static char dummy = (cs::analysis::add_point_visitor(new check_cast()), 0); // Every C++ plug-in for CodeSonar must define this function. static void cs_plug_main(void){} // All CodeSonar C++ plug-ins must finish with a line of this form (at // the top level). Note that the argument UnsafeCast_plugin to // CS_DEFINE_PLUGIN corresponds to the name of the compiled plug-in // (UnsafeCast_plugin.dll, UnsafeCast_plugin.so, or // UnsafeCast_plugin.bundle, depending on your system). CS_DEFINE_PLUGIN(UnsafeCast_plugin)
Build the plug-in into a library.
| Compiler | Command Line | Notes | |
|---|---|---|---|
| Windows | |||
| cl |
cl /LD /MD /EHsc
"/I%CSONAR%\codesonar\include"
"/I%CSONAR%\csurf\include" UnsafeCast_plugin.cpp "%CSONAR%\codesonar\lib\codesonar.lib" |
|
|
| Cygwin g++ |
Note: Cygwin g++ is only suitable for building
32-bit
CodeSonar plugins. Cygwin g++ only builds Cygwin binaries, so is
not suitable for building CodeSonar plug-ins. If you do not
have an alternative g++,
you will need to download and install one. One option is
mingw-w64.
|
|
|
| MinGW g++ |
g++ -shared
"-I$CSONAR\codesonar\include"
"-I$CSONAR\csurf\include" UnsafeCast_plugin.cpp -o UnsafeCast_plugin.dll "-L$CSONAR\codesonar\lib" -lcodesonar |
|
|
| All Other Systems We provide a full example for g++. For other compilers, build UnsafeCast_plugin.so from UnsafeCast_plugin.cpp, including $CSONAR/codesonar/include and $CSONAR/csurf/include. |
|||
| g++ |
g++ -fPIC -shared -o UnsafeCast_plugin.so
UnsafeCast_plugin.cpp
-I$CSONAR/codesonar/include -I$CSONAR/csurf/include |
|
|
See Writing C++ Plug-Ins For CodeSonar for further compilation details and troubleshooting hints.
Install the plug-in:
We have provided an extremely short example program to exercise the plug-in. You can also try building other programs into CodeSonar projects to see whether they contain these unsafe casts.
| with cl: |
codesonar analyze testcast host:port cl /c
testcast.c
|
|---|---|
| with gcc: |
codesonar analyze testcast host:port gcc -c
testcast.c
|
If you don't want to perform this check in future: