Library: document not-null and not-uninit argument configuration
This commit is contained in:
parent
24dfc052e2
commit
2a884446be
|
@ -91,14 +91,18 @@ bool Library::load(const char path[])
|
||||||
_noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0);
|
_noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0);
|
||||||
else if (strcmp(functionnode->Name(),"arg")==0 && functionnode->Attribute("nr") != NULL) {
|
else if (strcmp(functionnode->Name(),"arg")==0 && functionnode->Attribute("nr") != NULL) {
|
||||||
const int nr = atoi(functionnode->Attribute("nr"));
|
const int nr = atoi(functionnode->Attribute("nr"));
|
||||||
|
bool notnull = false;
|
||||||
const char *nullpointer = functionnode->Attribute("nullpointer");
|
bool notuninit = false;
|
||||||
const char *uninitdata = functionnode->Attribute("uninitdata");
|
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
|
||||||
const char *uninitderefdata = functionnode->Attribute("uninitderefdata");
|
if (strcmp(argnode->Name(), "not-null") == 0)
|
||||||
|
notnull = true;
|
||||||
functionArgument[name][nr].nullpointer = (nullpointer != NULL);
|
else if (strcmp(argnode->Name(), "not-uninit") == 0)
|
||||||
functionArgument[name][nr].uninitdata = (uninitdata != NULL);
|
notuninit = true;
|
||||||
functionArgument[name][nr].uninitderefdata = (uninitderefdata != NULL);
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
functionArgument[name][nr].notnull = notnull;
|
||||||
|
functionArgument[name][nr].notuninit = notuninit;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,23 +72,22 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Argument {
|
struct Argument {
|
||||||
bool nullpointer;
|
bool notnull;
|
||||||
bool uninitdata;
|
bool notuninit;
|
||||||
bool uninitderefdata;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// function name, argument nr => argument data
|
// function name, argument nr => argument data
|
||||||
std::map<std::string, std::map<int, Argument> > functionArgument;
|
std::map<std::string, std::map<int, Argument> > functionArgument;
|
||||||
|
|
||||||
bool isnullargbad(const std::string &functionName, int argnr) const {
|
bool isnullargbad(const std::string &functionName, int argnr) const {
|
||||||
const Argument *arg = getarg(functionName,argnr);
|
const Argument *arg = getarg(functionName,argnr);
|
||||||
return arg && arg->nullpointer;
|
return arg && arg->notnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isuninitargbad(const std::string &functionName, int argnr) const {
|
bool isuninitargbad(const std::string &functionName, int argnr) const {
|
||||||
const Argument *arg = getarg(functionName,argnr);
|
const Argument *arg = getarg(functionName,argnr);
|
||||||
return arg && arg->uninitdata;
|
return arg && arg->notuninit;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> returnuninitdata;
|
std::set<std::string> returnuninitdata;
|
||||||
|
|
||||||
|
@ -98,16 +97,16 @@ private:
|
||||||
std::map<std::string, int> _dealloc; // deallocation functions
|
std::map<std::string, int> _dealloc; // deallocation functions
|
||||||
std::map<std::string, bool> _noreturn; // is function noreturn?
|
std::map<std::string, bool> _noreturn; // is function noreturn?
|
||||||
|
|
||||||
const Argument * getarg(const std::string &functionName, int argnr) const {
|
const Argument * getarg(const std::string &functionName, int argnr) const {
|
||||||
std::map<std::string, std::map<int, Argument> >::const_iterator it1;
|
std::map<std::string, std::map<int, Argument> >::const_iterator it1;
|
||||||
it1 = functionArgument.find(functionName);
|
it1 = functionArgument.find(functionName);
|
||||||
if (it1 != functionArgument.end()) {
|
if (it1 != functionArgument.end()) {
|
||||||
const std::map<int,Argument>::const_iterator it2 = it1->second.find(argnr);
|
const std::map<int,Argument>::const_iterator it2 = it1->second.find(argnr);
|
||||||
if (it2 != it1->second.end())
|
if (it2 != it1->second.end())
|
||||||
return &it2->second;
|
return &it2->second;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getid(const std::map<std::string,int> &data, const std::string &name) const {
|
int getid(const std::map<std::string,int> &data, const std::string &name) const {
|
||||||
const std::map<std::string,int>::const_iterator it = data.find(name);
|
const std::map<std::string,int>::const_iterator it = data.find(name);
|
||||||
|
|
|
@ -706,12 +706,13 @@ Checking test.c...
|
||||||
|
|
||||||
<para><literal>Cppcheck</literal> has internal knowledge about how
|
<para><literal>Cppcheck</literal> has internal knowledge about how
|
||||||
standard C/C++ functions work. There is no internal knowledge about how
|
standard C/C++ functions work. There is no internal knowledge about how
|
||||||
various libraries and environments work. <literal>Cppcheck</literal> can
|
all libraries and environments work, and there can't be.
|
||||||
however be told how libraries and environments work by using configuration
|
<literal>Cppcheck</literal> can be told how libraries and environments
|
||||||
files.</para>
|
work by using configuration files.</para>
|
||||||
|
|
||||||
<para>The idea is that users will be able to download configuration files
|
<para>The idea is that users will be able to download library
|
||||||
for all popular libraries and environments here:</para>
|
configuration files for all popular libraries and environments
|
||||||
|
here:</para>
|
||||||
|
|
||||||
<para><uri>http://cppcheck.sourceforge.net/archive</uri></para>
|
<para><uri>http://cppcheck.sourceforge.net/archive</uri></para>
|
||||||
|
|
||||||
|
@ -733,9 +734,10 @@ Checking test.c...
|
||||||
<section>
|
<section>
|
||||||
<title><alloc> and <dealloc></title>
|
<title><alloc> and <dealloc></title>
|
||||||
|
|
||||||
<para>Allocation and deallocation is defined within
|
<para>Allocation and deallocation is defined <literal>using
|
||||||
<literal><memory></literal> or <literal><resource> using
|
<alloc> and <dealloc>. These are used inside inside
|
||||||
<alloc> and <dealloc>.</literal></para>
|
<literal><memory></literal> or
|
||||||
|
<literal><resource>.</literal></literal></para>
|
||||||
|
|
||||||
<para>Here is example code:</para>
|
<para>Here is example code:</para>
|
||||||
|
|
||||||
|
@ -765,33 +767,23 @@ Checking test.c...</programlisting>
|
||||||
</memory>
|
</memory>
|
||||||
</def></programlisting>
|
</def></programlisting>
|
||||||
|
|
||||||
|
<para>That tells Cppcheck that <literal>alloc_something</literal>
|
||||||
|
allocates memory and that the matching deallocation function is
|
||||||
|
<literal>free_something</literal>.</para>
|
||||||
|
|
||||||
<para>Output from <literal>Cppcheck</literal>:</para>
|
<para>Output from <literal>Cppcheck</literal>:</para>
|
||||||
|
|
||||||
<programlisting># cppcheck --library=something.cfg test.c
|
<programlisting># cppcheck --library=something.cfg test.c
|
||||||
Checking test.c...
|
Checking test.c...
|
||||||
[test.c:10]: (error) Memory leak: p</programlisting>
|
[test.c:10]: (error) Memory leak: p</programlisting>
|
||||||
|
|
||||||
<para>Some allocation functions initialize the allocated data. Others
|
|
||||||
don't. Here is a short code example:</para>
|
|
||||||
|
|
||||||
<programlisting>void f()
|
|
||||||
{
|
|
||||||
char *p = alloc_something();
|
|
||||||
char c = *p;
|
|
||||||
free_something();
|
|
||||||
}</programlisting>
|
|
||||||
|
|
||||||
<para>If alloc_something() initializes the memory that is allocated then
|
|
||||||
that code is OK. Otherwise that code is bad. To configure that </para>
|
|
||||||
|
|
||||||
<para/>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title><ignore> and <use></title>
|
<title><ignore> and <use></title>
|
||||||
|
|
||||||
<para>The <ignore> and <use> tells Cppcheck how functions
|
<para>The <literal><ignore></literal> and
|
||||||
uses allocated memory. Example code:</para>
|
<literal><use></literal> tells Cppcheck how functions uses
|
||||||
|
allocated memory. Example code:</para>
|
||||||
|
|
||||||
<programlisting>void f()
|
<programlisting>void f()
|
||||||
{
|
{
|
||||||
|
@ -840,7 +832,7 @@ Checking test.c...</programlisting>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title><alloc init="false"></title>
|
<title>allocate but not initialize</title>
|
||||||
|
|
||||||
<para>Some allocation function initialize the data, others don't. Here
|
<para>Some allocation function initialize the data, others don't. Here
|
||||||
is a example code:</para>
|
is a example code:</para>
|
||||||
|
@ -852,6 +844,11 @@ Checking test.c...</programlisting>
|
||||||
free_something();
|
free_something();
|
||||||
}</programlisting>
|
}</programlisting>
|
||||||
|
|
||||||
|
<para>No error is reported:</para>
|
||||||
|
|
||||||
|
<programlisting># cppcheck --library=something.cfg test.c
|
||||||
|
Checking test.c...</programlisting>
|
||||||
|
|
||||||
<para>Here is a configuration that tells cppcheck that alloc_something
|
<para>Here is a configuration that tells cppcheck that alloc_something
|
||||||
doesn't initialize the data:</para>
|
doesn't initialize the data:</para>
|
||||||
|
|
||||||
|
@ -865,11 +862,79 @@ Checking test.c...</programlisting>
|
||||||
|
|
||||||
<para>Now you will get this error message:</para>
|
<para>Now you will get this error message:</para>
|
||||||
|
|
||||||
<programlisting>daniel@dator:~/cppcheck$ ./cppcheck --library=something.cfg test.c
|
<programlisting># cppcheck --library=something.cfg test.c
|
||||||
Checking test.c...
|
Checking test.c...
|
||||||
[test.c:4]: (error) Memory is allocated but not initialized: p</programlisting>
|
[test.c:4]: (error) Memory is allocated but not initialized: p</programlisting>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>function arguments: null pointers</title>
|
||||||
|
|
||||||
|
<para>You can define if a function parameter can be NULL or if it must
|
||||||
|
be non-NULL.</para>
|
||||||
|
|
||||||
|
<para>Example code:</para>
|
||||||
|
|
||||||
|
<programlisting>void do_something(char *p);
|
||||||
|
|
||||||
|
void f()
|
||||||
|
{
|
||||||
|
do_something(NULL);
|
||||||
|
}</programlisting>
|
||||||
|
|
||||||
|
<para>Normally no error is reported for that code.</para>
|
||||||
|
|
||||||
|
<para>But if the do_something() parameter should be non-NULL you can use
|
||||||
|
this configuration:</para>
|
||||||
|
|
||||||
|
<programlisting><?xml version="1.0"?>
|
||||||
|
<def>
|
||||||
|
<function name="do_something">
|
||||||
|
<arg nr="1">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
|
</def></programlisting>
|
||||||
|
|
||||||
|
<para>Now the output from cppcheck is:</para>
|
||||||
|
|
||||||
|
<programlisting># cppcheck --library=something.cfg test1.c
|
||||||
|
Checking test1.c...
|
||||||
|
[test1.c:5]: (error) Null pointer dereference</programlisting>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Function arguments: uninitialized data</title>
|
||||||
|
|
||||||
|
<para>Here is example code:</para>
|
||||||
|
|
||||||
|
<programlisting>void do_something(char *p);
|
||||||
|
|
||||||
|
void f()
|
||||||
|
{
|
||||||
|
char str[10];
|
||||||
|
do_something(str);
|
||||||
|
}</programlisting>
|
||||||
|
|
||||||
|
<para>Normally <literal>Cppcheck</literal> 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:</para>
|
||||||
|
|
||||||
|
<para><programlisting><?xml version="1.0"?>
|
||||||
|
<def>
|
||||||
|
<function name="do_something">
|
||||||
|
<arg nr="1">
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
|
</def></programlisting>Now the cppcheck output is:</para>
|
||||||
|
|
||||||
|
<programlisting># cppcheck --library=something.cfg test1.c
|
||||||
|
Checking test1.c...
|
||||||
|
[test1.c:6]: (error) Uninitialized variable: str</programlisting>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>no return</title>
|
<title>no return</title>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue