Skip to content

Commit 66d8fa6

Browse files
committed
Library: added init attribute to <alloc>
1 parent 16d0a81 commit 66d8fa6

4 files changed

Lines changed: 99 additions & 25 deletions

File tree

lib/checkuninitvar.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ static const Token * skipBrackets(const Token *tok)
5454
class UninitVar : public ExecutionPath {
5555
public:
5656
/** Startup constructor */
57-
explicit UninitVar(Check *c, const SymbolDatabase* db, bool isc)
58-
: ExecutionPath(c, 0), symbolDatabase(db), isC(isc), var(0), alloc(false), strncpy_(false), memset_nonzero(false) {
57+
explicit UninitVar(Check *c, const SymbolDatabase* db, const Library *lib, bool isc)
58+
: ExecutionPath(c, 0), symbolDatabase(db), library(lib), isC(isc), var(0), alloc(false), strncpy_(false), memset_nonzero(false) {
5959
}
6060

6161
private:
@@ -68,8 +68,8 @@ class UninitVar : public ExecutionPath {
6868
void operator=(const UninitVar &);
6969

7070
/** internal constructor for creating extra checks */
71-
UninitVar(Check *c, const Variable* v, const SymbolDatabase* db, bool isc)
72-
: ExecutionPath(c, v->varId()), symbolDatabase(db), isC(isc), var(v), alloc(false), strncpy_(false), memset_nonzero(false) {
71+
UninitVar(Check *c, const Variable* v, const SymbolDatabase* db, const Library *lib, bool isc)
72+
: ExecutionPath(c, v->varId()), symbolDatabase(db), library(lib), isC(isc), var(v), alloc(false), strncpy_(false), memset_nonzero(false) {
7373
}
7474

7575
/** is other execution path equal? */
@@ -81,6 +81,9 @@ class UninitVar : public ExecutionPath {
8181
/** pointer to symbol database */
8282
const SymbolDatabase* symbolDatabase;
8383

84+
/** pointer to library */
85+
const Library *library;
86+
8487
const bool isC;
8588

8689
/** variable for this check */
@@ -425,7 +428,7 @@ class UninitVar : public ExecutionPath {
425428
}
426429

427430
if (var2->isPointer())
428-
checks.push_back(new UninitVar(owner, var2, symbolDatabase, isC));
431+
checks.push_back(new UninitVar(owner, var2, symbolDatabase, library, isC));
429432
else if (var2->typeEndToken()->str() != ">") {
430433
bool stdtype = false; // TODO: change to isC to handle unknown types better
431434
for (const Token* tok2 = var2->typeStartToken(); tok2 != var2->nameToken(); tok2 = tok2->next()) {
@@ -435,7 +438,7 @@ class UninitVar : public ExecutionPath {
435438
}
436439
}
437440
if (stdtype && (!var2->isArray() || var2->nameToken()->linkAt(1)->strAt(1) == ";"))
438-
checks.push_back(new UninitVar(owner, var2, symbolDatabase, isC));
441+
checks.push_back(new UninitVar(owner, var2, symbolDatabase, library, isC));
439442
}
440443
return &tok;
441444
}
@@ -573,7 +576,8 @@ class UninitVar : public ExecutionPath {
573576
return &tok;
574577
}
575578

576-
if (Token::Match(tok.next(), "= malloc|kmalloc") || Token::simpleMatch(tok.next(), "= new char [")) {
579+
if (Token::Match(tok.next(), "= malloc|kmalloc") || Token::simpleMatch(tok.next(), "= new char [") ||
580+
(Token::Match(tok.next(), "= %var% (") && library->returnuninitdata.find(tok.strAt(2)) != library->returnuninitdata.end())) {
577581
alloc_pointer(checks, tok.varId());
578582
if (tok.strAt(3) == "(")
579583
return tok.tokAt(3);
@@ -1037,7 +1041,7 @@ void CheckUninitVar::executionPaths()
10371041
if (_settings->_jobs == 1)
10381042
UninitVar::analyseFunctions(_tokenizer->tokens(), UninitVar::uvarFunctions);
10391043

1040-
UninitVar c(this, _tokenizer->getSymbolDatabase(), _tokenizer->isC());
1044+
UninitVar c(this, _tokenizer->getSymbolDatabase(), &_settings->library, _tokenizer->isC());
10411045
checkExecutionPaths(_tokenizer->getSymbolDatabase(), &c);
10421046
}
10431047
}

lib/library.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,15 @@ Library::Library() : allocid(0)
3333
_dealloc["fclose"] = allocid;
3434
}
3535

36-
Library::Library(const Library &lib) : use(lib.use), ignore(lib.ignore), allocid(lib.allocid), _alloc(lib._alloc), _dealloc(lib._dealloc), _noreturn(lib._noreturn)
36+
Library::Library(const Library &lib) :
37+
use(lib.use),
38+
ignore(lib.ignore),
39+
functionArgument(lib.functionArgument),
40+
returnuninitdata(lib.returnuninitdata),
41+
allocid(lib.allocid),
42+
_alloc(lib._alloc),
43+
_dealloc(lib._dealloc),
44+
_noreturn(lib._noreturn)
3745
{
3846

3947
}
@@ -56,9 +64,13 @@ bool Library::load(const char path[])
5664
if (strcmp(node->Name(),"memory")==0) {
5765
while (!ismemory(++allocid));
5866
for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
59-
if (strcmp(memorynode->Name(),"alloc")==0)
67+
if (strcmp(memorynode->Name(),"alloc")==0) {
6068
_alloc[memorynode->GetText()] = allocid;
61-
else if (strcmp(memorynode->Name(),"dealloc")==0)
69+
const char *init = memorynode->Attribute("init");
70+
if (init && strcmp(init,"false")==0) {
71+
returnuninitdata.insert(memorynode->GetText());
72+
}
73+
} else if (strcmp(memorynode->Name(),"dealloc")==0)
6274
_dealloc[memorynode->GetText()] = allocid;
6375
else if (strcmp(memorynode->Name(),"use")==0)
6476
use.insert(memorynode->GetText());

lib/library.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class CPPCHECKLIB Library {
8080
// function name, argument nr => argument data
8181
std::map<std::string, std::map<int, Argument> > functionArgument;
8282

83+
std::set<std::string> returnuninitdata;
84+
8385
private:
8486
int allocid;
8587
std::map<std::string, int> _alloc; // allocation functions

man/manual.docbook

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -449,47 +449,47 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati
449449
<term>callstack</term>
450450

451451
<listitem>
452-
callstack - if available
452+
callstack - if available
453453
</listitem>
454454
</varlistentry>
455455

456456
<varlistentry>
457457
<term>file</term>
458458

459459
<listitem>
460-
filename
460+
filename
461461
</listitem>
462462
</varlistentry>
463463

464464
<varlistentry>
465465
<term>id</term>
466466

467467
<listitem>
468-
message id
468+
message id
469469
</listitem>
470470
</varlistentry>
471471

472472
<varlistentry>
473473
<term>line</term>
474474

475475
<listitem>
476-
line number
476+
line number
477477
</listitem>
478478
</varlistentry>
479479

480480
<varlistentry>
481481
<term>message</term>
482482

483483
<listitem>
484-
verbose message text
484+
verbose message text
485485
</listitem>
486486
</varlistentry>
487487

488488
<varlistentry>
489489
<term>severity</term>
490490

491491
<listitem>
492-
severity
492+
severity
493493
</listitem>
494494
</varlistentry>
495495
</variablelist>
@@ -731,11 +731,11 @@ Checking test.c...
731731
&lt;/def&gt;</programlisting>
732732

733733
<section>
734-
<title>Leaks</title>
734+
<title>&lt;alloc&gt; and &lt;dealloc&gt;</title>
735735

736-
<para>Allocation and deallocation is defined with
737-
<literal>&lt;memory&gt;</literal> and
738-
<literal>&lt;resource&gt;.</literal></para>
736+
<para>Allocation and deallocation is defined within
737+
<literal>&lt;memory&gt;</literal> or <literal>&lt;resource&gt; using
738+
&lt;alloc&gt; and &lt;dealloc&gt;.</literal></para>
739739

740740
<para>Here is example code:</para>
741741

@@ -760,8 +760,8 @@ Checking test.c...</programlisting>
760760
<programlisting>&lt;?xml version="1.0"?&gt;
761761
&lt;def&gt;
762762
&lt;memory&gt;
763-
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
764763
&lt;alloc&gt;alloc_something&lt;/alloc&gt;
764+
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
765765
&lt;/memory&gt;
766766
&lt;/def&gt;</programlisting>
767767

@@ -771,7 +771,27 @@ Checking test.c...</programlisting>
771771
Checking test.c...
772772
[test.c:10]: (error) Memory leak: p</programlisting>
773773

774-
<para>Another example code:</para>
774+
<para>Some allocation functions initialize the allocated data. Others
775+
don't. Here is a short code example:</para>
776+
777+
<programlisting>void f()
778+
{
779+
char *p = alloc_something();
780+
char c = *p;
781+
free_something();
782+
}</programlisting>
783+
784+
<para>If alloc_something() initializes the memory that is allocated then
785+
that code is OK. Otherwise that code is bad. To configure that </para>
786+
787+
<para/>
788+
</section>
789+
790+
<section>
791+
<title>&lt;ignore&gt; and &lt;use&gt;</title>
792+
793+
<para>The &lt;ignore&gt; and &lt;use&gt; tells Cppcheck how functions
794+
uses allocated memory. Example code:</para>
775795

776796
<programlisting>void f()
777797
{
@@ -786,8 +806,8 @@ Checking test.c...
786806
<programlisting>&lt;?xml version="1.0"?&gt;
787807
&lt;def&gt;
788808
&lt;memory&gt;
789-
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
790809
&lt;alloc&gt;alloc_something&lt;/alloc&gt;
810+
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
791811
&lt;/memory&gt;
792812
&lt;ignore&gt;do_something&lt;/ignore&gt;
793813
&lt;/def&gt;</programlisting>
@@ -804,14 +824,50 @@ Checking test.c...
804824
<para><programlisting>&lt;?xml version="1.0"?&gt;
805825
&lt;def&gt;
806826
&lt;memory&gt;
807-
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
808827
&lt;alloc&gt;alloc_something&lt;/alloc&gt;
828+
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
809829
&lt;use&gt;do_something&lt;/use&gt;
810830
&lt;/memory&gt;
811831
&lt;/def&gt;</programlisting>Running Cppcheck now:</para>
812832

813833
<programlisting># cppcheck --library=something.cfg test.c
814834
Checking test.c...</programlisting>
835+
836+
<para>Cppcheck will often assume that functions "use" allocated memory.
837+
By using &lt;ignore&gt; you can make Cppcheck detect more errors. By
838+
using &lt;use&gt;, no extra errors are detected but Cppcheck will not
839+
need to assume.</para>
840+
</section>
841+
842+
<section>
843+
<title>&lt;alloc init="false"&gt;</title>
844+
845+
<para>Some allocation function initialize the data, others don't. Here
846+
is a example code:</para>
847+
848+
<programlisting>void f()
849+
{
850+
char *p = alloc_something();
851+
char c = *p;
852+
free_something();
853+
}</programlisting>
854+
855+
<para>Here is a configuration that tells cppcheck that alloc_something
856+
doesn't initialize the data:</para>
857+
858+
<programlisting>&lt;?xml version="1.0"?&gt;
859+
&lt;def&gt;
860+
&lt;memory&gt;
861+
&lt;alloc init="false"&gt;alloc_something&lt;/alloc&gt;
862+
&lt;dealloc&gt;free_something&lt;/dealloc&gt;
863+
&lt;/memory&gt;
864+
&lt;/def&gt;</programlisting>
865+
866+
<para>Now you will get this error message:</para>
867+
868+
<programlisting>daniel@dator:~/cppcheck$ ./cppcheck --library=something.cfg test.c
869+
Checking test.c...
870+
[test.c:4]: (error) Memory is allocated but not initialized: p</programlisting>
815871
</section>
816872

817873
<section>

0 commit comments

Comments
 (0)