forked from OSchip/llvm-project
[analyzer] Add support for __attribute__((returns_nonnull)).
Differential Revision: https://reviews.llvm.org/D118657
This commit is contained in:
parent
6e03a68b77
commit
faabdfcf7f
|
@ -376,6 +376,11 @@ def TrustNonnullChecker : Checker<"TrustNonnull">,
|
|||
"are not null">,
|
||||
Documentation<NotDocumented>;
|
||||
|
||||
def TrustReturnsNonnullChecker : Checker<"TrustReturnsNonnull">,
|
||||
HelpText<"Trust that returns from methods annotated with returns_nonnull "
|
||||
"are not null">,
|
||||
Documentation<NotDocumented>;
|
||||
|
||||
} // end "apiModeling"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -111,6 +111,7 @@ add_clang_library(clangStaticAnalyzerCheckers
|
|||
TestAfterDivZeroChecker.cpp
|
||||
TraversalChecker.cpp
|
||||
TrustNonnullChecker.cpp
|
||||
TrustReturnsNonnullChecker.cpp
|
||||
UndefBranchChecker.cpp
|
||||
UndefCapturedBlockVarChecker.cpp
|
||||
UndefResultChecker.cpp
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
//== TrustReturnsNonnullChecker.cpp -- API nullability modeling -*- C++ -*--==//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This checker adds nullability-related assumptions to methods annotated with
|
||||
// returns_nonnull attribute.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
|
||||
class TrustReturnsNonnullChecker : public Checker<check::PostCall> {
|
||||
|
||||
public:
|
||||
TrustReturnsNonnullChecker(ASTContext &Ctx) {}
|
||||
|
||||
void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
|
||||
ProgramStateRef State = C.getState();
|
||||
|
||||
if (isNonNullPtr(Call))
|
||||
if (auto L = Call.getReturnValue().getAs<Loc>())
|
||||
State = State->assume(*L, /*assumption=*/true);
|
||||
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
||||
private:
|
||||
/// \returns Whether the method declaration has the attribute returns_nonnull.
|
||||
bool isNonNullPtr(const CallEvent &Call) const {
|
||||
QualType ExprRetType = Call.getResultType();
|
||||
const Decl *CallDeclaration = Call.getDecl();
|
||||
if (!ExprRetType->isAnyPointerType() || !CallDeclaration)
|
||||
return false;
|
||||
|
||||
return CallDeclaration->hasAttr<ReturnsNonNullAttr>();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void ento::registerTrustReturnsNonnullChecker(CheckerManager &Mgr) {
|
||||
Mgr.registerChecker<TrustReturnsNonnullChecker>(Mgr.getASTContext());
|
||||
}
|
||||
|
||||
bool ento::shouldRegisterTrustReturnsNonnullChecker(const CheckerManager &mgr) {
|
||||
return true;
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
// CHECK-NEXT: core.CallAndMessageModeling
|
||||
// CHECK-NEXT: apiModeling.StdCLibraryFunctions
|
||||
// CHECK-NEXT: apiModeling.TrustNonnull
|
||||
// CHECK-NEXT: apiModeling.TrustReturnsNonnull
|
||||
// CHECK-NEXT: apiModeling.llvm.CastValue
|
||||
// CHECK-NEXT: apiModeling.llvm.ReturnValue
|
||||
// CHECK-NEXT: core.CallAndMessage
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// RUN: %clang_analyze_cc1 -analyzer-checker=core,apiModeling.TrustReturnsNonnull -verify %s
|
||||
|
||||
int *foo() __attribute__((returns_nonnull));
|
||||
|
||||
int *foo_no_attribute();
|
||||
|
||||
int test_foo() {
|
||||
int *x = foo();
|
||||
if (x) {}
|
||||
return *x; // no-warning
|
||||
}
|
||||
|
||||
int test_foo_no_attribute() {
|
||||
int *x = foo_no_attribute();
|
||||
if (x) {}
|
||||
return *x; // expected-warning{{Dereference of null pointer}}
|
||||
}
|
||||
|
||||
void test(void *(*f)(void)) {
|
||||
f(); // Shouldn't crash compiler
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
// CHECK-NEXT: apiModeling.StdCLibraryFunctions
|
||||
// CHECK-NEXT: alpha.unix.StdCLibraryFunctionArgs
|
||||
// CHECK-NEXT: apiModeling.TrustNonnull
|
||||
// CHECK-NEXT: apiModeling.TrustReturnsNonnull
|
||||
// CHECK-NEXT: apiModeling.llvm.CastValue
|
||||
// CHECK-NEXT: apiModeling.llvm.ReturnValue
|
||||
// CHECK-NEXT: core.DivideZero
|
||||
|
|
|
@ -118,6 +118,7 @@ static_library("Checkers") {
|
|||
"TestAfterDivZeroChecker.cpp",
|
||||
"TraversalChecker.cpp",
|
||||
"TrustNonnullChecker.cpp",
|
||||
"TrustReturnsNonnullChecker.cpp",
|
||||
"UndefBranchChecker.cpp",
|
||||
"UndefCapturedBlockVarChecker.cpp",
|
||||
"UndefResultChecker.cpp",
|
||||
|
|
Loading…
Reference in New Issue