diff --git a/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp b/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp index 1782be135427aeb2e9eec761c2cb88e8a9e6297d..dd0e64a5b37454d338eff0111e2c39de29c0b4c3 100644 --- a/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp +++ b/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp @@ -125,6 +125,8 @@ public: void VisitReturnStmt(ReturnStmt *RS); void VisitCStyleCastExpr(CStyleCastExpr *CSCE); NullabilityKind getExprPathNullability(Expr *E); + void SetCFGBlocksByExpr(Expr *PtrE, const CFGBlock *NonNullBlock, + const CFGBlock *NullableBlock); void PassConditionStatusToSuccBlocks(Stmt *Cond); void HandleNestedStructInit(DeclStmt *DS, VarDecl *TopVD, RecordDecl *RD, InitListExpr *InitList, std::string FieldPrefix); @@ -525,6 +527,38 @@ void TransferFunctions::VisitReturnStmt(ReturnStmt *RS) { } } +// This function handles CFGBlocks setting by expression +void TransferFunctions::SetCFGBlocksByExpr(Expr *PtrE, + const CFGBlock *NonNullBlock, + const CFGBlock *NullableBlock) { + if (VarDecl *VD = getVarDeclFromExpr(PtrE)) { + if (getDefNullability(VD->getType(), Ctx) == NullabilityKind::Nullable && + CurrStatusVD.count(VD) && + CurrStatusVD[VD] != NullabilityKind::NonNull) { + NCI.BlocksConditionStatusVD[NonNullBlock][Block] = + std::pair(VD, NullabilityKind::NonNull); + NCI.BlocksConditionStatusVD[NullableBlock][Block] = + std::pair(VD, NullabilityKind::Nullable); + } + } else if (MemberExpr *ME = getMemberExprFromExpr(PtrE)) { + if (auto FD = dyn_cast(ME->getMemberDecl())) { + FieldPath FP; + VisitMEForFieldPath(ME, FP); + if (getDefNullability(FD->getType(), Ctx) == NullabilityKind::Nullable && + CurrStatusFP.count(FP) && + CurrStatusFP[FP] != NullabilityKind::NonNull) { + FieldPath FP; + VisitMEForFieldPath(ME, FP); + NCI.BlocksConditionStatusFP[NonNullBlock][Block] = + std::pair(FP, NullabilityKind::NonNull); + NCI.BlocksConditionStatusFP[NullableBlock][Block] = + std::pair(FP, + NullabilityKind::Nullable); + } + } + } +} + // This function handles condition expression and // pass the conditions to successor block. void TransferFunctions::PassConditionStatusToSuccBlocks(Stmt *Cond) { @@ -549,96 +583,24 @@ void TransferFunctions::PassConditionStatusToSuccBlocks(Stmt *Cond) { 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 - ? NullabilityKind::Nullable - : NullabilityKind::NonNull; - NullabilityKind FalseKind = BO->getOpcode() == BO_EQ - ? NullabilityKind::NonNull - : NullabilityKind::Nullable; - NCI.BlocksConditionStatusVD[TrueBlock][Block] = - std::pair(VD, TrueKind); - NCI.BlocksConditionStatusVD[FalseBlock][Block] = - std::pair(VD, FalseKind); - } - } else if (MemberExpr *ME = getMemberExprFromExpr(PointerE)) { - if (auto FD = dyn_cast(ME->getMemberDecl())) { - if (getDefNullability(FD->getType(), Ctx) == - NullabilityKind::Nullable) { - NullabilityKind TrueKind = BO->getOpcode() == BO_EQ - ? NullabilityKind::Nullable - : NullabilityKind::NonNull; - NullabilityKind FalseKind = BO->getOpcode() == BO_EQ - ? NullabilityKind::NonNull - : NullabilityKind::Nullable; - FieldPath FP; - VisitMEForFieldPath(ME, FP); - NCI.BlocksConditionStatusFP[TrueBlock][Block] = - std::pair(FP, TrueKind); - NCI.BlocksConditionStatusFP[FalseBlock][Block] = - std::pair(FP, FalseKind); - } - } + if (BO->getOpcode() == BO_EQ) { + // set FalseBlock NoNull + SetCFGBlocksByExpr(PointerE, FalseBlock, TrueBlock); + } else { + // set TrueBlock NoNull + SetCFGBlocksByExpr(PointerE, TrueBlock, FalseBlock); } } } else if (auto ICE = dyn_cast(Cond)) { // Condition expr is ImplicitCastExpr, such as: if (p), if (s.p), ... - if (VarDecl *VD = getVarDeclFromExpr(ICE)) { - if (getDefNullability(VD->getType(), Ctx) == - NullabilityKind::Nullable) { - NCI.BlocksConditionStatusVD[TrueBlock][Block] = - std::pair(VD, - NullabilityKind::NonNull); - NCI.BlocksConditionStatusVD[FalseBlock][Block] = - std::pair( - VD, NullabilityKind::Nullable); - } - } else if (MemberExpr *ME = getMemberExprFromExpr(ICE)) { - if (auto FD = dyn_cast(ME->getMemberDecl())) { - if (getDefNullability(FD->getType(), Ctx) == - NullabilityKind::Nullable) { - FieldPath FP; - VisitMEForFieldPath(ME, FP); - NCI.BlocksConditionStatusFP[TrueBlock][Block] = - std::pair( - FP, NullabilityKind::NonNull); - NCI.BlocksConditionStatusFP[FalseBlock][Block] = - std::pair( - FP, NullabilityKind::Nullable); - } - } - } + // set TrueBlock NoNull + SetCFGBlocksByExpr(ICE, TrueBlock, FalseBlock); } else if (auto UO = dyn_cast(Cond)) { // Condition expr is UnaryOperator, such as: // if (!p), if (!s.p), ... if (UO->getOpcode() == UO_LNot) { - if (VarDecl *VD = getVarDeclFromExpr(UO->getSubExpr())) { - if (getDefNullability(VD->getType(), Ctx) == - NullabilityKind::Nullable) { - NCI.BlocksConditionStatusVD[TrueBlock][Block] = - std::pair( - VD, NullabilityKind::Nullable); - NCI.BlocksConditionStatusVD[FalseBlock][Block] = - std::pair( - VD, NullabilityKind::NonNull); - } - } else if (MemberExpr *ME = getMemberExprFromExpr(UO->getSubExpr())) { - if (auto FD = dyn_cast(ME->getMemberDecl())) { - if (getDefNullability(FD->getType(), Ctx) == - NullabilityKind::Nullable) { - FieldPath FP; - VisitMEForFieldPath(ME, FP); - NCI.BlocksConditionStatusFP[TrueBlock][Block] = - std::pair( - FP, NullabilityKind::Nullable); - NCI.BlocksConditionStatusFP[FalseBlock][Block] = - std::pair( - FP, NullabilityKind::NonNull); - } - } - } + // set FalseBlock NoNull + SetCFGBlocksByExpr(UO->getSubExpr(), FalseBlock, TrueBlock); } } } diff --git a/clang/test/BSC/Negative/NullabilityCheck/null_pointer_check/nested_if_null_pointer_check.cbs b/clang/test/BSC/Negative/NullabilityCheck/null_pointer_check/nested_if_null_pointer_check.cbs new file mode 100644 index 0000000000000000000000000000000000000000..48edb38b0bd901374e32ad4ba1eaae36d976e52c --- /dev/null +++ b/clang/test/BSC/Negative/NullabilityCheck/null_pointer_check/nested_if_null_pointer_check.cbs @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -nullability-check=all -verify %s + + +int test1(void) { + int * _Nullable p = nullptr; + while (p){ + if (p != nullptr) { + *p =1; + p = nullptr; + } + *p = 2; // expected-error {{nullable pointer cannot be dereferenced}} + } + return 0; +} + +int test2(void) { + int * _Nullable p = nullptr; + int * _Nullable q = nullptr; + if (p){ + if (p != nullptr) { + *p =1; + p = q; + } + *p = 2; // expected-error {{nullable pointer cannot be dereferenced}} + + }; + return 0; +} + +int test3(void) { + int * _Nullable p; + int * _Nullable q; + if (p){ + if (p != nullptr) { + *p =1; + p = q; + } + *p = 2; // expected-error {{nullable pointer cannot be dereferenced}} + } + return 0; +} + +int main() { + test1(); + test2(); + test3(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/NullabilityCheck/null_pointer_check/nested_if_null_pointer_check.cbs b/clang/test/BSC/Positive/NullabilityCheck/null_pointer_check/nested_if_null_pointer_check.cbs new file mode 100644 index 0000000000000000000000000000000000000000..be3d2dc83d6cb46cd0acb6b8a003fc212bca5a3b --- /dev/null +++ b/clang/test/BSC/Positive/NullabilityCheck/null_pointer_check/nested_if_null_pointer_check.cbs @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -nullability-check=all -verify %s +// expected-no-diagnostics + +int test1(void) { + int * _Nullable p = nullptr; + if (p != nullptr){ + if (p != nullptr) { *p =1; } + else {int a = 1;} + *p = 2; // should not report error + } + return 0; +} + +int test2(void) { + int * _Nullable p = nullptr; + if (nullptr != p){ + if (p != nullptr) { *p =1; } + else {int a = 1;} + *p = 2; // should not report error + } + return 0; +} + +int test3(void) { + int * _Nullable p = nullptr; + if (p){ + if (p != nullptr) { *p =1; } + else {int a = 1;} + *p = 2; // should not report error + } + return 0; +} + +int test4(void) { + int * _Nullable p = nullptr; + if (!p) return 1; + if (p != nullptr) { *p =1; } + *p = 2; // should not report error + return 0; +} + +struct S{ +int * _Nullable p; +}; + +int test5(void) { + struct S s ; + if (s.p != nullptr){ + if (s.p != nullptr) { *s.p =1; } + else {int a = 1;} + *s.p = 2; // should not report error + } + return 0; +} + +int test6(void) { + struct S s ; + if (s.p){ + if (s.p != nullptr) { *s.p =1; } + else {int a = 1;} + *s.p = 2; // should not report error + } + return 0; +} + +int test7(void) { + struct S s ; + if (!s.p) return 1; + if (s.p != nullptr) { *s.p =1; } + else {int a = 1;} + *s.p = 2; // should not report error + return 0; +} + +int main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + return 0; +} \ No newline at end of file