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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

22

23using namespace clang;

24using namespace ento;

25

26

29

30

31namespace {

32

33class InnerPointerChecker

34 : public Checker<check::DeadSymbols, check::PostCall> {

35

36 CallDescriptionSet InvalidatingMemberFunctions{

37 CallDescription(CDM::CXXMethod, {"std", "basic_string", "append"}),

38 CallDescription(CDM::CXXMethod, {"std", "basic_string", "assign"}),

39 CallDescription(CDM::CXXMethod, {"std", "basic_string", "clear"}),

40 CallDescription(CDM::CXXMethod, {"std", "basic_string", "erase"}),

41 CallDescription(CDM::CXXMethod, {"std", "basic_string", "insert"}),

42 CallDescription(CDM::CXXMethod, {"std", "basic_string", "pop_back"}),

43 CallDescription(CDM::CXXMethod, {"std", "basic_string", "push_back"}),

44 CallDescription(CDM::CXXMethod, {"std", "basic_string", "replace"}),

45 CallDescription(CDM::CXXMethod, {"std", "basic_string", "reserve"}),

46 CallDescription(CDM::CXXMethod, {"std", "basic_string", "resize"}),

47 CallDescription(CDM::CXXMethod, {"std", "basic_string", "shrink_to_fit"}),

48 CallDescription(CDM::CXXMethod, {"std", "basic_string", "swap"})};

49

50 CallDescriptionSet AddressofFunctions{

51 CallDescription(CDM::SimpleFunc, {"std", "addressof"}),

52 CallDescription(CDM::SimpleFunc, {"std", "__addressof"})};

53

54 CallDescriptionSet InnerPointerAccessFunctions{

55 CallDescription(CDM::CXXMethod, {"std", "basic_string", "c_str"}),

56 CallDescription(CDM::SimpleFunc, {"std", "data"}, 1),

57 CallDescription(CDM::CXXMethod, {"std", "basic_string", "data"})};

58

59public:

60 class InnerPointerBRVisitor : public BugReporterVisitor {

62

63 public:

64 InnerPointerBRVisitor(SymbolRef Sym) : PtrToBuf(Sym) {}

65

66 static void *getTag() {

67 static int Tag = 0;

68 return &Tag;

69 }

70

71 void Profile(llvm::FoldingSetNodeID &ID) const override {

72 ID.AddPointer(getTag());

73 }

74

76 BugReporterContext &BRC,

77 PathSensitiveBugReport &BR) override;

78

79

80

82 RawPtrMapTy Map = State->get();

83 for (const auto &Entry : Map) {

84 if (Entry.second.contains(Sym))

85 return true;

86 }

87 return false;

88 }

89 };

90

91

92

93 bool isInvalidatingMemberFunction(const CallEvent &Call) const;

94

95

96

98 const MemRegion *ObjRegion,

99 CheckerContext &C) const;

100

101

102

103

104 void checkFunctionArguments(const CallEvent &Call, ProgramStateRef State,

105 CheckerContext &C) const;

106

107

108

109

110 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;

111

112

113 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;

114};

115

116}

117

118bool InnerPointerChecker::isInvalidatingMemberFunction(

120 if (const auto *MemOpCall = dyn_cast(&Call)) {

122 if (Opc == OO_Equal || Opc == OO_PlusEqual)

123 return true;

124 return false;

125 }

128}

129

130void InnerPointerChecker::markPtrSymbolsReleased(const CallEvent &Call,

132 const MemRegion *MR,

133 CheckerContext &C) const {

134 if (const PtrSet *PS = State->get(MR)) {

135 const Expr *Origin = Call.getOriginExpr();

136 for (const auto Symbol : *PS) {

137

138

140 }

141 State = State->remove(MR);

142 C.addTransition(State);

143 return;

144 }

145}

146

147void InnerPointerChecker::checkFunctionArguments(const CallEvent &Call,

149 CheckerContext &C) const {

150 if (const auto *FC = dyn_cast(&Call)) {

151 const FunctionDecl *FD = FC->getDecl();

153 return;

154

155 for (unsigned I = 0, E = FD->getNumParams(); I != E; ++I) {

159 continue;

160

161

162

164 unsigned ArgI = isaMemberOpCall ? I+1 : I;

165

166 SVal Arg = FC->getArgSVal(ArgI);

167 const auto *ArgRegion =

168 dyn_cast_or_null(Arg.getAsRegion());

169 if (!ArgRegion)

170 continue;

171

172

173

175 continue;

176

177 markPtrSymbolsReleased(Call, State, ArgRegion, C);

178 }

179 }

180}

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196void InnerPointerChecker::checkPostCall(const CallEvent &Call,

197 CheckerContext &C) const {

199

200

201 const TypedValueRegion *ObjRegion = nullptr;

202

203 if (const auto *ICall = dyn_cast(&Call)) {

204 ObjRegion = dyn_cast_or_null(

205 ICall->getCXXThisVal().getAsRegion());

206

207

208 if (isInvalidatingMemberFunction(Call)) {

209 markPtrSymbolsReleased(Call, State, ObjRegion, C);

210 return;

211 }

212 }

213

214 if (InnerPointerAccessFunctions.contains(Call)) {

215

217

218

219

220 ObjRegion =

221 dyn_cast_or_null(Call.getArgSVal(0).getAsRegion());

222 }

223

224 if (!ObjRegion)

225 return;

226

227 SVal RawPtr = Call.getReturnValue();

229

230

231

232 PtrSet::Factory &F = State->getStateManager().get_context();

233 const PtrSet *SetPtr = State->get(ObjRegion);

234 PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();

235 assert(C.wasInlined || Set.contains(Sym));

236 Set = F.add(Set, Sym);

237

238 State = State->set(ObjRegion, Set);

239 C.addTransition(State);

240 }

