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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

24

25using namespace clang;

26using namespace ento;

27

28

31

32

33namespace {

34

35class InnerPointerChecker

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

37

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

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

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

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

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

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

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

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

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

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

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

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

51

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

55

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

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

60

61public:

64

65 public:

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

67

68 static void *getTag() {

69 static int Tag = 0;

70 return &Tag;

71 }

72

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

74 ID.AddPointer(getTag());

75 }

76

80

81

82

84 RawPtrMapTy Map = State->get();

85 for (const auto &Entry : Map) {

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

87 return true;

88 }

89 return false;

90 }

91 };

92

93

94

95 bool isInvalidatingMemberFunction(const CallEvent &Call) const;

96

97

98

102

103

104

105

108

109

110

111

113

114

116};

117

118}

119

120bool InnerPointerChecker::isInvalidatingMemberFunction(

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

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

125 return true;

126 return false;

127 }

128 return isa(Call) ||

129 InvalidatingMemberFunctions.contains(Call);

130}

131

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

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

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

138 for (const auto Symbol : *PS) {

139

140

142 }

143 State = State->remove(MR);

144 C.addTransition(State);

145 return;

146 }

147}

148

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

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

155 return;

156

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

161 continue;

162

163

164

165 bool isaMemberOpCall = isa(FC);

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

167

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

169 const auto *ArgRegion =

170 dyn_cast_or_null(Arg.getAsRegion());

171 if (!ArgRegion)

172 continue;

173

174

175

176 if (AddressofFunctions.contains(Call))

177 continue;

178

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

180 }

181 }

182}

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

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

201

202

204

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

206 ObjRegion = dyn_cast_or_null(

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

208

209

210 if (isInvalidatingMemberFunction(Call)) {

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

212 return;

213 }

214 }

215

216 if (InnerPointerAccessFunctions.contains(Call)) {

217

218 if (isa(Call)) {

219

220

221

222 ObjRegion =

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

224 }

225

226 if (!ObjRegion)

227 return;

228

229 SVal RawPtr = Call.getReturnValue();

231

232

233

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

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

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

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

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

239

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

241 C.addTransition(State);

242 }

243

244 return;

245 }

246

247

248 checkFunctionArguments(Call, State, C);

249}

250

251void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,

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

255 RawPtrMapTy RPM = State->get();

256 for (const auto &Entry : RPM) {

258

259

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

261 }

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

263 PtrSet CleanedUpSet = *OldSet;

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

265 if (!SymReaper.isLive(Symbol))

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

267 }

268 State = CleanedUpSet.isEmpty()

269 ? State->remove(Entry.first)

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

271 }

272 }

273 C.addTransition(State);

274}

275

277namespace ento {

278namespace allocation_state {

279

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

282}

283

285 RawPtrMapTy Map = State->get();

286 for (const auto &Entry : Map) {

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

288 return Entry.first;

289 }

290 }

291 return nullptr;

292}

293

294}

295}

296}

297

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

302 return nullptr;

303

305 if (!S)

306 return nullptr;

307

310 const auto *TypedRegion = cast(ObjRegion);

312

314 llvm::raw_svector_ostream OS(Buf);

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

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

319}

320

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

324}

325

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

327 return true;

328}

#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

This represents one expression.

Represents a function declaration or definition.

const ParmVarDecl * getParamDecl(unsigned i) const

unsigned getNumParams() const

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

A (possibly-)qualified type.

bool isConstQualified() const

Determine whether this type is const-qualified.

Stmt - This represents one statement.

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

BugReporterVisitors are used to add custom diagnostics along a path.

An immutable set of CallDescriptions.

A CallDescription is a pattern that can be used to match calls based on the qualified name and the ar...

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

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

Used to register checkers.

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.

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.

const MemRegion * getAsRegion() const

A class responsible for cleaning up unused symbols.

bool isLiveRegion(const MemRegion *region)

bool isLive(SymbolRef sym)

TypedRegion - An abstract class representing regions that are typed.

TypedValueRegion - An abstract class representing regions having a typed value.

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

const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)

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

void registerInnerPointerCheckerAux(CheckerManager &Mgr)

Register the part of MallocChecker connected to InnerPointerChecker.

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.