Library: added init attribute to <alloc>

This commit is contained in:
Daniel Marjamäki 2013-07-15 08:44:00 +02:00
parent 16d0a818c9
commit 66d8fa62d1
4 changed files with 99 additions and 25 deletions

View File

@ -54,8 +54,8 @@ static const Token * skipBrackets(const Token *tok)
class UninitVar : public ExecutionPath { class UninitVar : public ExecutionPath {
public: public:
/** Startup constructor */ /** Startup constructor */
explicit UninitVar(Check *c, const SymbolDatabase* db, bool isc) explicit UninitVar(Check *c, const SymbolDatabase* db, const Library *lib, bool isc)
: ExecutionPath(c, 0), symbolDatabase(db), isC(isc), var(0), alloc(false), strncpy_(false), memset_nonzero(false) { : ExecutionPath(c, 0), symbolDatabase(db), library(lib), isC(isc), var(0), alloc(false), strncpy_(false), memset_nonzero(false) {
} }
private: private:
@ -68,8 +68,8 @@ private:
void operator=(const UninitVar &); void operator=(const UninitVar &);
/** internal constructor for creating extra checks */ /** internal constructor for creating extra checks */
UninitVar(Check *c, const Variable* v, const SymbolDatabase* db, bool isc) UninitVar(Check *c, const Variable* v, const SymbolDatabase* db, const Library *lib, bool isc)
: ExecutionPath(c, v->varId()), symbolDatabase(db), isC(isc), var(v), alloc(false), strncpy_(false), memset_nonzero(false) { : ExecutionPath(c, v->varId()), symbolDatabase(db), library(lib), isC(isc), var(v), alloc(false), strncpy_(false), memset_nonzero(false) {
} }
/** is other execution path equal? */ /** is other execution path equal? */
@ -81,6 +81,9 @@ private:
/** pointer to symbol database */ /** pointer to symbol database */
const SymbolDatabase* symbolDatabase; const SymbolDatabase* symbolDatabase;
/** pointer to library */
const Library *library;
const bool isC; const bool isC;
/** variable for this check */ /** variable for this check */
@ -425,7 +428,7 @@ private:
} }
if (var2->isPointer()) if (var2->isPointer())
checks.push_back(new UninitVar(owner, var2, symbolDatabase, isC)); checks.push_back(new UninitVar(owner, var2, symbolDatabase, library, isC));
else if (var2->typeEndToken()->str() != ">") { else if (var2->typeEndToken()->str() != ">") {
bool stdtype = false; // TODO: change to isC to handle unknown types better bool stdtype = false; // TODO: change to isC to handle unknown types better
for (const Token* tok2 = var2->typeStartToken(); tok2 != var2->nameToken(); tok2 = tok2->next()) { for (const Token* tok2 = var2->typeStartToken(); tok2 != var2->nameToken(); tok2 = tok2->next()) {
@ -435,7 +438,7 @@ private:
} }
} }
if (stdtype && (!var2->isArray() || var2->nameToken()->linkAt(1)->strAt(1) == ";")) if (stdtype && (!var2->isArray() || var2->nameToken()->linkAt(1)->strAt(1) == ";"))
checks.push_back(new UninitVar(owner, var2, symbolDatabase, isC)); checks.push_back(new UninitVar(owner, var2, symbolDatabase, library, isC));
} }
return &tok; return &tok;
} }
@ -573,7 +576,8 @@ private:
return &tok; return &tok;
} }
if (Token::Match(tok.next(), "= malloc|kmalloc") || Token::simpleMatch(tok.next(), "= new char [")) { if (Token::Match(tok.next(), "= malloc|kmalloc") || Token::simpleMatch(tok.next(), "= new char [") ||
(Token::Match(tok.next(), "= %var% (") && library->returnuninitdata.find(tok.strAt(2)) != library->returnuninitdata.end())) {
alloc_pointer(checks, tok.varId()); alloc_pointer(checks, tok.varId());
if (tok.strAt(3) == "(") if (tok.strAt(3) == "(")
return tok.tokAt(3); return tok.tokAt(3);
@ -1037,7 +1041,7 @@ void CheckUninitVar::executionPaths()
if (_settings->_jobs == 1) if (_settings->_jobs == 1)
UninitVar::analyseFunctions(_tokenizer->tokens(), UninitVar::uvarFunctions); UninitVar::analyseFunctions(_tokenizer->tokens(), UninitVar::uvarFunctions);
UninitVar c(this, _tokenizer->getSymbolDatabase(), _tokenizer->isC()); UninitVar c(this, _tokenizer->getSymbolDatabase(), &_settings->library, _tokenizer->isC());
checkExecutionPaths(_tokenizer->getSymbolDatabase(), &c); checkExecutionPaths(_tokenizer->getSymbolDatabase(), &c);
} }
} }

View File

