Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ class AnalysisOrderChecker
llvm::errs() << " {argno: " << Call.getNumArgs() << '}';
llvm::errs() << " [" << Call.getKindAsString() << ']';
llvm::errs() << '\n';
return true;
// We can't return `true` from this callback without binding the return
// value. Let's just fallthrough here and return `false`.
}
return false;
}
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,14 @@ class CheckerDocumentation
/// state. This callback allows a checker to provide domain specific knowledge
/// about the particular functions it knows about.
///
/// Note that to evaluate a call, the handler MUST bind the return value if
/// its a non-void function. Invalidate the arguments if necessary.
///
/// Note that in general, user-provided functions should not be eval-called
/// because the checker can't predict the exact semantics/contract of the
/// callee, and by having the eval::Call callback, we also prevent it from
/// getting inlined, potentially regressing analysis quality.
///
/// \returns true if the call has been successfully evaluated
/// and false otherwise. Note, that only one checker can evaluate a call. If
/// more than one checker claims that they can evaluate the same call the
Expand Down
12 changes: 11 additions & 1 deletion clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -909,7 +909,13 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
ExplodedNodeSet DstPostCall;
StmtNodeBuilder CallBldr(DstPreCall, DstPostCall, *currBldrCtx);
for (ExplodedNode *I : DstPreCall) {
// FIXME: Provide evalCall for checkers?
// Operator new calls (CXXNewExpr) are intentionally not eval-called,
// because it does not make sense to eval-call user-provided functions.
// 1) If the new operator can be inlined, then don't prevent it from
// inlining by having an eval-call of that operator.
// 2) If it can't be inlined, then the default conservative modeling
// is what we want anyway.
// So the best is to not allow eval-calling CXXNewExprs from checkers.
defaultEvalCall(CallBldr, I, *Call);
}
// If the call is inlined, DstPostCall will be empty and we bail out now.
Expand Down Expand Up @@ -1110,6 +1116,10 @@ void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
StmtNodeBuilder Bldr(DstPreCall, DstPostCall, *currBldrCtx);
for (ExplodedNode *I : DstPreCall) {
// Intentionally either inline or conservative eval-call the operator
// delete, but triggering an eval-call event for checkers.
// As detailed at handling CXXNewExprs, in short, because it does not
// really make sense to eval-call user-provided functions.
defaultEvalCall(Bldr, I, *Call);
}
} else {
Expand Down
17 changes: 17 additions & 0 deletions clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,33 @@ void foo() {
C C0;
C C1(42);
C *C2 = new C{2, 3};
delete C2;
}

// CHECK: PreCall (C::C) [CXXConstructorCall]
// CHECK-NEXT: EvalCall (C::C) {argno: 0} [CXXConstructorCall]
// CHECK-NEXT: PostCall (C::C) [CXXConstructorCall]

// CHECK-NEXT: PreCall (C::C) [CXXConstructorCall]
// CHECK-NEXT: EvalCall (C::C) {argno: 1} [CXXConstructorCall]
// CHECK-NEXT: PostCall (C::C) [CXXConstructorCall]

// CHECK-NEXT: PreCall (operator new) [CXXAllocatorCall]
// COMMENT: Operator new calls (CXXNewExpr) are intentionally not eval-called,
// COMMENT: because it does not make sense to eval call user-provided functions.
// COMMENT: 1) If the new operator can be inlined, then don't prevent it from
// COMMENT: inlining by having an eval-call of that operator.
// COMMENT: 2) If it can't be inlined, then the default conservative modeling
// COMMENT: is what we anyways want anyway.
// COMMENT: So the EvalCall event will not be triggered for operator new calls.
// CHECK-NOT: EvalCall
// CHECK-NEXT: PostCall (operator new) [CXXAllocatorCall]

// CHECK-NEXT: PreCall (C::C) [CXXConstructorCall]
// CHECK-NEXT: EvalCall (C::C) {argno: 2} [CXXConstructorCall]
// CHECK-NEXT: PostCall (C::C) [CXXConstructorCall]

// CHECK-NEXT: PreCall (operator delete) [CXXDeallocatorCall]
// COMMENT: Same reasoning as for CXXNewExprs above.
// CHECK-NOT: EvalCall
// CHECK-NEXT: PostCall (operator delete) [CXXDeallocatorCall]