diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index df70f03f0939eae1ca123abeafca101b2b62753d..5862cfcac7e44c084ceea56063b52dd485fa97f7 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1773,6 +1773,22 @@ def SignalHandlerChecker : Checker<"SignalHandler">, Released>, ]>, Documentation; + +def RefBaseDeleteChecker : Checker<"RefBaseDelete">, + HelpText<"Check for delete refbase managed by sptr/wptr">, + Documentation; + +def OHPtrImplicitConversionChecker : Checker<"OHPtrImplicitConversion">, + HelpText<"Check for implicit conversion of pointer to sptr/wptr">, + Documentation; + +def OHPtrNotInitChecker : Checker<"OHPtrNotInit">, + HelpText<"Check for sptr/wptr not init">, + Documentation; + +def NotHeapObjChecker : Checker<"NotHeapObj">, + HelpText<"Check for assign non-heap obj to sptr/wptr">, + Documentation; } // OHOS_LOCAL end diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 1749bd6233d6f3f5ce30ebf67c4776447206ba41..bc2d51c800e161e8c46f777c3d65e8bddb099f2b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -140,6 +140,15 @@ add_clang_library(clangStaticAnalyzerCheckers OpenHarmony/PrintSensitiveInfoChecker.cpp OpenHarmony/SignalHandlerChecker.cpp + # OHOS_LOCAL begin + + OpenHarmony/RefBaseDeleteChecker.cpp + OpenHarmony/OHPtrImplicitConversionChecker.cpp + OpenHarmony/NotHeapObjChecker.cpp + OpenHarmony/OHPtrNotInitChecker.cpp + + # OHOS_LOCAL end + LINK_LIBS clangAST clangASTMatchers diff --git a/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/NotHeapObjChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/NotHeapObjChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a39e2f47d616570baf0fd000ce87efb2f03d629 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/NotHeapObjChecker.cpp @@ -0,0 +1,126 @@ +//== NotHeapObjChecker.cpp ------------------------------*- 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 defines NotHeapObjChecker, which is a path-sensitive checker +// looking for sptr or wptr try to manage non-heap object. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +#include + +using namespace clang; +using namespace ento; +using namespace llvm; + +namespace { +class NotHeapObjChecker : public Checker { + mutable std::unique_ptr BT; + +private: + void reportBug(const CallEvent &Call, CheckerContext &C) const { + if (!BT) { + BT.reset( + new BugType(this, "sptr/wptr cannot manage non-heap objects", "OH")); + } + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) { + return; + } + auto report = + std::make_unique(*BT, BT->getDescription(), N); + report->addRange(Call.getSourceRange()); + C.emitReport(std::move(report)); + } + bool isHeapObject(SVal Val) const { + /** + * Detect whether the object is on the heap, due to the existence of + * UnKnownSpaceRegion has caused a great false positive rate, so reversely + * detect whether the object is on the stack and the global data area + */ + const MemRegion *Region = Val.getAsRegion(); + if (Region && (isa(Region->getMemorySpace()) || + isa(Region->getMemorySpace()))) { + return false; + } else { + return true; + } + } + bool isOHSmartPtrCall(const CallEvent &Call) const { + /** + * Detect if the function call invoked by OH smart pointer(sptr/wptr) + */ + const auto *MethodDecl = dyn_cast_or_null(Call.getDecl()); + if (!MethodDecl || !MethodDecl->getParent()) { + return false; + } + const auto *RecordDecl = MethodDecl->getParent(); + if (RecordDecl && RecordDecl->getDeclName().isIdentifier()) { + StringRef Name = RecordDecl->getName(); + return Name == "sptr" || Name == "wptr"; + } + return false; + } + +public: + /** + * When the object is assigned to the OH smart pointer, detect whether the + * object is on the heap. + */ + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; +}; +} // end anonymous namespace + +void NotHeapObjChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + if (!isOHSmartPtrCall(Call)) { + return; + } + if (Call.getNumArgs() < 1) { + return; + } + SVal Val = Call.getArgSVal(0); + // the argument is null pointer + if (C.getState()->isNull(Val).isConstrainedTrue()) { + return; + } + // it is allowed to assigne one sptr/wptr to another + if (Call.getArgExpr(0)->getType().getAsString().find("sptr") != + std::string::npos || + Call.getArgExpr(0)->getType().getAsString().find("wptr") != + std::string::npos) { + return; + } + std::string forceStr("ForceSetRefPtr"); + /** + * if the function is ForceSetRefPtr or the constructor of sptr/wptr + * detect if the argument is on the heap + */ + if ((dyn_cast(&Call) && + dyn_cast(&Call)->getKind() == + CE_CXXConstructor) || // if a constructor + (Call.getCalleeIdentifier() && + forceStr.compare(Call.getCalleeIdentifier()->getName().data()) == 0)) { + if (!isHeapObject(Val)) { // if the object is not on the heap, report bugs + reportBug(Call, C); + } + } +} + +void ento::registerNotHeapObjChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterNotHeapObjChecker(const CheckerManager &mgr) { + return true; +} \ No newline at end of file diff --git a/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/OHPtrImplicitConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/OHPtrImplicitConversionChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71e69b0ced968db1a853ea0d7133f3ba0fc15b0c --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/OHPtrImplicitConversionChecker.cpp @@ -0,0 +1,83 @@ +//== OHPtrImplicitConversionChecker.cpp ------------------------------*- 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 defines OHPtrImplicitConversionChecker, which is a path-sensitive +// checker looking for implicit conversion from common pointer to sptr/wptr. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +#include + +using namespace clang; +using namespace ento; + +namespace { +class OHPtrImplicitConversionChecker + : public Checker> { + mutable std::unique_ptr BT; + +private: + void reportBug(const ImplicitCastExpr *Cast, CheckerContext &C) const { + if (!BT) { + BT.reset( + new BugType(this, "Implicit convert pointer to sptr/wptr", "OH")); + } + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) { + return; + } + auto report = + std::make_unique(*BT, BT->getDescription(), N); + report->addRange(Cast->getSourceRange()); + C.emitReport(std::move(report)); + } + +public: + /** + * Listen all implicit conversion, if the function is the constructor of + * sptr/wptr, report bugs. + */ + void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const; + + llvm::raw_ostream &OUTS = llvm::outs(); +}; +} // end anonymous namespace + +void OHPtrImplicitConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast, + CheckerContext &C) const { + const ProgramStateRef State = C.getState(); + NamedDecl *ND = Cast->getConversionFunction(); + if (!ND) { + return; + } + if (Cast->getCastKind() != CK_ConstructorConversion) { + return; + } + + std::string cf = ND->getNameAsString(); + if (cf == "sptr" || cf == "wptr") { + return reportBug(Cast, C); + } +} + +// builtin +void ento::registerOHPtrImplicitConversionChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterOHPtrImplicitConversionChecker( + const CheckerManager &mgr) { + return true; +} \ No newline at end of file diff --git a/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/OHPtrNotInitChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/OHPtrNotInitChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b18fba8bfc4567ef86b97127b2189db80bce47fe --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/OHPtrNotInitChecker.cpp @@ -0,0 +1,190 @@ +//== OHPtrNotInitChecker.cpp ------------------------------*- 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 defines OHPtrNotInitChecker, which is a path-sensitive checker +// looking for the usuage of sptr or wptr which is not init. +// write or execute permission +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" + +using namespace clang; +using namespace ento; +using namespace llvm; + +namespace { +class OHPtrNotInitChecker : public Checker { +public: + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + /** + * A CallBack to iterate all bindings of region store + * + * sptr/wptr has only one attribute, and it should be null pointer + * if sptr/wptr not init. + */ + class CallBack : public StoreManager::BindingsHandler { + private: + ProgramStateRef &State; + bool isNull = false; + + public: + CallBack(ProgramStateRef &S) : State(S) {} + bool HandleBinding(StoreManager &SMgr, Store S, const MemRegion *Region, + SVal Val) override { + if (State->isNull(Val).isConstrainedTrue()) { + isNull = true; + return false; + } + return true; + } + bool isNullPtr() const { return isNull; } + }; + +private: + // if the function call is invoked by sptr/wptr + bool isSmartPointer(const CallEvent &Call) const; + // detect wheather the namespace is OHOS + bool isOHOSNameSpace(const DeclContext *DC) const; + void bugReport(CheckerContext &C, const ProgramStateRef &State) const; + BugType NON_FATAL_BUG{this, "NON_FATAL_BUG", "NON_FATAL_BUG"}; +}; +} // end anonymous namespace + +// regist a map to trace the state of sptr/wptr +REGISTER_MAP_WITH_PROGRAMSTATE(InitMap, const MemRegion *, + bool) // true: don't warning +void OHPtrNotInitChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + if (!isSmartPointer(Call)) { + return; + } + + /** + * Let wptr avoid false positives, which still report bugs after initialized + * confusing... @_@ + */ + const auto *CCC = dyn_cast(&Call); + if (CCC && (Call.getNumArgs() > 0)) { + SVal Val = CCC->getCXXThisVal(); + const MemRegion *Region = Val.getAsRegion(); + State = State->set(Region, true); + C.addTransition(State); + return; + } + const auto *CMOC = dyn_cast(&Call); + if (!CMOC) { + return; + } + SVal Val = CMOC->getCXXThisVal(); + // if sptr/wptr itself is a null pointer + if (State->isNull(Val).isConstrainedTrue()) { + bugReport(C, State); + } + /** + * Because clang sometimes cannot infer the value of sptr/wptr from the + * context, there will be false positives. + * + * So we reduce false positives by tracking the state of sptr/wptr. When sptr + * and wptr have been compared with the null pointer or performed a + * not operation, it is considered impossible to be empty + */ + if (CMOC->getOverloadedOperator() == OO_Exclaim) { // ! + const MemRegion *Region = Val.getAsRegion(); + State = State->set(Region, true); + C.addTransition(State); + } + if ((CMOC->getOverloadedOperator() == OO_EqualEqual) || + (CMOC->getOverloadedOperator() == OO_ExclaimEqual)) { // ==/!= nullptr + int comparedArgIndex = 0; + SVal ArgVal = Call.getArgSVal(comparedArgIndex); + ConditionTruthVal Nullness = State->isNull(ArgVal); + if (Nullness.isConstrainedTrue()) { + const MemRegion *Region = Val.getAsRegion(); + State = State->set(Region, true); + C.addTransition(State); + } + } + /** + * When the operator-> or operator* has been invoked, and the + * sptr/wptr not init, report bugs + */ + if (CMOC->getOverloadedOperator() == OO_Arrow || + CMOC->getOverloadedOperator() == OO_Star) { // process -> and * + CallBack Cb(State); + State->getStateManager().getStoreManager().iterBindings(State->getStore(), + Cb); + const MemRegion *Region = Val.getAsRegion(); + // Whether sptr/wptr has been manually judged empty + if (State->get(Region)) { + return; + } + /** + * If the only attribute of sptr/wptr is null, then it is considered + * uninitialized and an error is reported + */ + if (Cb.isNullPtr()) { + bugReport(C, State); + } + } +} + +bool OHPtrNotInitChecker::isSmartPointer(const CallEvent &Call) const { + const auto *MethodDecl = dyn_cast_or_null(Call.getDecl()); + if (!MethodDecl) { + return false; + } + const auto *RecordDecl = MethodDecl->getParent(); + if (!RecordDecl) { + return false; + } + if (!isOHOSNameSpace(RecordDecl->getDeclContext())) { + return false; + } + if (RecordDecl->getDeclName().isIdentifier()) { + StringRef Name = RecordDecl->getName(); + return (Name == "sptr") || (Name == "wptr"); + } + + return false; +} + +bool OHPtrNotInitChecker::isOHOSNameSpace(const DeclContext *DC) const { + if (!DC->isNamespace()) + return false; + const auto *ND = cast(DC); + if (!ND) { + return false; + } + const IdentifierInfo *II = ND->getIdentifier(); + return II && II->isStr("OHOS"); +} + +void OHPtrNotInitChecker::bugReport(CheckerContext &C, + const ProgramStateRef &State) const { + ExplodedNode *N = C.generateNonFatalErrorNode(State); + + auto R = std::make_unique(NON_FATAL_BUG, + "sptr/wptr not init", N); + C.emitReport(std::move(R)); +} + +void ento::registerOHPtrNotInitChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterOHPtrNotInitChecker(const CheckerManager &mgr) { + return true; +} \ No newline at end of file diff --git a/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/RefBaseDeleteChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/RefBaseDeleteChecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24869aa9c791b73783d95fad035601c592a441d6 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/OpenHarmony/RefBaseDeleteChecker.cpp @@ -0,0 +1,222 @@ +//== RefBaseDeleteChecker.cpp ------------------------------*- 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 defines RefBaseDeleteChecker, which is a path-sensitive checker +// looking for delete a pointer managed by sptr or wptr. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +#include + +using namespace clang; +using namespace ento; +using namespace llvm; + +// registe a map to track the state of RefBase +REGISTER_MAP_WITH_PROGRAMSTATE(RefBaseStateMap, const MemRegion *, bool) +namespace { +class RefBaseDeleteChecker + : public Checker> { + mutable std::unique_ptr BT; + +private: + /** + * Detect wheather the Object is derived from RefBase + */ + bool isDerivedFromRefBase(const CXXRecordDecl *decl) const { + if (!decl || !(decl->hasDefinition())) { + return false; + } + // iterate all parents recursively + for (auto s = decl->bases_begin(), e = decl->bases_end(); s != e; s++) { + QualType qt = s->getType(); + std::string base_str = qt.getAsString(); + if (base_str == "class OHOS::RefBase") { + return true; + } + CXXRecordDecl *crd = qt->getAsCXXRecordDecl(); + if (isDerivedFromRefBase(crd)) { + return true; + } + } + return false; + } + void reportBug(const CXXDeleteExpr *DE, CheckerContext &C) const { + if (!BT) { + BT.reset(new BugType( + this, "Manually deleted the RefBase pointer managed by sptr/wptr", + "OH")); + } + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) { + return; + } + auto report = + std::make_unique(*BT, BT->getDescription(), N); + report->addRange(DE->getSourceRange()); + C.emitReport(std::move(report)); + } + + /** + * Detect wheather the object is a RefBase pointer or derived from RefBase + */ + bool isRefBasePtrOrDerived(const CXXDeleteExpr *DE, CheckerContext &C) const { + const Expr *deletedObj = DE->getArgument(); + if (!deletedObj) { + return false; + } + std::string deletedStr = deletedObj->getType().getAsString(); + if (deletedStr == "class OHOS::RefBase *") { + return true; + } + const MemRegion *mr = C.getSVal(deletedObj).getAsRegion(); + if (!mr) { + return false; + } + const MemRegion *baseRegion = mr->getBaseRegion(); + if (!baseRegion) { + return false; + } + const auto *derivedClassRegion = baseRegion->getAs(); + if (!derivedClassRegion) { + return false; + } + const CXXRecordDecl *derivedClass = + derivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl(); + return isDerivedFromRefBase(derivedClass); + } + + void addTransition(ProgramStateRef State, + const MemRegion *OtherSmartPtrRegion, + CheckerContext &C) const { + /** + * add the MemRegion of OH pointer to the map to track its state + */ + while (OtherSmartPtrRegion != OtherSmartPtrRegion->getBaseRegion()) { + // recursively find base region and track its state + // mainly for: sptr s(DerivedClassObj); + OtherSmartPtrRegion = OtherSmartPtrRegion->getBaseRegion(); + } + State = State->set(OtherSmartPtrRegion, true); + C.addTransition(State); + } + + bool isOHOSNameSpace(const CallEvent &Call) const { + /** + * detect wheather the namespace is OHOS + */ + const auto *MethodDecl = dyn_cast_or_null(Call.getDecl()); + if (!MethodDecl) { + return false; + } + const auto *RecordDecl = MethodDecl->getParent(); + if (!RecordDecl) { + return false; + } + const DeclContext *DC = RecordDecl->getDeclContext(); + if (!DC) { + return false; + } + if (!DC->isNamespace()) { + return false; + } + const auto *ND = cast(DC); + if (!ND) { + return false; + } + const IdentifierInfo *II = ND->getIdentifier(); + return II && II->isStr("OHOS"); + } + + bool isSmartPointer(const CallEvent &Call) const { + /** + * Detect if the function call invoked by OH smart pointer(sptr/wptr) + */ + const auto *MethodDecl = dyn_cast_or_null(Call.getDecl()); + if (!MethodDecl) { + return false; + } + const auto *RecordDecl = MethodDecl->getParent(); + if (!RecordDecl) { + return false; + } + if (!isOHOSNameSpace(Call)) { + return false; + } + if (RecordDecl->getDeclName().isIdentifier()) { + StringRef Name = RecordDecl->getName(); + return (Name == "sptr") || (Name == "wptr"); + } + + return false; + } + +public: + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const; +}; +} // end anonymous namespace + +void RefBaseDeleteChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + /** + * after analyzing, when assign a refbase to sptr/wptr, its + * index always 0. + * here directely track state of argument whose inddex is 0. + */ + if (!isSmartPointer(Call)) { + return; + } + if (Call.getNumArgs() < 1) { + return; + } + const MemRegion *ParamRegion = Call.getArgSVal(0).getAsRegion(); + if (!ParamRegion) { + return; + } + addTransition(Call.getState(), ParamRegion, C); +} +void RefBaseDeleteChecker::checkPreStmt(const CXXDeleteExpr *DE, + CheckerContext &C) const { + /** + * Listen to all delete statements, if it is found that the deleted object is + * a refbase pointer and is in the map, an warning will be reported + */ + if (!isRefBasePtrOrDerived(DE, C)) { + return; + } + const Expr *DeletedObj = DE->getArgument(); + const MemRegion *MR = C.getSVal(DeletedObj).getAsRegion(); + if (!MR) { + return; + } + while (MR != MR->getBaseRegion()) { + MR = MR->getBaseRegion(); + } + const ProgramStateRef State = C.getState(); + const bool *tracked = State->get(MR); + if (tracked) { + reportBug(DE, C); + } +} + +// builtin +void ento::registerRefBaseDeleteChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterRefBaseDeleteChecker(const CheckerManager &mgr) { + return true; +} \ No newline at end of file diff --git a/clang/test/Analysis/implicit_conversion.cpp b/clang/test/Analysis/implicit_conversion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b211c758eee8b1d2219550581ce0eea60593553 --- /dev/null +++ b/clang/test/Analysis/implicit_conversion.cpp @@ -0,0 +1,68 @@ +// RUN: %clang --analyze -Xanalyzer -analyzer-checker=openharmony.OHPtrImplicitConversion %s + +#include "refbase.h" + +using namespace std; +using namespace OHOS; + +class Derived:public RefBase{}; +void sptr_test_good_case01(){ + sptr s(new RefBase); +} + +void sptr_test_good_case02(){ + sptr s(new Derived()); +} + +void sptr_test_good_case03(){ + class Derived:public RefBase{}; + sptr s(new Derived()); +} + +sptr sptr_test_good_case0405_helper(sptr s){ + return s; +} + +void sptr_test_good_case04(){ + sptr s(new RefBase()); + sptr sp = sptr_test_good_case0405_helper(s); +} + +sptr sptr_test_good_case05(){ + sptr s(new RefBase()); + sptr p = sptr_test_good_case0405_helper(s); +} + +void sptr_test_bad_case01(){ + sptr s = new RefBase(); // expected-warning {{Implicit convert pointer to sptr/wptr}} +} + +void sptr_test_bad_case02(){ + class Derived:public RefBase{}; + sptr s = new Derived(); // expected-warning {{Implicit convert pointer to sptr/wptr}} +} + +sptr sptr_test_bad_case03_helper(sptr s){ + return s.GetRefPtr(); // expected-warning {{Implicit convert pointer to sptr/wptr}} +} + +void sptr_test_bad_case03(){ + RefBase *r = new RefBase(); + sptr s = sptr_test_bad_case03_helper(r); // expected-warning {{Implicit convert pointer to sptr/wptr}} +} + +void sptr_test_bad_case04(){ + sptr s = nullptr; // expected-warning {{Implicit convert pointer to sptr/wptr}} +} + + +/********************wptr******************/ +void wptr_test_good_case01(){ + wptr w(new RefBase()); + wptr wp = w; +} + +void wptr_test_bad_case01(){ + RefBase * r = new Derived(); + wptr w = r; // expected-warning {{Implicit convert pointer to sptr/wptr}} +} diff --git a/clang/test/Analysis/nonheap.cpp b/clang/test/Analysis/nonheap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b2d47f57a36193537c4578110ad43cb5a7708393 --- /dev/null +++ b/clang/test/Analysis/nonheap.cpp @@ -0,0 +1,44 @@ +// RUN: %clang --analyze -Xanalyzer -analyzer-checker=openharmony.NotHeapObj %s + +#include "refbase.h" + +using namespace std; +using namespace OHOS; + +void sptr_test_good_case01(){ + RefBase *r = new RefBase(); + sptr s(r); +} + +RefBase *g_helper = new RefBase(); +void sptr_test_good_case02(){ + sptr s(g_helper); +} + +void sptr_test_bad_case01(){ + RefBase r; + sptr s(&r); // expected-warning {{sptr/wptr cannot manage non-heap objects}} +} +RefBase b_helper; +void sptr_test_bad_case02(){ + sptr s(&b_helper); // expected-warning {{sptr/wptr cannot manage non-heap objects}} +} + + +/********************wptr******************/ +void wptr_test_good_case01(){ + RefBase *r = new RefBase(); + wptr w(r); +} + +void wptr_test_good_case02(){ + wptr w(g_helper); +} + +void wptr_test_bad_case01(){ + wptr w(&b_helper); // expected-warning {{sptr/wptr cannot manage non-heap objects}} +} +void wptr_test_bad_case02(){ + RefBase r; + wptr s(&r); // expected-warning {{sptr/wptr cannot manage non-heap objects}} +} diff --git a/clang/test/Analysis/notinit.cpp b/clang/test/Analysis/notinit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5e57bc0081b064594cbfcb3b2ee78e0e3a3d49e --- /dev/null +++ b/clang/test/Analysis/notinit.cpp @@ -0,0 +1,99 @@ +// RUN: %clang --analyze -Xanalyzer -analyzer-checker=openharmony.OHPtrNotInit %s + +#include "refbase.h" + +using namespace OHOS; + +void sptr_test_good_case01(){ + sptr s(new RefBase()); + s->GetRefCounter(); + (*s).GetRefCounter(); +} +void sptr_test_good_case02(){ + sptr s; + s.ForceSetRefPtr(new RefBase()); + s->GetRefCounter(); + (*s).GetRefCounter(); +} +void sptr_test_good_case03(){ + sptr s(new RefBase()); + sptr p(new RefBase); + s = p; + s->GetRefCounter(); + (*s).GetRefCounter(); +} +void sptr_test_good_case04(){ + sptr s; + s.ForceSetRefPtr(new RefBase()); + s->GetRefCounter(); +} + + + + +void sptr_test_good_case05(sptr s){ + if(s == nullptr){ + return; + } + s->GetRefCounter(); +} + + +void sptr_test_good_case06(){ + class D{ + public: + sptr s = new RefBase(); + }; + D d; + if(1 < 2 || d.s == nullptr){ + return; + } + if(d.s->GetRefCounter() == nullptr){ + d.s->GetRefCounter(); + } +} + + + +void sptr_test_good_case07_helper01(sptr s){ + if(s == nullptr){ + return; + } + s->GetRefCounter(); +} +void sptr_test_good_case07_helper02(sptr s){ + if(s){ + s->GetRefCounter(); + } +} +void sptr_test_good_case07_helper03(sptr s){ + if(s != nullptr){ + s->GetRefCounter(); + } +} +void sptr_test_good_case07(){ + sptr s; + sptr_test_good_case07_helper01(s); + sptr_test_good_case07_helper02(s); + sptr_test_good_case07_helper03(s); +} +void sptr_test_bad_case01(){ + sptr s; + s->GetRefCounter(); // expected-warning {{sptr/wptr not init}} +} +void sptr_test_bad_case02(){ + sptr s; + (*s).GetRefCounter(); // expected-warning {{sptr/wptr not init}} +} + +/*****************wptr****************/ + +void wptr_test_good_case01(){ + wptr w(new RefBase()); + w->GetRefCounter(); +} + +void wptr_test_bad_case01(){ + wptr w; + w->GetRefCounter(); // expected-warning {{sptr/wptr not init}} +} diff --git a/clang/test/Analysis/refbase.h b/clang/test/Analysis/refbase.h new file mode 100644 index 0000000000000000000000000000000000000000..505dfa6d15475d604ea4760c899351a84a227c8a --- /dev/null +++ b/clang/test/Analysis/refbase.h @@ -0,0 +1,132 @@ +namespace OHOS +{ + class RefCounter + { + public: + int i = 1; + }; + class WeakRefCounter + { + public: + WeakRefCounter(){} + WeakRefCounter(RefCounter counter){} + int i = 1; + }; + class RefBase + { + public: + RefBase(); + RefCounter *GetRefCounter() const { return refs_; } + ~RefBase() + { + delete refs_; + } + + private: + RefCounter *refs_ = new RefCounter(); + }; + + template + class sptr + { + public: + sptr() {} + sptr(T *other) : refs_(other){}; + sptr(const sptr &other) : refs_(other.GetRefPtr()) {} + sptr(sptr &&other) : refs_(other.GetRefPtr()) {} + ~sptr() { + delete refs_; // expected-warning {{Attempt to delete released memory}} + } + sptr &operator=(sptr &&other) + { + refs_ = other.GetRefPtr(); + return *this; + } + inline void ForceSetRefPtr(T *other) { refs_ = other; } + inline operator T *() const { return refs_; } + inline T &operator*() const { + return *refs_; // expected-warning {{Returning null reference}} + } + inline T *operator->() const { return refs_; } + inline bool operator!() const { return refs_ == nullptr; } + sptr &operator=(T *other) + { + refs_ = other; + return *this; + } + sptr &operator=(const sptr &other) + { + refs_ = other.GetRefPtr(); + return *this; + } + bool operator==(const T *other) const { return refs_ == other; } + inline bool operator!=(const T *other) const { return !operator==(other); } + + bool operator==(const sptr &other) const { return refs_ == other.GetRefPtr(); } + inline bool operator!=(const sptr &other) const { return !operator==(other); } + inline T *GetRefPtr() const { return refs_; } + + private: + T *refs_ = nullptr; + }; + + template + class wptr + { + template + friend class wptr; + + public: + wptr() {} + wptr(T *other) : refs_(new WeakRefCounter()) {} + + wptr(const wptr &other) : refs_(new WeakRefCounter()) {} + wptr(const sptr &other) : refs_(new WeakRefCounter(other.GetRefPtr()->GetRefCounter())) {} + template + wptr(const wptr &other) : refs_(new WeakRefCounter()) {} + template + wptr(const sptr &other) : refs_(new WeakRefCounter(other.GetRefPtr()->GetRefCounter())) {} + ~wptr() { delete refs_; } + wptr &operator=(T *other); + template + wptr &operator=(O *other); + wptr &operator=(const wptr &other); + wptr &operator=(const sptr &other); + template + wptr &operator=(const wptr &other); + template + wptr &operator=(const sptr &other); + inline T &operator*() const + { + return *GetRefPtr(); + } + inline T *operator->() const + { + return reinterpret_cast(refs_); + } + bool operator==(const T *other) const; + inline bool operator!=(const T *other) const + { + return !operator==(other); + }; + bool operator==(const wptr &other) const; + inline bool operator!=(const wptr &other) const + { + return !operator==(other); + } + bool operator==(const sptr &other) const; + inline bool operator!=(const sptr &other) const + { + return !operator==(other); + } + T *GetRefPtr() const; + int GetRefCounter() const + { + return refs_->i; + } + + private: + WeakRefCounter *refs_ = nullptr; + }; + +} \ No newline at end of file diff --git a/clang/test/Analysis/refbase_delete.cpp b/clang/test/Analysis/refbase_delete.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2cdfd1788debfef1d3376a8ce76bf221c6a8e560 --- /dev/null +++ b/clang/test/Analysis/refbase_delete.cpp @@ -0,0 +1,31 @@ +// RUN: %clang --analyze -Xanalyzer -analyzer-checker=openharmony.RefBaseDelete %s + +#include "refbase.h" + +#include + +using namespace std; +using namespace OHOS; + +void test_good_case01(){ + RefBase * r = new RefBase(); + delete r; +} + +void test_bad_case01(){ + RefBase * r = new RefBase(); + sptr s(r); + delete r; // expected-warning {{Manually deleted the RefBase pointer managed by sptr/wptr}} +} +void test_bad_case02(){ + class Derived:public RefBase{}; + Derived* d = new Derived(); + sptr s(d); + delete d; // expected-warning {{Manually deleted the RefBase pointer managed by sptr/wptr}} +} +void test_bad_case03(){ + class Derived:public RefBase{}; + Derived* d = new Derived(); + sptr s(d); + delete d; // expected-warning {{Manually deleted the RefBase pointer managed by sptr/wptr}} +} \ No newline at end of file