@@ -145,6 +145,92 @@ using MutexDescriptor =
145
145
std::variant<FirstArgMutexDescriptor, MemberMutexDescriptor,
146
146
RAIIMutexDescriptor>;
147
147
148
+ class NonBlockOpenVisitor : public BugReporterVisitor {
149
+ private:
150
+ const VarRegion *VR;
151
+ const CallExpr *OpenCallExpr;
152
+ int O_NONBLOCKV;
153
+ bool Satisfied;
154
+ CallDescription OpenFunction{CDM::CLibrary, {" open" }, 2 };
155
+
156
+ public:
157
+ NonBlockOpenVisitor (const VarRegion *VR, int O_NONBLOCKV)
158
+ : VR(VR), OpenCallExpr(nullptr ), O_NONBLOCKV(O_NONBLOCKV),
159
+ Satisfied (false ) {}
160
+
161
+ static void *getTag () {
162
+ static int Tag = 0 ;
163
+ return static_cast <void *>(&Tag);
164
+ }
165
+
166
+ void Profile (llvm::FoldingSetNodeID &ID) const override {
167
+ ID.AddPointer (getTag ());
168
+ ID.AddPointer (VR);
169
+ }
170
+
171
+ PathDiagnosticPieceRef VisitNode (const ExplodedNode *N,
172
+ BugReporterContext &BRC,
173
+ PathSensitiveBugReport &BR) override {
174
+ if (Satisfied)
175
+ return nullptr ;
176
+
177
+ // check for open call's 2th argument
178
+ if (std::optional<StmtPoint> P = N->getLocationAs <StmtPoint>()) {
179
+ if (OpenCallExpr && OpenCallExpr == P->getStmtAs <CallExpr>()) {
180
+ Satisfied = true ;
181
+ const auto *openFlagExpr = OpenCallExpr->getArg (1 );
182
+ SVal flagSV = N->getSVal (openFlagExpr);
183
+ const llvm::APSInt *flagV = flagSV.getAsInteger ();
184
+ if (!flagV)
185
+ return nullptr ;
186
+
187
+ if ((*flagV & O_NONBLOCKV) != 0 )
188
+ BR.markInvalid (getTag (), nullptr );
189
+
190
+ return nullptr ;
191
+ }
192
+ }
193
+
194
+ const ExplodedNode *Pred = N->getFirstPred ();
195
+ SVal presv = Pred->getState ()->getSVal (VR);
196
+ SVal sv = N->getState ()->getSVal (VR);
197
+
198
+ // check if file descirptor's SVal changed between nodes
199
+ if (sv == presv)
200
+ return nullptr ;
201
+
202
+ std::optional<PostStore> P = N->getLocationAs <PostStore>();
203
+ if (!P)
204
+ return nullptr ;
205
+
206
+ if (const auto *DS = P->getStmtAs <DeclStmt>()) {
207
+ // variable initialization
208
+ // int fd = open(...)
209
+ const VarDecl *VD = VR->getDecl ();
210
+ if (DS->getSingleDecl () == VR->getDecl ()) {
211
+ const auto *InitCall = dyn_cast_if_present<CallExpr>(VD->getInit ());
212
+ if (!InitCall || !OpenFunction.matchesAsWritten (*InitCall))
213
+ return nullptr ;
214
+
215
+ OpenCallExpr = InitCall;
216
+ }
217
+ } else if (const auto *BO = P->getStmtAs <BinaryOperator>()) {
218
+ // assignment
219
+ // fd = open(...)
220
+ const auto *DRE = dyn_cast<DeclRefExpr>(BO->getLHS ());
221
+ if (DRE && DRE->getDecl () == VR->getDecl ()) {
222
+ const auto *InitCall = dyn_cast<CallExpr>(BO->getRHS ());
223
+ if (!InitCall || !OpenFunction.matchesAsWritten (*InitCall))
224
+ return nullptr ;
225
+
226
+ OpenCallExpr = InitCall;
227
+ }
228
+ }
229
+
230
+ return nullptr ;
231
+ }
232
+ };
233
+
148
234
class BlockInCriticalSectionChecker : public Checker <check::PostCall> {
149
235
private:
150
236
const std::array<MutexDescriptor, 8 > MutexDescriptors{
@@ -339,6 +425,36 @@ void BlockInCriticalSectionChecker::reportBlockInCritSection(
339
425
os.str (), ErrNode);
340
426
R->addRange (Call.getSourceRange ());
341
427
R->markInteresting (Call.getReturnValue ());
428
+ // for 'read' call, check whether it's file descriptor(first argument) is
429
+ // created by 'open' API with O_NONBLOCK flag and don't report for this
430
+ // situation.
431
+ if (Call.getCalleeIdentifier ()->getName () == " read" ) {
432
+ do {
433
+ const auto *arg = Call.getArgExpr (0 );
434
+ if (!arg)
435
+ break ;
436
+
437
+ const auto *DRE = dyn_cast<DeclRefExpr>(arg->IgnoreImpCasts ());
438
+ if (!DRE)
439
+ break ;
440
+
441
+ const auto *VD = dyn_cast_if_present<VarDecl>(DRE->getDecl ());
442
+ if (!VD)
443
+ break ;
444
+
445
+ const VarRegion *VR = C.getState ()->getRegion (VD, C.getLocationContext ());
446
+ if (!VR)
447
+ break ;
448
+
449
+ std::optional<int > O_NONBLOCKV = tryExpandAsInteger (
450
+ " O_NONBLOCK" , C.getBugReporter ().getPreprocessor ());
451
+ if (!O_NONBLOCKV)
452
+ break ;
453
+
454
+ R->addVisitor (
455
+ std::make_unique<NonBlockOpenVisitor>(VR, O_NONBLOCKV.value ()));
456
+ } while (false );
457
+ }
342
458
C.emitReport (std::move (R));
343
459
}
344
460
0 commit comments