Fix #10179 FP divideSizeof with dereferenced pointer-to-pointer (#3786)

This commit is contained in:
chrchr-github 2022-04-10 22:47:27 +02:00 committed by GitHub
parent aa7a1f25c1
commit bd9f5231b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 14 deletions

View File

@ -373,18 +373,31 @@ void CheckSizeof::suspiciousSizeofCalculation()
if (!mSettings->severity.isEnabled(Severity::warning) || !mSettings->certainty.isEnabled(Certainty::inconclusive)) if (!mSettings->severity.isEnabled(Severity::warning) || !mSettings->certainty.isEnabled(Certainty::inconclusive))
return; return;
// TODO: Use AST here. This should be possible as soon as sizeof without brackets is correctly parsed
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "sizeof (")) { if (Token::simpleMatch(tok, "sizeof (")) {
const Token* const end = tok->linkAt(1); const Token* lPar = tok->astParent();
const Variable* var = end->previous()->variable(); if (lPar && lPar->str() == "(") {
if (end->strAt(-1) == "*" || (var && var->isPointer() && !var->isArray())) { const Token* const rPar = lPar->link();
if (end->strAt(1) == "/") const Token* varTok = rPar->previous();
while (varTok && varTok->str() == "]")
varTok = varTok->link()->previous();
if (lPar->astParent() && lPar->astParent()->str() == "/") {
const Variable* var = varTok ? varTok->variable() : nullptr;
if (var && var->isPointer() && !var->isArray() && !(lPar->astOperand2() && lPar->astOperand2()->str() == "*"))
divideSizeofError(tok); divideSizeofError(tok);
} else if (Token::simpleMatch(end, ") * sizeof") && end->next()->astOperand1() == tok->next()) else if (varTok && varTok->str() == "*") {
const Token* arrTok = lPar->astParent()->astOperand1();
arrTok = arrTok ? arrTok->next() : nullptr;
var = arrTok ? arrTok->variable() : nullptr;
if (var && var->isPointer() && !var->isArray())
divideSizeofError(tok);
}
}
else if (Token::simpleMatch(rPar, ") * sizeof") && rPar->next()->astOperand1() == tok->next())
multiplySizeofError(tok); multiplySizeofError(tok);
} }
} }
}
} }
void CheckSizeof::multiplySizeofError(const Token *tok) void CheckSizeof::multiplySizeofError(const Token *tok)

View File

