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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

46#include "llvm/Support/raw_ostream.h"

47

48using namespace clang;

49using namespace ento;

50

55

56namespace {

57class ObjCSelfInitChecker : public Checker< check::PostObjCMessage,

58 check::PostStmt,

59 check::PreStmt,

60 check::PreCall,

61 check::PostCall,

62 check::Location,

63 check::Bind > {

64 const BugType BT{this, "Missing \"self = [(super or self) init...]\"",

66

67 void checkForInvalidSelf(const Expr *E, CheckerContext &C,

68 const char *errorStr) const;

69

70public:

71 void checkPostObjCMessage(const ObjCMethodCall &Msg, CheckerContext &C) const;

72 void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;

73 void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;

74 void checkLocation(SVal location, bool isLoad, const Stmt *S,

75 CheckerContext &C) const;

76 void checkBind(SVal loc, SVal val, const Stmt *S, bool AtDeclInit,

77 CheckerContext &C) const;

78

79 void checkPreCall(const CallEvent &CE, CheckerContext &C) const;

80 void checkPostCall(const CallEvent &CE, CheckerContext &C) const;

81

83 const char *NL, const char *Sep) const override;

84};

85}

86

87namespace {

88enum SelfFlagEnum {

89

90 SelfFlag_None = 0x0,

91

92 SelfFlag_Self = 0x1,

93

94 SelfFlag_InitRes = 0x2

95};

96}

97

100

101

102

103

104

106

108 if (SymbolRef sym = val.getAsSymbol())

109 if (const SelfFlagEnum *attachedFlags = state->get(sym))

110 return *attachedFlags;

111 return SelfFlag_None;

112}

113

117

120

122 state = state->set(sym,

123 SelfFlagEnum(getSelfFlags(val, state) | flag));

124 C.addTransition(state);

125 }

126}

127

131

132

133

134

136 SVal exprVal = C.getSVal(E);

138 return false;

139 if (hasSelfFlag(exprVal, SelfFlag_InitRes, C))

140 return false;

141

142 return true;

143}

144

145void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C,

146 const char *errorStr) const {

147 if (!E)

148 return;

149

150 if (C.getState()->get())

151 return;

152

154 return;

155

156

157 ExplodedNode *N = C.generateErrorNode();

158 if (!N)

159 return;

160

161 C.emitReport(std::make_unique(BT, errorStr, N));

162}

163

164void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,

165 CheckerContext &C) const {

166

167

168

169

170

172 C.getCurrentAnalysisDeclContext()->getDecl())))

173 return;

174

176

178

179

180

181

182 state = state->set(true);

183

186 return;

187 }

188

189

190

191

192

193}

194

195void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,

196 CheckerContext &C) const {

197

199 C.getCurrentAnalysisDeclContext()->getDecl())))

200 return;

201

202 checkForInvalidSelf(

204 "Instance variable used while 'self' is not set to the result of "

205 "'[(super or self) init...]'");

206}

207

208void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,

209 CheckerContext &C) const {

210

212 C.getCurrentAnalysisDeclContext()->getDecl())))

213 return;

214

216 "Returning 'self' while it is not set to the result of "

217 "'[(super or self) init...]'");

218}

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236void ObjCSelfInitChecker::checkPreCall(const CallEvent &CE,

237 CheckerContext &C) const {

238

240 C.getCurrentAnalysisDeclContext()->getDecl())))

241 return;

242

245

246

247

248

249

250 for (unsigned i = 0; i < NumArgs; ++i) {

253 SelfFlagEnum selfFlags =

255 C.addTransition(state->set(selfFlags));

256 return;

257 } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {

259 C.addTransition(state->set(selfFlags));

260 return;

261 }

262 }

263}

264

265void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,

266 CheckerContext &C) const {

267

269 C.getCurrentAnalysisDeclContext()->getDecl())))

270 return;

271

273 SelfFlagEnum prevFlags = state->get();

274 if (!prevFlags)

275 return;

276 state = state->remove();

277

279 for (unsigned i = 0; i < NumArgs; ++i) {

282

283

284

285 addSelfFlag(state, state->getSVal(argV.castAs()), prevFlags, C);

286 return;

287 } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {

288

289

290

291

293 return;

294 }

295 }

296

297 C.addTransition(state);

298}

299

300void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,

301 const Stmt *S,

302 CheckerContext &C) const {

304 C.getCurrentAnalysisDeclContext()->getDecl())))

305 return;

306

307

308

311 addSelfFlag(state, state->getSVal(location.castAs()), SelfFlag_Self,

312 C);

313}

314

315void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S,

316 bool AtDeclInit, CheckerContext &C) const {

317

318

319

320

321

326

327

329 State = State->remove();

331 State = State->remove(sym);

332 C.addTransition(State);

333 }

334}

335

336void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State,

