Bug 867348 - Part 1: Add an analysis that catches calls to certain functions involving arithmetic expressions; r=jrmuizel

--HG--
extra : rebase_source : d89b16b9ab591479400a3e5e89b217a67319669d
This commit is contained in:
Ehsan Akhgari 2014-12-18 15:25:15 -05:00
parent 422e060b44
commit 545e0b3667
3 changed files with 116 additions and 0 deletions

View File

@ -329,6 +329,49 @@ AST_MATCHER(QualType, nonheapClassAggregate) {
AST_MATCHER(FunctionDecl, heapAllocator) {
return MozChecker::hasCustomAnnotation(&Node, "moz_heap_allocator");
}
/// This matcher will match any declaration that is marked as not accepting
/// arithmetic expressions in its arguments.
AST_MATCHER(Decl, noArithmeticExprInArgs) {
return MozChecker::hasCustomAnnotation(&Node, "moz_no_arith_expr_in_arg");
}
/// This matcher will match all arithmetic binary operators.
AST_MATCHER(BinaryOperator, binaryArithmeticOperator) {
BinaryOperatorKind opcode = Node.getOpcode();
return opcode == BO_Mul ||
opcode == BO_Div ||
opcode == BO_Rem ||
opcode == BO_Add ||
opcode == BO_Sub ||
opcode == BO_Shl ||
opcode == BO_Shr ||
opcode == BO_And ||
opcode == BO_Xor ||
opcode == BO_Or ||
opcode == BO_MulAssign ||
opcode == BO_DivAssign ||
opcode == BO_RemAssign ||
opcode == BO_AddAssign ||
opcode == BO_SubAssign ||
opcode == BO_ShlAssign ||
opcode == BO_ShrAssign ||
opcode == BO_AndAssign ||
opcode == BO_XorAssign ||
opcode == BO_OrAssign;
}
/// This matcher will match all arithmetic unary operators.
AST_MATCHER(UnaryOperator, unaryArithmeticOperator) {
UnaryOperatorKind opcode = Node.getOpcode();
return opcode == UO_PostInc ||
opcode == UO_PostDec ||
opcode == UO_PreInc ||
opcode == UO_PreDec ||
opcode == UO_Plus ||
opcode == UO_Minus ||
opcode == UO_Not;
}
}
}
@ -367,6 +410,33 @@ DiagnosticsMatcher::DiagnosticsMatcher() {
astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(),
returns(pointerType(pointee(stackClassAggregate()))))))).bind("node"),
&stackClassChecker);
astMatcher.addMatcher(callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()),
anyOf(
hasDescendant(binaryOperator(allOf(binaryArithmeticOperator(),
hasLHS(hasDescendant(declRefExpr())),
hasRHS(hasDescendant(declRefExpr()))
)).bind("node")),
hasDescendant(unaryOperator(allOf(unaryArithmeticOperator(),
hasUnaryOperand(allOf(hasType(builtinType()),
anyOf(hasDescendant(declRefExpr()), declRefExpr())))
)).bind("node"))
)
)).bind("call"),
&arithmeticArgChecker);
astMatcher.addMatcher(constructExpr(allOf(hasDeclaration(noArithmeticExprInArgs()),
anyOf(
hasDescendant(binaryOperator(allOf(binaryArithmeticOperator(),
hasLHS(hasDescendant(declRefExpr())),
hasRHS(hasDescendant(declRefExpr()))
)).bind("node")),
hasDescendant(unaryOperator(allOf(unaryArithmeticOperator(),
hasUnaryOperand(allOf(hasType(builtinType()),
anyOf(hasDescendant(declRefExpr()), declRefExpr())))
)).bind("node"))
)
)).bind("call"),
&arithmeticArgChecker);
}
void DiagnosticsMatcher::StackClassChecker::run(
@ -472,6 +542,19 @@ void DiagnosticsMatcher::NonHeapClassChecker::noteInferred(QualType T,
noteInferred(cast<ValueDecl>(cause)->getType(), Diag);
}
void DiagnosticsMatcher::ArithmeticArgChecker::run(
const MatchFinder::MatchResult &Result) {
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
DiagnosticIDs::Error, "cannot pass an arithmetic expression of built-in types to %0");
const Expr *expr = Result.Nodes.getNodeAs<Expr>("node");
if (const CallExpr *call = Result.Nodes.getNodeAs<CallExpr>("call")) {
Diag.Report(expr->getLocStart(), errorID) << call->getDirectCallee();
} else if (const CXXConstructExpr *ctr = Result.Nodes.getNodeAs<CXXConstructExpr>("call")) {
Diag.Report(expr->getLocStart(), errorID) << ctr->getConstructor();
}
}
class MozCheckAction : public PluginASTAction {
public:
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override {

View File

@ -0,0 +1,32 @@
#define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg")))
struct X {
explicit X(int) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT;
void baz(int) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT;
};
int operator+(int, X);
int operator+(X, int);
int operator++(X);
void badArithmeticsInArgs() {
int a;
typedef int myint;
myint b;
X goodObj1(a);
goodObj1.baz(b);
X badObj1(a + b); // expected-error{{cannot pass an arithmetic expression of built-in types to 'X'}}
X badObj2 = X(a ? 0 : ++a); // expected-error{{cannot pass an arithmetic expression of built-in types to 'X'}}
X badObj3(~a); // expected-error{{cannot pass an arithmetic expression of built-in types to 'X'}}
badObj1.baz(a - 1 - b); // expected-error{{cannot pass an arithmetic expression of built-in types to 'baz'}}
badObj1.baz(++a); // expected-error{{cannot pass an arithmetic expression of built-in types to 'baz'}}
badObj1.baz(a++); // expected-error{{cannot pass an arithmetic expression of built-in types to 'baz'}}
badObj1.baz(a || b);
badObj1.baz(a + goodObj1);
badObj1.baz(goodObj1 + a);
badObj1.baz(++goodObj1);
badObj1.baz(-1);
badObj1.baz(-1.0);
badObj1.baz(1 + 2);
badObj1.baz(1 << (sizeof(int)/2));
}

View File

@ -8,6 +8,7 @@ SOURCES += [
'TestBadImplicitConversionCtor.cpp',
'TestCustomHeap.cpp',
'TestMustOverride.cpp',
'TestNoArithmeticExprInArgument.cpp',
'TestNonHeapClass.cpp',
'TestStackClass.cpp',
]