clang: lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

16#include

17

18using namespace clang;

19

20namespace {

21

22bool hasPublicMethodInBaseClass(const CXXRecordDecl *R, StringRef NameToMatch) {

23 assert(R);

25

28 if (MethodName == NameToMatch && MD->getAccess() == AS_public)

29 return true;

30 }

31 return false;

32}

33

34}

35

37

38std::optional<const clang::CXXRecordDecl *>

41

42 const Type *T = Base->getType().getTypePtrOrNull();

43 if (T)

44 return std::nullopt;

45

47 if (!R)

48 return std::nullopt;

50 return std::nullopt;

51

52 return hasPublicMethodInBaseClass(R, NameToMatch) ? R : nullptr;

53}

54

56 StringRef IncMethodName,

57 StringRef DecMethodName) {

58 assert(R);

59

61 if (!R)

62 return std::nullopt;

63

64 bool hasRef = hasPublicMethodInBaseClass(R, IncMethodName);

65 bool hasDeref = hasPublicMethodInBaseClass(R, DecMethodName);

66 if (hasRef && hasDeref)

67 return true;

68

71

72 bool AnyInconclusiveBase = false;

76 if (!hasRefInBase) {

77 AnyInconclusiveBase = true;

78 return false;

79 }

80 return (*hasRefInBase) != nullptr;

81 };

82

83 hasRef = hasRef || R->lookupInBases(hasPublicRefInBase, Paths,

84 true);

85 if (AnyInconclusiveBase)

86 return std::nullopt;

87

88 Paths.clear();

92 if (!hasDerefInBase) {

93 AnyInconclusiveBase = true;

94 return false;

95 }

96 return (*hasDerefInBase) != nullptr;

97 };

98 hasDeref = hasDeref || R->lookupInBases(hasPublicDerefInBase, Paths,

99 true);

100 if (AnyInconclusiveBase)

101 return std::nullopt;

102

103 return hasRef && hasDeref;

104}

105

108}

109

112 "decrementCheckedPtrCount");

113}

114

116 return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" ||

117 Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";

118}

119

121 return Name == "CheckedPtr" || Name == "CheckedRef";

122}

123

125 assert(F);

126 const std::string &FunctionName = safeGetName(F);

127

128 return isRefType(FunctionName) || FunctionName == "adoptRef" ||

129 FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" ||

130 FunctionName == "makeUniqueRefWithoutFastMallocCheck"

131

132 || FunctionName == "String" || FunctionName == "AtomString" ||

133 FunctionName == "UniqueString"

134

135 || FunctionName == "Identifier";

136}

137

139 assert(F);

141}

142

145}

146

147template

150 while (type.isNull()) {

152 type = elaboratedT->desugar();

153 continue;

154 }

156 if (!SpecialT)

157 return false;

158 auto *Decl = SpecialT->getTemplateName().getAsTemplateDecl();

160 return false;

161 return Pred(Decl->getNameAsString());

162 }

163 return false;

164}

165

169}

170

174 Name == "UniqueRef" || Name == "LazyUniqueRef";

175 });

176}

177

179 if (auto *Subst = dyn_cast(T)) {

180 if (auto *Decl = Subst->getAssociatedDecl()) {

182 return false;

183 }

184 }

186}

187

189 if (auto *Subst = dyn_cast(T)) {

190 if (auto *Decl = Subst->getAssociatedDecl()) {

192 return false;

193 }

194 }

196}

197

199{

200

202 return false;

203

205 if (!IsRefCountable)

206 return std::nullopt;

207

208 return (*IsRefCountable);

209}

210

213 return false;

215}

216

221 }

222 return false;

223}

224

229 }

230 return false;

231}

232

243 }

244 }

245 return false;

246}

247

249 assert(M);

250

