Fixed #3245 (False positive: Dangerous usage of 'string' (strncpy doesn't always 0-terminate it))
This commit is contained in:
parent
8f49eb6a7e
commit
316aa920eb
|
@ -240,17 +240,22 @@ private:
|
||||||
if (mode == 0 && (c->array || (c->pointer && c->alloc)))
|
if (mode == 0 && (c->array || (c->pointer && c->alloc)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// mode 2 : bad usage of pointer. if it's not a pointer then the usage is ok.
|
// mode 2 : reading array data with mem.. function. It's ok if the
|
||||||
|
// array is not 0-terminated
|
||||||
|
if (mode == 2 && c->strncpy_)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// mode 3 : bad usage of pointer. if it's not a pointer then the usage is ok.
|
||||||
// example: ptr->foo();
|
// example: ptr->foo();
|
||||||
if (mode == 2 && !c->pointer)
|
if (mode == 3 && !c->pointer)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// mode 3 : using dead pointer is invalid.
|
// mode 4 : using dead pointer is invalid.
|
||||||
if (mode == 3 && (!c->pointer || c->alloc))
|
if (mode == 4 && (!c->pointer || c->alloc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// mode 4 : reading uninitialized array or pointer is invalid.
|
// mode 5 : reading uninitialized array or pointer is invalid.
|
||||||
if (mode == 4 && (!c->array && !c->pointer))
|
if (mode == 5 && (!c->array && !c->pointer))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CheckUninitVar *checkUninitVar = dynamic_cast<CheckUninitVar *>(c->owner);
|
CheckUninitVar *checkUninitVar = dynamic_cast<CheckUninitVar *>(c->owner);
|
||||||
|
@ -290,6 +295,15 @@ private:
|
||||||
use(checks, tok, 1);
|
use(checks, tok, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reading array elements with a "mem.." function. It's ok if the array is not 0-terminated.
|
||||||
|
* @param checks all available checks
|
||||||
|
* @param tok variable token
|
||||||
|
*/
|
||||||
|
static void use_array_mem(std::list<ExecutionPath *> &checks, const Token *tok) {
|
||||||
|
use(checks, tok, 2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bad pointer usage. If the variable is not a pointer then the usage is ok.
|
* Bad pointer usage. If the variable is not a pointer then the usage is ok.
|
||||||
* @param checks all available checks
|
* @param checks all available checks
|
||||||
|
@ -297,7 +311,7 @@ private:
|
||||||
* @return if error is found, true is returned
|
* @return if error is found, true is returned
|
||||||
*/
|
*/
|
||||||
static bool use_pointer(std::list<ExecutionPath *> &checks, const Token *tok) {
|
static bool use_pointer(std::list<ExecutionPath *> &checks, const Token *tok) {
|
||||||
return use(checks, tok, 2);
|
return use(checks, tok, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -307,7 +321,7 @@ private:
|
||||||
* @return if error is found, true is returned
|
* @return if error is found, true is returned
|
||||||
*/
|
*/
|
||||||
static bool use_dead_pointer(std::list<ExecutionPath *> &checks, const Token *tok) {
|
static bool use_dead_pointer(std::list<ExecutionPath *> &checks, const Token *tok) {
|
||||||
return use(checks, tok, 3);
|
return use(checks, tok, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -318,10 +332,9 @@ private:
|
||||||
* @return if error is found, true is returned
|
* @return if error is found, true is returned
|
||||||
*/
|
*/
|
||||||
static bool use_array_or_pointer_data(std::list<ExecutionPath *> &checks, const Token *tok) {
|
static bool use_array_or_pointer_data(std::list<ExecutionPath *> &checks, const Token *tok) {
|
||||||
return use(checks, tok, 4);
|
return use(checks, tok, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** declaring a variable */
|
/** declaring a variable */
|
||||||
void declare(std::list<ExecutionPath *> &checks, const Token *vartok, const Token &tok, const bool p, const bool a) const {
|
void declare(std::list<ExecutionPath *> &checks, const Token *vartok, const Token &tok, const bool p, const bool a) const {
|
||||||
if (vartok->varId() == 0)
|
if (vartok->varId() == 0)
|
||||||
|
@ -576,7 +589,12 @@ private:
|
||||||
std::list<const Token *> var;
|
std::list<const Token *> var;
|
||||||
CheckNullPointer::parseFunctionCall(tok, var, 1);
|
CheckNullPointer::parseFunctionCall(tok, var, 1);
|
||||||
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it) {
|
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it) {
|
||||||
|
// is function memset/memcpy/etc?
|
||||||
|
if (tok.str().compare(0,3,"mem") == 0)
|
||||||
|
use_array_mem(checks, *it);
|
||||||
|
else
|
||||||
use_array(checks, *it);
|
use_array(checks, *it);
|
||||||
|
|
||||||
use_dead_pointer(checks, *it);
|
use_dead_pointer(checks, *it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,11 +857,17 @@ private:
|
||||||
use_array_or_pointer_data(checks, tok.str() == "!" ? tok.next() : &tok);
|
use_array_or_pointer_data(checks, tok.str() == "!" ? tok.next() : &tok);
|
||||||
|
|
||||||
else if (Token::Match(&tok, "!| %var% (")) {
|
else if (Token::Match(&tok, "!| %var% (")) {
|
||||||
|
const Token * const ftok = (tok.str() == "!") ? tok.next() : &tok;
|
||||||
std::list<const Token *> var;
|
std::list<const Token *> var;
|
||||||
CheckNullPointer::parseFunctionCall(tok.str() == "!" ? *tok.next() : tok, var, 1);
|
CheckNullPointer::parseFunctionCall(*ftok, var, 1);
|
||||||
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it)
|
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it) {
|
||||||
|
// is function memset/memcpy/etc?
|
||||||
|
if (ftok->str().compare(0,3,"mem") == 0)
|
||||||
|
use_array_mem(checks, *it);
|
||||||
|
else
|
||||||
use_array(checks, *it);
|
use_array(checks, *it);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (Token::Match(&tok, "! %var% )")) {
|
else if (Token::Match(&tok, "! %var% )")) {
|
||||||
use(checks, &tok);
|
use(checks, &tok);
|
||||||
|
|
|
@ -1330,6 +1330,23 @@ private:
|
||||||
" strncat(a, \"world\", 20);\n"
|
" strncat(a, \"world\", 20);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
// #3245 - false positive
|
||||||
|
{
|
||||||
|
checkUninitVar("void f() {\n"
|
||||||
|
" char a[100];\n"
|
||||||
|
" strncpy(a,p,10);\n"
|
||||||
|
" memcmp(a,q,10);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkUninitVar("void f() {\n"
|
||||||
|
" char a[100];\n"
|
||||||
|
" strncpy(a,p,10);\n"
|
||||||
|
" if (memcmp(a,q,10)==0);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialization with memset (not 0-terminating string)..
|
// initialization with memset (not 0-terminating string)..
|
||||||
|
|
Loading…
Reference in New Issue