From 2a884446be3736af700fccecadb36fefda7a937f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 15 Jul 2013 21:58:29 +0200 Subject: [PATCH] Library: document not-null and not-uninit argument configuration --- lib/library.cpp | 20 +++++--- lib/library.h | 41 ++++++++-------- man/manual.docbook | 119 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 124 insertions(+), 56 deletions(-) diff --git a/lib/library.cpp b/lib/library.cpp index 39a59c735..141f51157 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -91,14 +91,18 @@ bool Library::load(const char path[]) _noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0); else if (strcmp(functionnode->Name(),"arg")==0 && functionnode->Attribute("nr") != NULL) { const int nr = atoi(functionnode->Attribute("nr")); - - const char *nullpointer = functionnode->Attribute("nullpointer"); - const char *uninitdata = functionnode->Attribute("uninitdata"); - const char *uninitderefdata = functionnode->Attribute("uninitderefdata"); - - functionArgument[name][nr].nullpointer = (nullpointer != NULL); - functionArgument[name][nr].uninitdata = (uninitdata != NULL); - functionArgument[name][nr].uninitderefdata = (uninitderefdata != NULL); + bool notnull = false; + bool notuninit = false; + for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) { + if (strcmp(argnode->Name(), "not-null") == 0) + notnull = true; + else if (strcmp(argnode->Name(), "not-uninit") == 0) + notuninit = true; + else + return false; + } + functionArgument[name][nr].notnull = notnull; + functionArgument[name][nr].notuninit = notuninit; } else return false; } diff --git a/lib/library.h b/lib/library.h index c4087a82f..80b1595d4 100644 --- a/lib/library.h +++ b/lib/library.h @@ -72,23 +72,22 @@ public: } struct Argument { - bool nullpointer; - bool uninitdata; - bool uninitderefdata; + bool notnull; + bool notuninit; }; // function name, argument nr => argument data std::map > functionArgument; - bool isnullargbad(const std::string &functionName, int argnr) const { - const Argument *arg = getarg(functionName,argnr); - return arg && arg->nullpointer; - } + bool isnullargbad(const std::string &functionName, int argnr) const { + const Argument *arg = getarg(functionName,argnr); + return arg && arg->notnull; + } - bool isuninitargbad(const std::string &functionName, int argnr) const { - const Argument *arg = getarg(functionName,argnr); - return arg && arg->uninitdata; - } + bool isuninitargbad(const std::string &functionName, int argnr) const { + const Argument *arg = getarg(functionName,argnr); + return arg && arg->notuninit; + } std::set returnuninitdata; @@ -98,16 +97,16 @@ private: std::map _dealloc; // deallocation functions std::map _noreturn; // is function noreturn? - const Argument * getarg(const std::string &functionName, int argnr) const { - std::map >::const_iterator it1; - it1 = functionArgument.find(functionName); - if (it1 != functionArgument.end()) { - const std::map::const_iterator it2 = it1->second.find(argnr); - if (it2 != it1->second.end()) - return &it2->second; - } - return NULL; - } + const Argument * getarg(const std::string &functionName, int argnr) const { + std::map >::const_iterator it1; + it1 = functionArgument.find(functionName); + if (it1 != functionArgument.end()) { + const std::map::const_iterator it2 = it1->second.find(argnr); + if (it2 != it1->second.end()) + return &it2->second; + } + return NULL; + } int getid(const std::map &data, const std::string &name) const { const std::map::const_iterator it = data.find(name); diff --git a/man/manual.docbook b/man/manual.docbook index 58a24d282..ffaaa9ac6 100644 --- a/man/manual.docbook +++ b/man/manual.docbook @@ -706,12 +706,13 @@ Checking test.c... Cppcheck has internal knowledge about how standard C/C++ functions work. There is no internal knowledge about how - various libraries and environments work. Cppcheck can - however be told how libraries and environments work by using configuration - files. + all libraries and environments work, and there can't be. + Cppcheck can be told how libraries and environments + work by using configuration files. - The idea is that users will be able to download configuration files - for all popular libraries and environments here: + The idea is that users will be able to download library + configuration files for all popular libraries and environments + here: http://cppcheck.sourceforge.net/archive @@ -733,9 +734,10 @@ Checking test.c...
<alloc> and <dealloc> - Allocation and deallocation is defined within - <memory> or <resource> using - <alloc> and <dealloc>. + Allocation and deallocation is defined using + <alloc> and <dealloc>. These are used inside inside + <memory> or + <resource>. Here is example code: @@ -765,33 +767,23 @@ Checking test.c... </memory> </def> + That tells Cppcheck that alloc_something + allocates memory and that the matching deallocation function is + free_something. + Output from Cppcheck: # cppcheck --library=something.cfg test.c Checking test.c... [test.c:10]: (error) Memory leak: p - - Some allocation functions initialize the allocated data. Others - don't. Here is a short code example: - - void f() -{ - char *p = alloc_something(); - char c = *p; - free_something(); -} - - If alloc_something() initializes the memory that is allocated then - that code is OK. Otherwise that code is bad. To configure that - -
<ignore> and <use> - The <ignore> and <use> tells Cppcheck how functions - uses allocated memory. Example code: + The <ignore> and + <use> tells Cppcheck how functions uses + allocated memory. Example code: void f() { @@ -840,7 +832,7 @@ Checking test.c...
- <alloc init="false"> + allocate but not initialize Some allocation function initialize the data, others don't. Here is a example code: @@ -852,6 +844,11 @@ Checking test.c... free_something(); } + No error is reported: + + # cppcheck --library=something.cfg test.c +Checking test.c... + Here is a configuration that tells cppcheck that alloc_something doesn't initialize the data: @@ -865,11 +862,79 @@ Checking test.c... Now you will get this error message: - daniel@dator:~/cppcheck$ ./cppcheck --library=something.cfg test.c + # cppcheck --library=something.cfg test.c Checking test.c... [test.c:4]: (error) Memory is allocated but not initialized: p
+
+ function arguments: null pointers + + You can define if a function parameter can be NULL or if it must + be non-NULL. + + Example code: + + void do_something(char *p); + +void f() +{ + do_something(NULL); +} + + Normally no error is reported for that code. + + But if the do_something() parameter should be non-NULL you can use + this configuration: + + <?xml version="1.0"?> +<def> + <function name="do_something"> + <arg nr="1"> + <not-null/> + </arg> + </function> +</def> + + Now the output from cppcheck is: + + # cppcheck --library=something.cfg test1.c +Checking test1.c... +[test1.c:5]: (error) Null pointer dereference +
+ +
+ Function arguments: uninitialized data + + Here is example code: + + void do_something(char *p); + +void f() +{ + char str[10]; + do_something(str); +} + + Normally Cppcheck doesn't report any error + message for that. However if the parameter must be initialized there is + a problem. Here is a configuration that says that the parameter must be + initialized: + + <?xml version="1.0"?> +<def> + <function name="do_something"> + <arg nr="1"> + <not-uninit/> + </arg> + </function> +</def>Now the cppcheck output is: + + # cppcheck --library=something.cfg test1.c +Checking test1.c... +[test1.c:6]: (error) Uninitialized variable: str +
+
no return