[analyzer] Add support for __attribute__((returns_nonnull)).

Differential Revision: https://reviews.llvm.org/D118657
This commit is contained in:
Rashmi Mudduluru 2022-02-01 18:28:42 -08:00 committed by Artem Dergachev
parent 6e03a68b77
commit faabdfcf7f
7 changed files with 90 additions and 0 deletions

View File

@ -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"
//===----------------------------------------------------------------------===//

View File

@ -111,6 +111,7 @@ add_clang_library(clangStaticAnalyzerCheckers
TestAfterDivZeroChecker.cpp
TraversalChecker.cpp
TrustNonnullChecker.cpp
TrustReturnsNonnullChecker.cpp
UndefBranchChecker.cpp
UndefCapturedBlockVarChecker.cpp
UndefResultChecker.cpp

View File

@ -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;
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -118,6 +118,7 @@ static_library("Checkers") {
"TestAfterDivZeroChecker.cpp",
"TraversalChecker.cpp",
"TrustNonnullChecker.cpp",
"TrustReturnsNonnullChecker.cpp",
"UndefBranchChecker.cpp",
"UndefCapturedBlockVarChecker.cpp",
"UndefResultChecker.cpp",