@ -427,6 +427,35 @@ private:
" return (end - source) / sizeof(encode_block_type) * sizeof(encode_block_type);\n" " return (end - source) / sizeof(encode_block_type) * sizeof(encode_block_type);\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("struct S { T* t; };\n" // #10179
"int f(S* s) {\n"
" return g(sizeof(*s->t) / 4);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" const char* a[N];\n"
" for (int i = 0; i < (int)(sizeof(a) / sizeof(char*)); i++) {}\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("int f(const S& s) {\n"
" int** p;\n"
" return sizeof(p[0]) / 4;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Division of result of sizeof() on pointer type.\n", errout.str());
check("struct S {\n"
" unsigned char* s;\n"
"};\n"
"struct T {\n"
" S s[38];\n"
"};\n"
"void f(T* t) {\n"
" for (size_t i = 0; i < sizeof(t->s) / sizeof(t->s[0]); i++) {}\n"
"}\n");
ASSERT_EQUALS("", errout.str());
} }
void checkPointerSizeof() { void checkPointerSizeof() {
@ -722,7 +751,9 @@ private:
check("void foo(memoryMapEntry_t* entry, memoryMapEntry_t* memoryMapEnd) {\n" check("void foo(memoryMapEntry_t* entry, memoryMapEntry_t* memoryMapEnd) {\n"
" memmove(entry, entry + 1, (memoryMapEnd - entry) / sizeof(entry));\n" " memmove(entry, entry + 1, (memoryMapEnd - entry) / sizeof(entry));\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:2]: (warning) Division by result of sizeof(). memmove() expects a size in bytes, did you intend to multiply instead?\n", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (warning, inconclusive) Division of result of sizeof() on pointer type.\n"
"[test.cpp:2]: (warning) Division by result of sizeof(). memmove() expects a size in bytes, did you intend to multiply instead?\n",
errout.str());
check("Foo* allocFoo(int num) {\n" check("Foo* allocFoo(int num) {\n"
" return malloc(num / sizeof(Foo));\n" " return malloc(num / sizeof(Foo));\n"

View File

@ -125,6 +125,11 @@ def compile_version(cppcheck_path, jobs):
def compile_cppcheck(cppcheck_path, jobs): def compile_cppcheck(cppcheck_path, jobs):
print('Compiling {}'.format(os.path.basename(cppcheck_path))) print('Compiling {}'.format(os.path.basename(cppcheck_path)))
try: try:
os.chdir(cppcheck_path)
if sys.platform == 'win32':
subprocess.call(['MSBuild.exe', cppcheck_path + '/cppcheck.sln', '/property:Configuration=Release', '/property:Platform=x64'])
subprocess.call([cppcheck_path + '/bin/cppcheck.exe', '--version'])
else:
subprocess.check_call(['make', jobs, 'MATCHCOMPILER=yes', 'CXXFLAGS=-O2 -g -w'], cwd=cppcheck_path) subprocess.check_call(['make', jobs, 'MATCHCOMPILER=yes', 'CXXFLAGS=-O2 -g -w'], cwd=cppcheck_path)
subprocess.check_call([os.path.join(cppcheck_path, 'cppcheck'), '--version'], cwd=cppcheck_path) subprocess.check_call([os.path.join(cppcheck_path, 'cppcheck'), '--version'], cwd=cppcheck_path)
except: except:
@ -279,6 +284,9 @@ def __run_command(cmd, print_cmd=True):
print(cmd) print(cmd)
start_time = time.time() start_time = time.time()
comm = None comm = None
if sys.platform == 'win32':
p = subprocess.Popen(shlex.split(cmd, comments=False, posix=False), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else:
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid) p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid)
try: try:
comm = p.communicate(timeout=CPPCHECK_TIMEOUT) comm = p.communicate(timeout=CPPCHECK_TIMEOUT)
@ -323,6 +331,10 @@ def scan_package(work_path, cppcheck_path, jobs, libraries, capture_callstack=Tr
options = libs + ' --showtime=top5 --check-library --inconclusive --enable=style,information --template=daca2' options = libs + ' --showtime=top5 --check-library --inconclusive --enable=style,information --template=daca2'
options += ' -D__GNUC__ --platform=unix64' options += ' -D__GNUC__ --platform=unix64'
options += ' -rp={}'.format(dir_to_scan) options += ' -rp={}'.format(dir_to_scan)
if sys.platform == 'win32':
cppcheck_cmd = cppcheck_path + '/bin/cppcheck.exe ' + options
cmd = cppcheck_cmd + ' ' + jobs + ' ' + dir_to_scan
else:
cppcheck_cmd = os.path.join(cppcheck_path, 'cppcheck') + ' ' + options cppcheck_cmd = os.path.join(cppcheck_path, 'cppcheck') + ' ' + options
cmd = 'nice ' + cppcheck_cmd + ' ' + jobs + ' ' + dir_to_scan cmd = 'nice ' + cppcheck_cmd + ' ' + jobs + ' ' + dir_to_scan
returncode, stdout, stderr, elapsed_time = __run_command(cmd) returncode, stdout, stderr, elapsed_time = __run_command(cmd)

View File

@ -3,6 +3,7 @@
# Run this script from your branch with proposed Cppcheck patch to verify your # Run this script from your branch with proposed Cppcheck patch to verify your
# patch against current main. It will compare output of testing a bunch of # patch against current main. It will compare output of testing a bunch of
# opensource packages # opensource packages
# If running on Windows, make sure that git.exe, wget.exe, and MSBuild.exe are available in PATH
import donate_cpu_lib as lib import donate_cpu_lib as lib
import argparse import argparse