diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index aea97e47a..ae7eee1e7 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -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); } } diff --git a/lib/library.cpp b/lib/library.cpp index 7019b1e52..39a59c735 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -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()); diff --git a/lib/library.h b/lib/library.h index 6a70f7b72..cc86233af 100644 --- a/lib/library.h +++ b/lib/library.h @@ -80,6 +80,8 @@ public: // function name, argument nr => argument data std::map > functionArgument; + std::set returnuninitdata; + private: int allocid; std::map _alloc; // allocation functions diff --git a/man/manual.docbook b/man/manual.docbook index 0679697c1..58a24d282 100644 --- a/man/manual.docbook +++ b/man/manual.docbook @@ -449,7 +449,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati callstack - callstack - if available + callstack - if available @@ -457,7 +457,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati file - filename + filename @@ -465,7 +465,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati id - message id + message id @@ -473,7 +473,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati line - line number + line number @@ -481,7 +481,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati message - verbose message text + verbose message text @@ -489,7 +489,7 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati severity - severity + severity @@ -731,11 +731,11 @@ Checking test.c... </def>
- Leaks + <alloc> and <dealloc> - Allocation and deallocation is defined with - <memory> and - <resource>. + Allocation and deallocation is defined within + <memory> or <resource> using + <alloc> and <dealloc>. Here is example code: @@ -760,8 +760,8 @@ Checking test.c... <?xml version="1.0"?> <def> <memory> - <dealloc>free_something</dealloc> <alloc>alloc_something</alloc> + <dealloc>free_something</dealloc> </memory> </def> @@ -771,7 +771,27 @@ Checking test.c... Checking test.c... [test.c:10]: (error) Memory leak: p - Another example code: + 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: void f() { @@ -786,8 +806,8 @@ Checking test.c... <?xml version="1.0"?> <def> <memory> - <dealloc>free_something</dealloc> <alloc>alloc_something</alloc> + <dealloc>free_something</dealloc> </memory> <ignore>do_something</ignore> </def> @@ -804,14 +824,50 @@ Checking test.c... <?xml version="1.0"?> <def> <memory> - <dealloc>free_something</dealloc> <alloc>alloc_something</alloc> + <dealloc>free_something</dealloc> <use>do_something</use> </memory> </def>Running Cppcheck now: # cppcheck --library=something.cfg test.c Checking test.c... + + 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. +
+ +
+ <alloc init="false"> + + Some allocation function initialize the data, others don't. Here + is a example code: + + void f() +{ + char *p = alloc_something(); + char c = *p; + free_something(); +} + + Here is a configuration that tells cppcheck that alloc_something + doesn't initialize the data: + + <?xml version="1.0"?> +<def> + <memory> + <alloc init="false">alloc_something</alloc> + <dealloc>free_something</dealloc> + </memory> +</def> + + Now you will get this error message: + + daniel@dator:~/cppcheck$ ./cppcheck --library=something.cfg test.c +Checking test.c... +[test.c:4]: (error) Memory is allocated but not initialized: p