@ -33,7 +33,15 @@ Library::Library() : allocid(0)
_dealloc["fclose"] = allocid; _dealloc["fclose"] = allocid;
} }
Library::Library(const Library &lib) : use(lib.use), ignore(lib.ignore), allocid(lib.allocid), _alloc(lib._alloc), _dealloc(lib._dealloc), _noreturn(lib._noreturn) Library::Library(const Library &lib) :
use(lib.use),
ignore(lib.ignore),
functionArgument(lib.functionArgument),
returnuninitdata(lib.returnuninitdata),
allocid(lib.allocid),
_alloc(lib._alloc),
_dealloc(lib._dealloc),
_noreturn(lib._noreturn)
{ {
} }
@ -56,9 +64,13 @@ bool Library::load(const char path[])
if (strcmp(node->Name(),"memory")==0) { if (strcmp(node->Name(),"memory")==0) {
while (!ismemory(++allocid)); while (!ismemory(++allocid));
for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) { for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
if (strcmp(memorynode->Name(),"alloc")==0) if (strcmp(memorynode->Name(),"alloc")==0) {
_alloc[memorynode->GetText()] = allocid; _alloc[memorynode->GetText()] = allocid;
else if (strcmp(memorynode->Name(),"dealloc")==0) const char *init = memorynode->Attribute("init");
if (init && strcmp(init,"false")==0) {
returnuninitdata.insert(memorynode->GetText());
}
} else if (strcmp(memorynode->Name(),"dealloc")==0)
_dealloc[memorynode->GetText()] = allocid; _dealloc[memorynode->GetText()] = allocid;
else if (strcmp(memorynode->Name(),"use")==0) else if (strcmp(memorynode->Name(),"use")==0)
use.insert(memorynode->GetText()); use.insert(memorynode->GetText());

View File

@ -80,6 +80,8 @@ public:
// 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;
std::set<std::string> returnuninitdata;
private: private:
int allocid; int allocid;
std::map<std::string, int> _alloc; // allocation functions std::map<std::string, int> _alloc; // allocation functions

View File

@ -731,11 +731,11 @@ Checking test.c...
&lt;/def&gt;</programlisting> &lt;/def&gt;</programlisting>
<section> <section>
<title>Leaks</title> <title>&lt;alloc&gt; and &lt;dealloc&gt;</title>
<para>Allocation and deallocation is defined with <para>Allocation and deallocation is defined within
<literal>&lt;memory&gt;</literal> and <literal>&lt;memory&gt;</literal> or <literal>&lt;resource&gt; using
<literal>&lt;resource&gt;.</literal></para> &lt;alloc&gt; and &lt;dealloc&gt;.</literal></para>
<para>Here is example code:</para> <para>Here is example code:</para>
@ -760,8 +760,8 @@ Checking test.c...</programlisting>
<programlisting>&lt;?xml version="1.0"?&gt; <programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt; &lt;def&gt;
&lt;memory&gt; &lt;memory&gt;
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
&lt;alloc&gt;alloc_something&lt;/alloc&gt; &lt;alloc&gt;alloc_something&lt;/alloc&gt;
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
&lt;/memory&gt; &lt;/memory&gt;
&lt;/def&gt;</programlisting> &lt;/def&gt;</programlisting>
@ -771,7 +771,27 @@ Checking test.c...</programlisting>
Checking test.c... Checking test.c...
[test.c:10]: (error) Memory leak: p</programlisting> [test.c:10]: (error) Memory leak: p</programlisting>
<para>Another example code:</para> <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>
<title>&lt;ignore&gt; and &lt;use&gt;</title>
<para>The &lt;ignore&gt; and &lt;use&gt; tells Cppcheck how functions
uses allocated memory. Example code:</para>
<programlisting>void f() <programlisting>void f()
{ {
@ -786,8 +806,8 @@ Checking test.c...
<programlisting>&lt;?xml version="1.0"?&gt; <programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt; &lt;def&gt;
&lt;memory&gt; &lt;memory&gt;
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
&lt;alloc&gt;alloc_something&lt;/alloc&gt; &lt;alloc&gt;alloc_something&lt;/alloc&gt;
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
&lt;/memory&gt; &lt;/memory&gt;
&lt;ignore&gt;do_something&lt;/ignore&gt; &lt;ignore&gt;do_something&lt;/ignore&gt;
&lt;/def&gt;</programlisting> &lt;/def&gt;</programlisting>
@ -804,14 +824,50 @@ Checking test.c...
<para><programlisting>&lt;?xml version="1.0"?&gt; <para><programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt; &lt;def&gt;
&lt;memory&gt; &lt;memory&gt;
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
&lt;alloc&gt;alloc_something&lt;/alloc&gt; &lt;alloc&gt;alloc_something&lt;/alloc&gt;
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
&lt;use&gt;do_something&lt;/use&gt; &lt;use&gt;do_something&lt;/use&gt;
&lt;/memory&gt; &lt;/memory&gt;
&lt;/def&gt;</programlisting>Running Cppcheck now:</para> &lt;/def&gt;</programlisting>Running Cppcheck now:</para>
<programlisting># cppcheck --library=something.cfg test.c <programlisting># cppcheck --library=something.cfg test.c
Checking test.c...</programlisting> Checking test.c...</programlisting>
<para>Cppcheck will often assume that functions "use" allocated memory.
By using &lt;ignore&gt; you can make Cppcheck detect more errors. By
using &lt;use&gt;, no extra errors are detected but Cppcheck will not
need to assume.</para>
</section>
<section>
<title>&lt;alloc init="false"&gt;</title>
<para>Some allocation function initialize the data, others don't. Here
is a example code:</para>
<programlisting>void f()
{
char *p = alloc_something();
char c = *p;
free_something();
}</programlisting>
<para>Here is a configuration that tells cppcheck that alloc_something
doesn't initialize the data:</para>
<programlisting>&lt;?xml version="1.0"?&gt;
&lt;def&gt;
&lt;memory&gt;
&lt;alloc init="false"&gt;alloc_something&lt;/alloc&gt;
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
&lt;/memory&gt;
&lt;/def&gt;</programlisting>
<para>Now you will get this error message:</para>
<programlisting>daniel@dator:~/cppcheck$ ./cppcheck --library=something.cfg test.c
Checking test.c...
[test.c:4]: (error) Memory is allocated but not initialized: p</programlisting>
</section> </section>
<section> <section>