This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] StdLibraryFunctionsChecker: match signature based on FunctionDecl
ClosedPublic

Authored by martong on Apr 3 2020, 8:37 AM.

Details

Summary

Currently we match the summary signature based on the arguments in the CallExpr.
There are a few problems with this approach.

  1. Variadic arguments are handled badly. Consider the below code:
int foo(void *stream, const char *format, ...);
void test_arg_constraint_on_variadic_fun() {
   foo(0, "%d%d", 1, 2); // CallExpr
}

Here the call expression holds 4 arguments, whereas the function declaration
has only 2 ParmVarDecls. So there is no way to create a summary that
matches the call expression, because the discrepancy in the number of
arguments causes a mismatch.

  1. The call expression does not handle the restrict type qualifier. In C99, fwrite's signature is the following:
size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict);

However, in a call expression, like below, the type of the argument does not
have the restrict qualifier.

void test_fread_fwrite(FILE *fp, int *buf) {
  size_t x = fwrite(buf, sizeof(int), 10, fp);
}

The type of the 1st argument in the CallExpr is

PointerType 0x55b7168af2e0 'const void *'
`-QualType 0x55b7168373c1 'const void' const
  `-BuiltinType 0x55b7168373c0 'void'

However, the type in the signature of the FunctionDecl and in the summary map is

QualType 0x55b7168af2e2 'const void *__restrict' __restrict
`-PointerType 0x55b7168af2e0 'const void *'
  `-QualType 0x55b7168373c1 'const void' const
    `-BuiltinType 0x55b7168373c0 'void'

The restrict qualifier is not in the call expression (actually, why would it be?). So, this results in an unmatched signature and the summary is not applied.

The solution is to match the summary against the referened callee
FunctionDecl that we can query from the CallExpr.

Further patches will continue with additional refactoring where I am going to
do a lookup during the checker initialization and the signature match will
happen there. That way, we will not check the signature during every call,
rather we will compare only two FunctionDecl pointers.

Diff Detail

Event Timeline

martong created this revision.Apr 3 2020, 8:37 AM
martong edited the summary of this revision. (Show Details)Apr 3 2020, 8:39 AM
martong edited the summary of this revision. (Show Details)
martong edited the summary of this revision. (Show Details)Apr 3 2020, 8:45 AM
NoQ accepted this revision.Apr 6 2020, 1:15 AM

Excellent! No objections. It should have absolutely been like that from the start: summaries are of functions, not of call sites.

This revision is now accepted and ready to land.Apr 6 2020, 1:15 AM
balazske added inline comments.
clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
552

This assert can be removed, after the previous getCanonicalType call it looks redundant.

Szelethus accepted this revision.Apr 6 2020, 2:39 AM

LGTM! Maybe its worth glancing over the rest of the code (comments in particular) whether anything would be outdated by this change.

martong marked 2 inline comments as done.Apr 6 2020, 8:33 AM

LGTM! Maybe its worth glancing over the rest of the code (comments in particular) whether anything would be outdated by this change.

Yeah, seems like the comments are still aligned. Also, I am going to submit the next patch, which will scramble the current structures (and probably the related comments as well).

clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
552

Thanks, good catch!

This revision was automatically updated to reflect the committed changes.
martong marked an inline comment as done.