251 if (isa(M)) {

253 auto className = safeGetName(calleeMethodsClass);

255

256 if (isCheckedPtr(className) && (method == "get" || method == "ptr"))

257 return true;

258

259 if ((isRefType(className) && (method == "get" || method == "ptr")) ||

260 ((className == "String" || className == "AtomString" ||

261 className == "AtomStringImpl" || className == "UniqueString" ||

262 className == "UniqueStringImpl" || className == "Identifier") &&

263 method == "impl"))

264 return true;

265

266

267

269 if (auto *maybeRefToRawOperator = dyn_cast(M))

270 return isUnsafePtr(maybeRefToRawOperator->getConversionType());

271 }

272

274 if (auto *maybeRefToRawOperator = dyn_cast(M))

275 return isUnsafePtr(maybeRefToRawOperator->getConversionType());

276 }

277 }

278 return false;

279}

280

282 assert(R);

284

285 const auto &ClassName = safeGetName(TmplR);

287 }

288 return false;

289}

290

292 assert(R);

294 const auto &ClassName = safeGetName(TmplR);

296 }

297 return false;

298}

299

301 assert(F);

303 return true;

304

305

306 const auto FunctionName = safeGetName(F);

307 if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||

308 FunctionName == "dynamicDowncast" || FunctionName == "downcast" ||

309 FunctionName == "checkedDowncast" ||

310 FunctionName == "uncheckedDowncast" || FunctionName == "bitwise_cast")

311 return true;

312

313 return false;

314}

315

317 assert(F);

318

319 if (auto *MethodDecl = dyn_cast(F)) {

320 if (!MethodDecl->isStatic())

321 return false;

322 }

324 StringRef Name = NameStr;

325 return Name == "singleton" || Name.ends_with("Singleton");

326}

327

328

329

331 : public ConstStmtVisitor<TrivialFunctionAnalysisVisitor, bool> {

332

333

334 bool VisitChildren(const Stmt *S) {

335 for (const Stmt *Child : S->children()) {

336 if (Child && Visit(Child))

337 return false;

338 }

339

340 return true;

341 }

342

343 template <typename StmtOrDecl, typename CheckFunction>

344 bool WithCachedResult(const StmtOrDecl *S, CheckFunction Function) {

345 auto CacheIt = Cache.find(S);

346 if (CacheIt != Cache.end())

347 return CacheIt->second;

348

349

350 auto [RecursiveIt, IsNew] = RecursiveFn.insert(std::make_pair(S, true));

351 if (!IsNew)

352 return RecursiveIt->second;

353

355

357 for (auto &It : RecursiveFn)

358 It.second = false;

359 }

360 RecursiveIt = RecursiveFn.find(S);

361 assert(RecursiveIt != RecursiveFn.end());

362 Result = RecursiveIt->second;

363 RecursiveFn.erase(RecursiveIt);

365

367 }

368

369public:

370 using CacheTy = TrivialFunctionAnalysis::CacheTy;

371

373

375 return WithCachedResult(D, [&]() {

376 if (auto *CtorDecl = dyn_cast(D)) {

377 for (auto *CtorInit : CtorDecl->inits()) {

378 if (!Visit(CtorInit->getInit()))

379 return false;

380 }

381 }

383 if (!Body)

384 return false;

385 return Visit(Body);

386 });

387 }

388

390

391

392 return false;

393 }

394

396

397

398 return WithCachedResult(CS, [&]() { return VisitChildren(CS); });

399 }

400

402

404 return Visit(RV);

405 return true;

406 }

407

411 return WithCachedResult(IS, [&]() { return VisitChildren(IS); });

412 }

414 return WithCachedResult(FS, [&]() { return VisitChildren(FS); });

415 }

417 return WithCachedResult(FS, [&]() { return VisitChildren(FS); });

418 }

420 return WithCachedResult(WS, [&]() { return VisitChildren(WS); });

421 }

425

426

431

433

435 }

436

438

440 }

441

443

444

445 return VisitChildren(CAO);

446 }

447

449 return VisitChildren(ASE);