337 const char *NL, const char *Sep) const {

338 SelfFlagTy FlagMap = State->get();

339 bool DidCallInit = State->get();

340 SelfFlagEnum PreCallFlags = State->get();

341

342 if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)

343 return;

344

345 Out << Sep << NL << "ObjCSelfInitChecker:" << NL;

346

347 if (DidCallInit)

348 Out << " An init method has been called." << NL;

349

350 if (PreCallFlags != SelfFlag_None) {

351 if (PreCallFlags & SelfFlag_Self) {

352 Out << " An argument of the current call came from the 'self' variable."

353 << NL;

354 }

355 if (PreCallFlags & SelfFlag_InitRes) {

356 Out << " An argument of the current call came from an init method."

357 << NL;

358 }

359 }

360

361 Out << NL;

362 for (auto [Sym, Flag] : FlagMap) {

363 Out << Sym << " : ";

364

365 if (Flag == SelfFlag_None)

366 Out << "none";

367

368 if (Flag & SelfFlag_Self)

369 Out << "self variable";

370

371 if (Flag & SelfFlag_InitRes) {

372 if (Flag != SelfFlag_InitRes)

373 Out << " | ";

374 Out << "result of init method";

375 }

376

377 Out << NL;

378 }

379}

380

381

382

384 if (!ND)

385 return false;

386

387 const ObjCMethodDecl *MD = dyn_cast(ND);

388 if (!MD)

389 return false;

391 return false;

392

393

394

398 for ( ; ID ; ID = ID->getSuperClass()) {

400

401 if (II == NSObjectII)

402 break;

403 }

404 return ID != nullptr;

405}

406

407

411 return false;

413 return false;

414

417 return (DR->getDecl() == analCtx->getSelfDecl());

418

419 return false;

420}

421

425

429

430

431

432

433

434void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {

436}

437

438bool ento::shouldRegisterObjCSelfInitChecker(const CheckerManager &mgr) {

439 return true;

440}

static bool isInitMessage(const ObjCMethodCall &Msg)

Definition ObjCSelfInitChecker.cpp:426

static bool isSelfVar(SVal location, CheckerContext &C)

Returns true if the location is 'self'.

Definition ObjCSelfInitChecker.cpp:408

static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND)

Definition ObjCSelfInitChecker.cpp:383

static bool isInitializationMethod(const ObjCMethodDecl *MD)

Definition ObjCSelfInitChecker.cpp:422

static bool isInvalidSelf(const Expr *E, CheckerContext &C)

Returns true of the value of the expression is the object that 'self' points to and is an object that...

Definition ObjCSelfInitChecker.cpp:135

static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state)

A call receiving a reference to 'self' invalidates the object that 'self' contains.

Definition ObjCSelfInitChecker.cpp:107

static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C)

Definition ObjCSelfInitChecker.cpp:128

static void addSelfFlag(ProgramStateRef state, SVal val, SelfFlagEnum flag, CheckerContext &C)

Definition ObjCSelfInitChecker.cpp:118

#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)

Declares an immutable map of type NameTy, suitable for placement into the ProgramState.

#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)

Declares a program state trait for type Type called Name, and introduce a type named NameTy.

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

AnalysisDeclContext contains the context data for the function, method or block under analysis.

const ImplicitParamDecl * getSelfDecl() const

ASTContext & getASTContext() const LLVM_READONLY

This represents one expression.

One of these records is kept for each identifier that is lexed.

IdentifierInfo & get(StringRef Name)

Return the identifier token info for the specified named identifier.

This represents a decl that may have a name.

Represents an ObjC class declaration.

ObjCInterfaceDecl * getSuperClass() const

const Expr * getBase() const

ObjCMethodDecl - Represents an instance or class method declaration.

ObjCMethodFamily getMethodFamily() const

Determines the family of this method.

ObjCInterfaceDecl * getClassInterface()

virtual SVal getArgSVal(unsigned Index) const

Returns the value of a given argument at the time of the call.

virtual unsigned getNumArgs() const =0

Returns the number of arguments (explicit and implicit).

SVal getReturnValue() const

Returns the return value of the call.

CHECKER * registerChecker(AT &&...Args)

Register a single-part checker (derived from Checker): construct its singleton instance,...

Simple checker classes that implement one frontend (i.e.

Represents any expression that calls an Objective-C method.

const ObjCMessageExpr * getOriginExpr() const override

Returns the expression whose value will be the result of this call.

SVal - This represents a symbolic expression, which can be either an L-value or an R-value.

SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const

If this SVal wraps a symbol return that SymbolRef.

T castAs() const

Convert to the specified SVal type, asserting that this SVal is of the desired type.

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * stripCasts(bool StripBaseCasts=true) const

Get the underlining region and strip casts.

const char *const CoreFoundationObjectiveC

IntrusiveRefCntPtr< const ProgramState > ProgramStateRef

const SymExpr * SymbolRef

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

bool isa(CodeGen::Address addr)

if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))