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

68 const char *errorStr) const;

69

70public:

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

77

80

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

83};

84}

85

86namespace {

87enum SelfFlagEnum {

88

89 SelfFlag_None = 0x0,

90

91 SelfFlag_Self = 0x1,

92

93 SelfFlag_InitRes = 0x2

94};

95}

96

99

100

101

102

103

105

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

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

109 return *attachedFlags;

110 return SelfFlag_None;

111}

112

115}

116

119

121 state = state->set(sym,

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

123 C.addTransition(state);

124 }

125}

126

129}

130

131

132

133

135 SVal exprVal = C.getSVal(E);

137 return false;

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

139 return false;

140

141 return true;

142}

143

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

145 const char *errorStr) const {

146 if (E)

147 return;

148

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

150 return;

151

153 return;

154

155

157 if (!N)

158 return;

159

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

161}

162

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

165

166

167

168

169

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

172 return;

173

175

177

178

179

180

181 state = state->set(true);

182

185 return;

186 }

187

188

189

190

191

192}

193

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

196

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

199 return;

200

201 checkForInvalidSelf(

202 E->getBase(), C,

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

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

205}

206

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

209

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

212 return;

213

214 checkForInvalidSelf(S->getRetValue(), C,

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

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

217}

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

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

237

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

240 return;

241

244

245

246

247

248

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

252 SelfFlagEnum selfFlags =

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

255 return;

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

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

259 return;

260 }

261 }

262}

263

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

266

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

269 return;

270

272 SelfFlagEnum prevFlags = state->get();

273 if (!prevFlags)

274 return;

275 state = state->remove();

276

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

281

282

283

285 return;

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

287

288

289

290

292 return;

293 }

294 }

295

296 C.addTransition(state);

297}

298

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

300 const Stmt *S,

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

304 return;

305

306

307

311 C);

312}

313

314

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

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 << *this << " :" << 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;

412 if (!isaloc::MemRegionVal(location))

413 return false;

414

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

418

419 return false;

420}

421

424}

425

428}

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)

static bool isSelfVar(SVal location, CheckerContext &C)

Returns true if the location is 'self'.

static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND)

static bool isInitializationMethod(const ObjCMethodDecl *MD)

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...

static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state)

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

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

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

#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

ObjCIvarRefExpr - A reference to an ObjC instance variable.

ObjCMethodDecl - Represents an instance or class method declaration.

ObjCMethodFamily getMethodFamily() const

Determines the family of this method.

ObjCInterfaceDecl * getClassInterface()

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

Stmt - This represents one statement.

Represents an abstract call to a function or method along a particular path.

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.

virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const

See CheckerManager::runCheckersForPrintState.

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

Used to register checkers.

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

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