450 }

451

453

454 return VisitChildren(CO);

455 }

456

458

460

461 return true;

462 }

463

466 return false;

467

469 if (!Callee)

470 return false;

472

473 if (Callee->isInStdNamespace() &&

474 (Name == "addressof" || Name == "forward" || Name == "move"))

475 return true;

476

477 if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||

478 Name == "WTFReportBacktrace" ||

479 Name == "WTFCrashWithSecurityImplication" || Name == "WTFCrash" ||

480 Name == "WTFReportAssertionFailure" || Name == "isMainThread" ||

481 Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||

482 Name == "isWebThread" || Name == "isUIThread" ||

483 Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||

484 Name == "bitwise_cast" || Name.find("__builtin") == 0 ||

485 Name == "__libcpp_verbose_abort")

486 return true;

487

489 }

490

491 bool

493

494 return true;

495 }

496

498 return VisitChildren(E);

499 }

500

502

503 return true;

504 }

505

508 return false;

509

511 if (!TrivialThis)

512 return false;

513

515 if (!Callee)

516 return false;

517

519 if (Name == "ref" || Name == "incrementCheckedPtrCount")

520 return true;

521

522 std::optional IsGetterOfRefCounted = isGetterOfSafePtr(Callee);

523 if (IsGetterOfRefCounted && *IsGetterOfRefCounted)

524 return true;

525

526

528 }

529

532 return false;

534 if (!Callee)

535 return false;

536

538 }

539

541 if (auto *Expr = E->getExpr()) {

543 return false;

544 }

545 return true;

546 }

547

550 if (Arg && Visit(Arg))

551 return false;

552 }

553 return true;

554 }

555

558 if (Arg && Visit(Arg))

559 return false;

560 }

561

562

564 }

565

568 }

569

571

574 }

575

578 }

579

582 }

583

586 if (!TrivialFunctionAnalysis::isTrivialImpl(Temp->getDestructor(), Cache))

587 return false;

588 }

590 }

591

594 }

595

597

599 for (const Expr *Child : ILE->inits()) {

600 if (Child && Visit(Child))

601 return false;

602 }

603 return true;

604 }

605

607

609 }

610

612

613 return true;

614 }

615

617

618 return true;

619 }

620

622

623 return true;

624 }

625

626

633

635

636 return true;

637 }

638

639private:

642};

643

644bool TrivialFunctionAnalysis::isTrivialImpl(

645 const Decl *D, TrivialFunctionAnalysis::CacheTy &Cache) {

647 return V.IsFunctionTrivial(D);

648}

649

650bool TrivialFunctionAnalysis::isTrivialImpl(

651 const Stmt *S, TrivialFunctionAnalysis::CacheTy &Cache) {

653 bool Result = V.Visit(S);

654 assert(Cache.contains(S) && "Top-level statement not properly cached!");

656}

657

658}

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

Defines the clang::Expr interface and subclasses for C++ expressions.

ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.

AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, __atomic_load,...

A builtin binary operation expression such as "x + y" or "x <= y".

BreakStmt - This represents a break.

Represents a path from a specific derived class (which is not represented as part of the path) to a p...

BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...

Represents a base class of a C++ class.

Represents binding an expression to a temporary.

CXXTemporary * getTemporary()

const Expr * getSubExpr() const

A boolean literal, per ([C++ lex.bool] Boolean literals).

Represents a call to a C++ constructor.

CXXConstructorDecl * getConstructor() const

Get the constructor that this expression will (ultimately) call.

A default argument (C++ [dcl.fct.default]).

CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...

Represents a call to an inherited base class constructor from an inheriting constructor.