241

242 return;

243 }

244

245

246 checkFunctionArguments(Call, State, C);

247}

248

249void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,

250 CheckerContext &C) const {

252 PtrSet::Factory &F = State->getStateManager().get_context();

253 RawPtrMapTy RPM = State->get();

254 for (const auto &Entry : RPM) {

256

257

258 State = State->remove(Entry.first);

259 }

260 if (const PtrSet *OldSet = State->get(Entry.first)) {

261 PtrSet CleanedUpSet = *OldSet;

262 for (const auto Symbol : Entry.second) {

263 if (!SymReaper.isLive(Symbol))

264 CleanedUpSet = F.remove(CleanedUpSet, Symbol);

265 }

266 State = CleanedUpSet.isEmpty()

267 ? State->remove(Entry.first)

268 : State->set(Entry.first, CleanedUpSet);

269 }

270 }

271 C.addTransition(State);

272}

273

274namespace clang {

275namespace ento {

276namespace allocation_state {

277

279 return std::make_uniqueInnerPointerChecker::InnerPointerBRVisitor(Sym);

280}

281

283 RawPtrMapTy Map = State->get();

284 for (const auto &Entry : Map) {

285 if (Entry.second.contains(Sym)) {

286 return Entry.first;

287 }

288 }

289 return nullptr;

290}

291

292}

293}

294}

295

297 const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {

298 if (!isSymbolTracked(N->getState(), PtrToBuf) ||

300 return nullptr;

301

303 if (!S)

304 return nullptr;

305

306 const MemRegion *ObjRegion =

309 QualType ObjTy = TypedRegion->getValueType();

310

311 SmallString<256> Buf;

312 llvm::raw_svector_ostream OS(Buf);

313 OS << "Pointer to inner buffer of '" << ObjTy << "' obtained here";

316 return std::make_shared(Pos, OS.str(), true);

317}

318

319void ento::registerInnerPointerChecker(CheckerManager &Mgr) {

322}

323

324bool ento::shouldRegisterInnerPointerChecker(const CheckerManager &mgr) {

325 return true;

326}

#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)

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

#define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem)

Declares an immutable set type Name and registers the factory for such sets in the program state,...

bool isInStdNamespace() const

const ParmVarDecl * getParamDecl(unsigned i) const

unsigned getNumParams() const

Return the number of parameters this function must have based on its FunctionType.

bool isConstQualified() const

Determine whether this type is const-qualified.

bool isReferenceType() const

QualType getPointeeType() const

If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.

const SourceManager & getSourceManager() const

bool contains(const CallEvent &Call) const

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

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.

const ProgramStateRef & getState() const

const Stmt * getStmtForDiagnostics() const

If the node's program point corresponds to a statement, retrieve that statement.

const LocationContext * getLocationContext() const

ExplodedNode * getFirstPred()

MemRegion - The root abstract class for all memory regions.

SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const

If this SVal wraps a symbol return that SymbolRef.

const MemRegion * getAsRegion() const

bool isLiveRegion(const MemRegion *region)

bool isLive(SymbolRef sym)

ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)

std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)

This function provides an additional visitor that augments the bug report with information relevant t...

Definition InnerPointerChecker.cpp:278

const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)

'Sym' represents a pointer to the inner buffer of a container object.

Definition InnerPointerChecker.cpp:282

IntrusiveRefCntPtr< const ProgramState > ProgramStateRef

const SymExpr * SymbolRef

void registerInnerPointerCheckerAux(CheckerManager &Mgr)

Register the part of MallocChecker connected to InnerPointerChecker.

@ OS

Indicates that the tracking object is a descendant of a referenced-counted OSObject,...

std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef

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

OverloadedOperatorKind

Enumeration specifying the different kinds of C++ overloaded operators.

bool isa(CodeGen::Address addr)

U cast(CodeGen::Address addr)