Any way to generate warnings for function-pointer

2020-05-20 02:14发布

问题:

It took me forever to track down that there was a bug in my code being triggered by /OPT:ICF:

Because /OPT:ICF can cause the same address to be assigned to different functions or read-only data members (const variables compiled by using /Gy), it can break a program that depends on unique addresses for functions or read-only data members.

(I had been storing and comparing function pointers for equality, which breaks when the linker throws away identical functions.)

Now I need to find every place where I might have done such a thing.

The test case is of course trivial:

//MSVC: /Gy /link /OPT:ICF
int test1(void) { return 0; }
int test2(void) { return 0; }
int main(void) { return test1 == test2; }

I've tried -Wall, -Wextra, -Weverything, -pedantic, etc. but none of them generate warnings.

Is there any compiler option or tool (whether part of Visual C++, GCC, Clang, or other) that can analyze my code and tell me where I'm comparing function pointers with each other, like in the code above?

回答1:

Is there any compiler option or tool (whether part of Visual C++, GCC, Clang, or other) that can analyze my code and tell me where I'm comparing function pointers with each other, like in the code above?

I'm not sure if there exists such a compiler option.

However, there is such a tool. clang-tidy. You can write your own checks for clang-tidy, it's actually remarkably easy if you follow this blog. Specifically, the AST comes with a bunch of matchers already, which should handle the use-case you want.

Something like this seems to work:

binaryOperator(
    anyOf(hasOperatorName("=="), hasOperatorName("!=")),
    hasLHS(ignoringImpCasts(declRefExpr(hasType(functionType())))),
    hasRHS(ignoringImpCasts(declRefExpr(hasType(functionType())))))

Which flags the example in the OP:

fp.cxx:3:25: note: "root" binds here
int main(void) { return test1 == test2; }
                        ^~~~~~~~~~~~~~

That works specifically for the OP case, but you actually have to be more explicit to match all the other likely cases:

const auto AnyFunc = ignoringImpCasts(declRefExpr(hasType(anyOf(
    functionType(),
    pointsTo(functionType()),
    references(functionType())))));

Finder->AddMatcher(binaryOperator(
    anyOf(hasOperatorName("=="), hasOperatorName("!=")),
    hasLHS(AnyFunc),
    hasRHS(AnyFunc)).bind("op"), this);

Or something close to that effect.