Library: added init attribute to <alloc>
This commit is contained in:
parent
16d0a818c9
commit
66d8fa62d1
|
@ -54,8 +54,8 @@ static const Token * skipBrackets(const Token *tok)
|
|||
class UninitVar : public ExecutionPath {
|
||||
public:
|
||||
/** Startup constructor */
|
||||
explicit UninitVar(Check *c, const SymbolDatabase* db, bool isc)
|
||||
: ExecutionPath(c, 0), symbolDatabase(db), isC(isc), var(0), alloc(false), strncpy_(false), memset_nonzero(false) {
|
||||
explicit UninitVar(Check *c, const SymbolDatabase* db, const Library *lib, bool isc)
|
||||
: ExecutionPath(c, 0), symbolDatabase(db), library(lib), isC(isc), var(0), alloc(false), strncpy_(false), memset_nonzero(false) {
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -68,8 +68,8 @@ private:
|
|||
void operator=(const UninitVar &);
|
||||
|
||||
/** internal constructor for creating extra checks */
|
||||
UninitVar(Check *c, const Variable* v, const SymbolDatabase* db, bool isc)
|
||||
: ExecutionPath(c, v->varId()), symbolDatabase(db), isC(isc), var(v), alloc(false), strncpy_(false), memset_nonzero(false) {
|
||||
UninitVar(Check *c, const Variable* v, const SymbolDatabase* db, const Library *lib, bool isc)
|
||||
: ExecutionPath(c, v->varId()), symbolDatabase(db), library(lib), isC(isc), var(v), alloc(false), strncpy_(false), memset_nonzero(false) {
|
||||
}
|
||||
|
||||
/** is other execution path equal? */
|
||||
|
@ -81,6 +81,9 @@ private:
|
|||
/** pointer to symbol database */
|
||||
const SymbolDatabase* symbolDatabase;
|
||||
|
||||
/** pointer to library */
|
||||
const Library *library;
|
||||
|
||||
const bool isC;
|
||||
|
||||
/** variable for this check */
|
||||
|
@ -425,7 +428,7 @@ private:
|
|||
}
|
||||
|
||||
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() != ">") {
|
||||
bool stdtype = false; // TODO: change to isC to handle unknown types better
|
||||
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) == ";"))
|
||||
checks.push_back(new UninitVar(owner, var2, symbolDatabase, isC));
|
||||
checks.push_back(new UninitVar(owner, var2, symbolDatabase, library, isC));
|
||||
}
|
||||
return &tok;
|
||||
}
|
||||
|
@ -573,7 +576,8 @@ private:
|
|||
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());
|
||||
if (tok.strAt(3) == "(")
|
||||
return tok.tokAt(3);
|
||||
|
@ -1037,7 +1041,7 @@ void CheckUninitVar::executionPaths()
|
|||
if (_settings->_jobs == 1)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,15 @@ Library::Library() : allocid(0)
|
|||
_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) {
|
||||
while (!ismemory(++allocid));
|
||||
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;
|
||||
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;
|
||||
else if (strcmp(memorynode->Name(),"use")==0)
|
||||
use.insert(memorynode->GetText());
|
||||
|
|
|
@ -80,6 +80,8 @@ public:
|
|||
// function name, argument nr => argument data
|
||||
std::map<std::string, std::map<int, Argument> > functionArgument;
|
||||
|
||||
std::set<std::string> returnuninitdata;
|
||||
|
||||
private:
|
||||
int allocid;
|
||||
std::map<std::string, int> _alloc; // allocation functions
|
||||
|
|
|
@ -449,7 +449,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati
|
|||
<term>callstack</term>
|
||||
|
||||
<listitem>
|
||||
callstack - if available
|
||||
callstack - if available
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -457,7 +457,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati
|
|||
<term>file</term>
|
||||
|
||||
<listitem>
|
||||
filename
|
||||
filename
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -465,7 +465,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati
|
|||
<term>id</term>
|
||||
|
||||
<listitem>
|
||||
message id
|
||||
message id
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -473,7 +473,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati
|
|||
<term>line</term>
|
||||
|
||||
<listitem>
|
||||
line number
|
||||
line number
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -481,7 +481,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati
|
|||
<term>message</term>
|
||||
|
||||
<listitem>
|
||||
verbose message text
|
||||
verbose message text
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -489,7 +489,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati
|
|||
<term>severity</term>
|
||||
|
||||
<listitem>
|
||||
severity
|
||||
severity
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
@ -731,11 +731,11 @@ Checking test.c...
|
|||
</def></programlisting>
|
||||
|
||||
<section>
|
||||
<title>Leaks</title>
|
||||
<title><alloc> and <dealloc></title>
|
||||
|
||||
<para>Allocation and deallocation is defined with
|
||||
<literal><memory></literal> and
|
||||
<literal><resource>.</literal></para>
|
||||
<para>Allocation and deallocation is defined within
|
||||
<literal><memory></literal> or <literal><resource> using
|
||||
<alloc> and <dealloc>.</literal></para>
|
||||
|
||||
<para>Here is example code:</para>
|
||||
|
||||
|
@ -760,8 +760,8 @@ Checking test.c...</programlisting>
|
|||
<programlisting><?xml version="1.0"?>
|
||||
<def>
|
||||
<memory>
|
||||
<dealloc>free_something</dealloc>
|
||||
<alloc>alloc_something</alloc>
|
||||
<dealloc>free_something</dealloc>
|
||||
</memory>
|
||||
</def></programlisting>
|
||||
|
||||
|
@ -771,7 +771,27 @@ Checking test.c...</programlisting>
|
|||
Checking test.c...
|
||||
[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><ignore> and <use></title>
|
||||
|
||||
<para>The <ignore> and <use> tells Cppcheck how functions
|
||||
uses allocated memory. Example code:</para>
|
||||
|
||||
<programlisting>void f()
|
||||
{
|
||||
|
@ -786,8 +806,8 @@ Checking test.c...
|
|||
<programlisting><?xml version="1.0"?>
|
||||
<def>
|
||||
<memory>
|
||||
<dealloc>free_something</dealloc>
|
||||
<alloc>alloc_something</alloc>
|
||||
<dealloc>free_something</dealloc>
|
||||
</memory>
|
||||
<ignore>do_something</ignore>
|
||||
</def></programlisting>
|
||||
|
@ -804,14 +824,50 @@ Checking test.c...
|
|||
<para><programlisting><?xml version="1.0"?>
|
||||
<def>
|
||||
<memory>
|
||||
<dealloc>free_something</dealloc>
|
||||
<alloc>alloc_something</alloc>
|
||||
<dealloc>free_something</dealloc>
|
||||
<use>do_something</use>
|
||||
</memory>
|
||||
</def></programlisting>Running Cppcheck now:</para>
|
||||
|
||||
<programlisting># cppcheck --library=something.cfg test.c
|
||||
Checking test.c...</programlisting>
|
||||
|
||||
<para>Cppcheck will often assume that functions "use" allocated memory.
|
||||
By using <ignore> you can make Cppcheck detect more errors. By
|
||||
using <use>, no extra errors are detected but Cppcheck will not
|
||||
need to assume.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><alloc init="false"></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><?xml version="1.0"?>
|
||||
<def>
|
||||
<memory>
|
||||
<alloc init="false">alloc_something</alloc>
|
||||
<dealloc>free_something</dealloc>
|
||||
</memory>
|
||||
</def></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>
|
||||
|
|
Loading…
Reference in New Issue