Represents a call to a member function that may be written either with member call syntax (e....

CXXMethodDecl * getMethodDecl() const

Retrieve the declaration of the called method.

Expr * getImplicitObjectArgument() const

Retrieve the implicit object argument for the member call.

Represents a static or instance method of a struct/union/class.

const CXXRecordDecl * getParent() const

Return the parent of this method declaration, which is the class in which this method is defined.

Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".

The null pointer literal (C++11 [lex.nullptr])

A call to an overloaded operator written using operator syntax.

Represents a C++ struct/union/class.

method_range methods() const

CXXRecordDecl * getDefinition() const

const CXXRecordDecl * getTemplateInstantiationPattern() const

Retrieve the record declaration from which this record could be instantiated.

bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, bool LookupInDependent=false) const

Look for entities within the base classes of this C++ class, transitively searching all base class su...

bool hasDefinition() const

Represents the this expression in C++.

CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).

FunctionDecl * getDirectCallee()

If the callee is a FunctionDecl, return it. Otherwise return null.

CaseStmt - Represent a case statement.

CompoundAssignOperator - For compound assignments (e.g.

CompoundStmt - This represents a group of statements like { stmt stmt }.

ConditionalOperator - The ?: ternary operator.

ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.

ConstantExpr - An expression that occurs in a constant context and optionally the result of evaluatin...

ContinueStmt - This represents a continue.

A reference to a declared variable, function, enum, etc.

DeclStmt - Adaptor class for mixing declarations with statements and expressions.

Decl - This represents one declaration (or definition), e.g.

virtual Stmt * getBody() const

getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...

DoStmt - This represents a 'do/while' stmt.

Represents a type that was referred to using an elaborated type keyword, e.g., struct S,...

ExplicitCastExpr - An explicit cast written in the source code.

Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...

This represents one expression.

ForStmt - This represents a 'for (init;cond;inc)' stmt.

const Expr * getSubExpr() const

Represents a function declaration or definition.

GotoStmt - This represents a direct goto.

IfStmt - This represents an if/then/else.

ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...

Describes an C or C++ initializer list.

ArrayRef< Expr * > inits()

LabelStmt - Represents a label, which has a substatement.

Represents a prvalue temporary that is written into memory so that a reference can bind to it.

Expr * getSubExpr() const

Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.

MemberExpr - [C99 6.5.2.3] Structure and Union Members.

ParenExpr - This represents a parenthesized expression, e.g.

const Expr * getSubExpr() const

[C99 6.4.2.2] - A predefined identifier such as func.

A (possibly-)qualified type.

ReturnStmt - This represents a return, optionally of an expression: return; return 4;.

Represents a C++11 static_assert declaration.

RetTy Visit(PTR(Stmt) S, ParamTys... P)

Stmt - This represents one statement.

StringLiteral - This represents a string literal expression, e.g.

Represents a reference to a non-type template parameter that has been substituted with a template arg...

SwitchStmt - This represents a 'switch' stmt.

Represents a type template specialization; the template must be a class template, a type alias templa...

bool VisitMemberExpr(const MemberExpr *ME)

TrivialFunctionAnalysisVisitor(CacheTy &Cache)

bool VisitStringLiteral(const StringLiteral *E)

bool VisitStaticAssertDecl(const StaticAssertDecl *SAD)

bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE)

bool VisitBreakStmt(const BreakStmt *)

bool VisitCXXThisExpr(const CXXThisExpr *CTE)

bool IsFunctionTrivial(const Decl *D)

bool VisitLabelStmt(const LabelStmt *)

bool VisitUnaryOperator(const UnaryOperator *UO)

bool VisitPredefinedExpr(const PredefinedExpr *E)

bool VisitContinueStmt(const ContinueStmt *)

bool VisitSwitchStmt(const SwitchStmt *SS)

bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO)

bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)

bool VisitFixedPointLiteral(const FixedPointLiteral *E)

bool VisitDeclRefExpr(const DeclRefExpr *DRE)

bool VisitDoStmt(const DoStmt *DS)

bool VisitIfStmt(const IfStmt *IS)

bool VisitIntegerLiteral(const IntegerLiteral *E)

bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT)

bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E)

bool VisitFloatingLiteral(const FloatingLiteral *E)

