diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 1036fad80de1457196c40fe713f81d1922bb6ecc..92e3087d9dd4ed1cb230f95b0e4861e9ab4b13e4 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13062,6 +13062,11 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, } if (LHSTy->isNullPtrType()) { +#if ENABLE_BSC + // not support compile-time evaluation of null pointer comparisons for bsc + if (Info.getLangOpts().BSC && RHSTy->isPointerType()) + return false; +#endif assert(E->isComparisonOp() && "unexpected nullptr operation"); assert(RHSTy->isNullPtrType() && "missing pointer conversion"); // C++11 [expr.rel]p4, [expr.eq]p3: If two operands of type std::nullptr_t diff --git a/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp b/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp index 30393cf5e1c0b8b8a926068287304c6d3ef19c57..1782be135427aeb2e9eec761c2cb88e8a9e6297d 100644 --- a/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp +++ b/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp @@ -544,9 +544,12 @@ void TransferFunctions::PassConditionStatusToSuccBlocks(Stmt *Cond) { // Condition expr is BinaryOperator, such as: // if (p != nullptr), if (s.p != nullptr), if (p == nullptr), if (s.p != // nullptr), ... - if (BO->isEqualityOp() && BO->getRHS()->isNullExpr(Ctx)) { - Expr *LHS = BO->getLHS(); - if (VarDecl *VD = getVarDeclFromExpr(LHS)) { + bool isNullPtrEqual = + BO->getRHS()->isNullExpr(Ctx) || BO->getLHS()->isNullExpr(Ctx); + if (BO->isEqualityOp() && isNullPtrEqual) { + Expr *PointerE = + BO->getRHS()->isNullExpr(Ctx) ? BO->getLHS() : BO->getRHS(); + if (VarDecl *VD = getVarDeclFromExpr(PointerE)) { if (getDefNullability(VD->getType(), Ctx) == NullabilityKind::Nullable) { NullabilityKind TrueKind = BO->getOpcode() == BO_EQ @@ -560,7 +563,7 @@ void TransferFunctions::PassConditionStatusToSuccBlocks(Stmt *Cond) { NCI.BlocksConditionStatusVD[FalseBlock][Block] = std::pair(VD, FalseKind); } - } else if (MemberExpr *ME = getMemberExprFromExpr(LHS)) { + } else if (MemberExpr *ME = getMemberExprFromExpr(PointerE)) { if (auto FD = dyn_cast(ME->getMemberDecl())) { if (getDefNullability(FD->getType(), Ctx) == NullabilityKind::Nullable) { diff --git a/clang/lib/Analysis/BSC/BSCOwnership.cpp b/clang/lib/Analysis/BSC/BSCOwnership.cpp index 0a1a56e624f0c88795f4efd7a1203b903b60f5d5..3948ee249242559480581ffa98ac9efd37f2eb2d 100644 --- a/clang/lib/Analysis/BSC/BSCOwnership.cpp +++ b/clang/lib/Analysis/BSC/BSCOwnership.cpp @@ -1741,7 +1741,7 @@ SmallVector Ownership::OwnershipStatus::checkMemoryLeak( } } else { if (isDestructor) { - if (const ParmVarDecl *PVD = dyn_cast(VD)) { + if (isa(VD)) { if (!SOwnedOwnedFields[VD].empty()) { diags.push_back(OwnershipDiagInfo( Loc, OwnershipDiagKind::OwnedStructNotProperlyFreed, @@ -2230,9 +2230,15 @@ void OwnershipImpl::MaybeSetNull(const CFGBlock *block, return; } if (const IfStmt *IS = dyn_cast_or_null(pred->getTerminatorStmt())) { - if (const BinaryOperator *BO = dyn_cast(IS->getCond())) { - if (BO->getRHS()->isNullExpr(ctx)) { - if (const ImplicitCastExpr *ICE = dyn_cast(BO->getLHS())) { + if (const BinaryOperator *BO = + dyn_cast(IS->getCond()->IgnoreParenImpCasts())) { + bool isNullPtrEqual = + BO->getRHS()->isNullExpr(ctx) || BO->getLHS()->isNullExpr(ctx); + if (isNullPtrEqual) { + Expr *PointerE = + BO->getRHS()->isNullExpr(ctx) ? BO->getLHS() : BO->getRHS(); + if (const ImplicitCastExpr *ICE = + dyn_cast(PointerE)) { if (BO->getOpcode() == BO_EQ) { if (*pred->succ_begin() == block) // block is True branch. status.setToNull(ICE->getSubExpr()); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3b346e689b731528478a532325511604d42cfc6b..0b71868f2e77ffcd31b76bf0f9d77e036198603b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13426,7 +13426,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } #if ENABLE_BSC - if (getLangOpts().BSC && LHSType->isPointerType() && RHSType->isNullPtrType()) + if (getLangOpts().BSC && + (LHSType->isPointerType() || LHSType->isNullPtrType()) && + (RHSType->isPointerType() || RHSType->isNullPtrType())) return computeResultTy(); #endif diff --git a/clang/test/BSC/Positive/NullabilityCheck/null_pointer_check/null_pointer_check.cbs b/clang/test/BSC/Positive/NullabilityCheck/null_pointer_check/null_pointer_check.cbs new file mode 100644 index 0000000000000000000000000000000000000000..f13fca7307d9bd3a103bf7eb7f0d892357c2c9c7 --- /dev/null +++ b/clang/test/BSC/Positive/NullabilityCheck/null_pointer_check/null_pointer_check.cbs @@ -0,0 +1,79 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output | FileCheck %s +// RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include +#include + +#define RETURN_IF(expr, ret) \ + if (expr) { \ + return ret; \ + } + +safe T *owned safe_malloc(T t) { + unsafe { + T *addr = (T *)malloc(sizeof(T)); + if (!addr) { + addr = &t; + T* forget = &t; + *forget = t; + exit(EXIT_FAILURE); + } else { + *addr = t; + } + return (T *owned)addr; + } +} + +safe void safe_free(T *owned p) { + unsafe { + free((void *)p); + } +} + +safe int test(void) { + int * owned _Nullable p = nullptr; + RETURN_IF(nullptr == p, 1); + int a = 1; + p = safe_malloc(a); + RETURN_IF(nullptr == p, 1); + safe_free(p); + return 0; +} + +void nullptr_equals() { + int a = 0; + int *owned _Nullable p = nullptr; + if (nullptr == nullptr) { + printf ("nullptr equals nullptr\n"); + } else { + printf ("nullptr not equals nullptr\n"); + } + if (nullptr == p) { + printf ("nullptr equals q\n"); + } else { + printf ("nullptr not equals q\n"); + } + p = safe_malloc(4); + if (nullptr == p) { + printf ("nullptr equals q\n"); + } else { + printf ("nullptr not equals q\n"); + safe_free(p); + } + if (nullptr >= p) { + int b =1; + } +} + +int main() { + test(); + nullptr_equals(); +} + +// CHECK: nullptr equals nullptr +// CHECK-NEXT: nullptr equals q +// CHECK-NEXT: nullptr not equals q \ No newline at end of file