@@ -34,9 +34,9 @@ namespace {
34
34
class InnerPointerChecker
35
35
: public Checker<check::DeadSymbols, check::PostCall> {
36
36
37
- CallDescription AppendFn, AssignFn, ClearFn, CStrFn, DataFn, EraseFn ,
38
- InsertFn, PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn ,
39
- ShrinkToFitFn, SwapFn;
37
+ CallDescription AppendFn, AssignFn, AddressofFn, ClearFn, CStrFn, DataFn,
38
+ DataMemberFn, EraseFn, InsertFn, PopBackFn, PushBackFn, ReplaceFn ,
39
+ ReserveFn, ResizeFn, ShrinkToFitFn, SwapFn;
40
40
41
41
public:
42
42
class InnerPointerBRVisitor : public BugReporterVisitor {
@@ -73,9 +73,10 @@ class InnerPointerChecker
73
73
InnerPointerChecker ()
74
74
: AppendFn({" std" , " basic_string" , " append" }),
75
75
AssignFn ({" std" , " basic_string" , " assign" }),
76
+ AddressofFn ({" std" , " addressof" }),
76
77
ClearFn ({" std" , " basic_string" , " clear" }),
77
- CStrFn ({" std" , " basic_string" , " c_str" }),
78
- DataFn ({" std" , " basic_string" , " data" }),
78
+ CStrFn ({" std" , " basic_string" , " c_str" }), DataFn({ " std " , " data " }, 1 ),
79
+ DataMemberFn ({" std" , " basic_string" , " data" }),
79
80
EraseFn ({" std" , " basic_string" , " erase" }),
80
81
InsertFn ({" std" , " basic_string" , " insert" }),
81
82
PopBackFn ({" std" , " basic_string" , " pop_back" }),
@@ -90,6 +91,9 @@ class InnerPointerChecker
90
91
// / pointers referring to the container object's inner buffer.
91
92
bool isInvalidatingMemberFunction (const CallEvent &Call) const ;
92
93
94
+ // / Check whether the called function returns a raw inner pointer.
95
+ bool isInnerPointerAccessFunction (const CallEvent &Call) const ;
96
+
93
97
// / Mark pointer symbols associated with the given memory region released
94
98
// / in the program state.
95
99
void markPtrSymbolsReleased (const CallEvent &Call, ProgramStateRef State,
@@ -130,6 +134,12 @@ bool InnerPointerChecker::isInvalidatingMemberFunction(
130
134
Call.isCalled (SwapFn));
131
135
}
132
136
137
+ bool InnerPointerChecker::isInnerPointerAccessFunction (
138
+ const CallEvent &Call) const {
139
+ return (Call.isCalled (CStrFn) || Call.isCalled (DataFn) ||
140
+ Call.isCalled (DataMemberFn));
141
+ }
142
+
133
143
void InnerPointerChecker::markPtrSymbolsReleased (const CallEvent &Call,
134
144
ProgramStateRef State,
135
145
const MemRegion *MR,
@@ -172,6 +182,11 @@ void InnerPointerChecker::checkFunctionArguments(const CallEvent &Call,
172
182
if (!ArgRegion)
173
183
continue ;
174
184
185
+ // std::addressof function accepts a non-const reference as an argument,
186
+ // but doesn't modify it.
187
+ if (Call.isCalled (AddressofFn))
188
+ continue ;
189
+
175
190
markPtrSymbolsReleased (Call, State, ArgRegion, C);
176
191
}
177
192
}
@@ -195,36 +210,49 @@ void InnerPointerChecker::checkPostCall(const CallEvent &Call,
195
210
CheckerContext &C) const {
196
211
ProgramStateRef State = C.getState ();
197
212
213
+ // TODO: Do we need these to be typed?
214
+ const TypedValueRegion *ObjRegion = nullptr ;
215
+
198
216
if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
199
- // TODO: Do we need these to be typed?
200
- const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
217
+ ObjRegion = dyn_cast_or_null<TypedValueRegion>(
201
218
ICall->getCXXThisVal ().getAsRegion ());
202
- if (!ObjRegion)
203
- return ;
204
219
205
- if (Call.isCalled (CStrFn) || Call.isCalled (DataFn)) {
206
- SVal RawPtr = Call.getReturnValue ();
207
- if (SymbolRef Sym = RawPtr.getAsSymbol (/* IncludeBaseRegions=*/ true )) {
208
- // Start tracking this raw pointer by adding it to the set of symbols
209
- // associated with this container object in the program state map.
220
+ // Check [string.require] / second point.
221
+ if (isInvalidatingMemberFunction (Call)) {
222
+ markPtrSymbolsReleased (Call, State, ObjRegion, C);
223
+ return ;
224
+ }
225
+ }
210
226
211
- PtrSet::Factory &F = State->getStateManager ().get_context <PtrSet>();
212
- const PtrSet *SetPtr = State->get <RawPtrMap>(ObjRegion);
213
- PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet ();
214
- assert (C.wasInlined || !Set.contains (Sym));
215
- Set = F.add (Set, Sym);
227
+ if (isInnerPointerAccessFunction (Call)) {
216
228
217
- State = State->set <RawPtrMap>(ObjRegion, Set);
218
- C.addTransition (State);
219
- }
220
- return ;
229
+ if (isa<SimpleFunctionCall>(Call)) {
230
+ // NOTE: As of now, we only have one free access function: std::data.
231
+ // If we add more functions like this in the list, hardcoded
232
+ // argument index should be changed.
233
+ ObjRegion =
234
+ dyn_cast_or_null<TypedValueRegion>(Call.getArgSVal (0 ).getAsRegion ());
221
235
}
222
236
223
- // Check [string.require] / second point.
224
- if (isInvalidatingMemberFunction (Call)) {
225
- markPtrSymbolsReleased (Call, State, ObjRegion, C);
237
+ if (!ObjRegion)
226
238
return ;
239
+
240
+ SVal RawPtr = Call.getReturnValue ();
241
+ if (SymbolRef Sym = RawPtr.getAsSymbol (/* IncludeBaseRegions=*/ true )) {
242
+ // Start tracking this raw pointer by adding it to the set of symbols
243
+ // associated with this container object in the program state map.
244
+
245
+ PtrSet::Factory &F = State->getStateManager ().get_context <PtrSet>();
246
+ const PtrSet *SetPtr = State->get <RawPtrMap>(ObjRegion);
247
+ PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet ();
248
+ assert (C.wasInlined || !Set.contains (Sym));
249
+ Set = F.add (Set, Sym);
250
+
251
+ State = State->set <RawPtrMap>(ObjRegion, Set);
252
+ C.addTransition (State);
227
253
}
254
+
255
+ return ;
228
256
}
229
257
230
258
// Check [string.require] / first point.
0 commit comments