TrivialFunctionAnalysis::CacheTy CacheTy

bool VisitCaseStmt(const CaseStmt *CS)

bool VisitDeclStmt(const DeclStmt *DS)

bool VisitConditionalOperator(const ConditionalOperator *CO)

bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)

bool VisitCompoundStmt(const CompoundStmt *CS)

bool VisitConstantExpr(const ConstantExpr *CE)

bool VisitImplicitCastExpr(const ImplicitCastExpr *ICE)

bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE)

bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E)

bool VisitExprWithCleanups(const ExprWithCleanups *EWC)

bool VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE)

bool VisitCallExpr(const CallExpr *CE)

bool VisitForStmt(const ForStmt *FS)

bool VisitCXXNewExpr(const CXXNewExpr *NE)

bool VisitBinaryOperator(const BinaryOperator *BO)

bool checkArguments(const CallExpr *CE)

bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE)

bool VisitCXXForRangeStmt(const CXXForRangeStmt *FS)

bool VisitGotoStmt(const GotoStmt *)

bool VisitWhileStmt(const WhileStmt *WS)

bool VisitCharacterLiteral(const CharacterLiteral *E)

bool VisitInitListExpr(const InitListExpr *ILE)

bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E)

bool VisitAtomicExpr(const AtomicExpr *E)

bool VisitStmt(const Stmt *S)

bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E)

bool VisitExplicitCastExpr(const ExplicitCastExpr *ECE)

bool VisitParenExpr(const ParenExpr *PE)

bool VisitDefaultStmt(const DefaultStmt *DS)

bool VisitCXXConstructExpr(const CXXConstructExpr *CE)

bool VisitReturnStmt(const ReturnStmt *RS)

The base class of the type hierarchy.

CXXRecordDecl * getAsCXXRecordDecl() const

Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...

bool isPointerType() const

bool isReferenceType() const

const CXXRecordDecl * getPointeeCXXRecordDecl() const

If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.

UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.

UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...

Expr * getSubExpr() const

WhileStmt - This represents a 'while' stmt.

const internal::VariadicAllOfMatcher< Type > type

Matches Types in the clang AST.

The JSON file list parser is used to communicate input to InstallAPI.

bool isCtorOfSafePtr(const clang::FunctionDecl *F)

bool isPtrConversion(const FunctionDecl *F)

std::optional< bool > isCheckedPtrCapable(const clang::CXXRecordDecl *R)

std::optional< bool > isUnchecked(const QualType T)

bool isCtorOfRefCounted(const clang::FunctionDecl *F)

@ Result

The result type of a method or function.

std::optional< bool > isRefCountable(const clang::CXXRecordDecl *R)

std::optional< const clang::CXXRecordDecl * > hasPublicMethodInBase(const CXXBaseSpecifier *Base, StringRef NameToMatch)

bool isSingleton(const FunctionDecl *F)

bool isRefCounted(const CXXRecordDecl *R)

static bool isPtrOfType(const clang::QualType T, Predicate Pred)

std::optional< bool > isSmartPtrCompatible(const CXXRecordDecl *R, StringRef IncMethodName, StringRef DecMethodName)

bool isOwnerPtrType(const clang::QualType T)

bool isSafePtrType(const clang::QualType T)

std::optional< bool > isGetterOfSafePtr(const CXXMethodDecl *M)

bool isRefType(const std::string &Name)

const FunctionProtoType * T

std::optional< bool > isUncountedPtr(const QualType T)

std::string safeGetName(const T *ASTNode)

bool isCtorOfCheckedPtr(const clang::FunctionDecl *F)

bool isCheckedPtr(const std::string &Name)

std::optional< bool > isUnsafePtr(const QualType T)

@ Class

The "class" keyword introduces the elaborated-type-specifier.

std::optional< bool > isUncounted(const QualType T)

std::optional< bool > isUncheckedPtr(const QualType T)