18
18
#include " clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19
19
#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20
20
#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
21
- #include " clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
22
21
#include " clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
23
22
#include " clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
24
23
#include " clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -235,8 +234,6 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
235
234
BugType BT_StreamEof{this , " Stream already in EOF" , " Stream handling error" };
236
235
BugType BT_ResourceLeak{this , " Resource leak" , " Stream handling error" ,
237
236
/* SuppressOnSink =*/ true };
238
- BugType BT_ArgumentNull{this , " NULL pointer" , categories::UnixAPI};
239
- BugType BT_IllegalSize{this , " Invalid buffer size" , categories::MemoryError};
240
237
241
238
public:
242
239
void checkPreCall (const CallEvent &Call, CheckerContext &C) const ;
@@ -349,10 +346,10 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
349
346
{&StreamChecker::preWrite,
350
347
std::bind (&StreamChecker::evalUngetc, _1, _2, _3, _4), 1 }},
351
348
{{{" getdelim" }, 4 },
352
- {std::bind ( &StreamChecker::preGetdelim, _1, _2, _3, _4) ,
349
+ {&StreamChecker::preRead ,
353
350
std::bind (&StreamChecker::evalGetdelim, _1, _2, _3, _4), 3 }},
354
351
{{{" getline" }, 3 },
355
- {std::bind ( &StreamChecker::preGetdelim, _1, _2, _3, _4) ,
352
+ {&StreamChecker::preRead ,
356
353
std::bind (&StreamChecker::evalGetdelim, _1, _2, _3, _4), 2 }},
357
354
{{{" fseek" }, 3 },
358
355
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0 }},
@@ -448,9 +445,6 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
448
445
void evalUngetc (const FnDescription *Desc, const CallEvent &Call,
449
446
CheckerContext &C) const ;
450
447
451
- void preGetdelim (const FnDescription *Desc, const CallEvent &Call,
452
- CheckerContext &C) const ;
453
-
454
448
void evalGetdelim (const FnDescription *Desc, const CallEvent &Call,
455
449
CheckerContext &C) const ;
456
450
@@ -502,12 +496,6 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
502
496
CheckerContext &C,
503
497
ProgramStateRef State) const ;
504
498
505
- ProgramStateRef
506
- ensurePtrNotNull (SVal PtrVal, const Expr *PtrExpr, CheckerContext &C,
507
- ProgramStateRef State, const StringRef PtrDescr,
508
- std::optional<std::reference_wrapper<const BugType>> BT =
509
- std::nullopt) const ;
510
-
511
499
// / Check that the stream is the opened state.
512
500
// / If the stream is known to be not opened an error is generated
513
501
// / and nullptr returned, otherwise the original state is returned.
@@ -531,10 +519,6 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
531
519
ProgramStateRef ensureFseekWhenceCorrect (SVal WhenceVal, CheckerContext &C,
532
520
ProgramStateRef State) const ;
533
521
534
- ProgramStateRef ensureGetdelimBufferAndSizeCorrect (
535
- SVal LinePtrPtrSVal, SVal SizePtrSVal, const Expr *LinePtrPtrExpr,
536
- const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const ;
537
-
538
522
// / Generate warning about stream in EOF state.
539
523
// / There will be always a state transition into the passed State,
540
524
// / by the new non-fatal error node or (if failed) a normal transition,
@@ -1195,110 +1179,6 @@ void StreamChecker::evalUngetc(const FnDescription *Desc, const CallEvent &Call,
1195
1179
C.addTransition (StateFailed);
1196
1180
}
1197
1181
1198
- ProgramStateRef StreamChecker::ensureGetdelimBufferAndSizeCorrect (
1199
- SVal LinePtrPtrSVal, SVal SizePtrSVal, const Expr *LinePtrPtrExpr,
1200
- const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const {
1201
- static constexpr llvm::StringLiteral SizeGreaterThanBufferSize =
1202
- " The buffer from the first argument is smaller than the size "
1203
- " specified by the second parameter" ;
1204
- static constexpr llvm::StringLiteral SizeUndef =
1205
- " The buffer from the first argument is not NULL, but the size specified "
1206
- " by the second parameter is undefined." ;
1207
-
1208
- auto EmitBugReport = [this , &C, SizePtrExpr, LinePtrPtrExpr](
1209
- ProgramStateRef BugState, StringRef ErrMsg) {
1210
- if (ExplodedNode *N = C.generateErrorNode (BugState)) {
1211
- auto R =
1212
- std::make_unique<PathSensitiveBugReport>(BT_IllegalSize, ErrMsg, N);
1213
- bugreporter::trackExpressionValue (N, SizePtrExpr, *R);
1214
- bugreporter::trackExpressionValue (N, LinePtrPtrExpr, *R);
1215
- C.emitReport (std::move (R));
1216
- }
1217
- };
1218
-
1219
- // We have a pointer to a pointer to the buffer, and a pointer to the size.
1220
- // We want what they point at.
1221
- auto LinePtrSVal = getPointeeVal (LinePtrPtrSVal, State)->getAs <DefinedSVal>();
1222
- auto NSVal = getPointeeVal (SizePtrSVal, State);
1223
- if (!LinePtrSVal || !NSVal || NSVal->isUnknown ())
1224
- return nullptr ;
1225
-
1226
- assert (LinePtrPtrExpr && SizePtrExpr);
1227
-
1228
- const auto [LinePtrNotNull, LinePtrNull] = State->assume (*LinePtrSVal);
1229
- if (LinePtrNotNull && !LinePtrNull) {
1230
- // If `*lineptr` is not null, but `*n` is undefined, there is UB.
1231
- if (NSVal->isUndef ()) {
1232
- EmitBugReport (LinePtrNotNull, SizeUndef);
1233
- return nullptr ;
1234
- }
1235
-
1236
- // If it is defined, and known, its size must be less than or equal to
1237
- // the buffer size.
1238
- auto NDefSVal = NSVal->getAs <DefinedSVal>();
1239
- auto &SVB = C.getSValBuilder ();
1240
- auto LineBufSize =
1241
- getDynamicExtent (LinePtrNotNull, LinePtrSVal->getAsRegion (), SVB);
1242
- auto LineBufSizeGtN = SVB.evalBinOp (LinePtrNotNull, BO_GE, LineBufSize,
1243
- *NDefSVal, SVB.getConditionType ())
1244
- .getAs <DefinedOrUnknownSVal>();
1245
- if (!LineBufSizeGtN)
1246
- return LinePtrNotNull;
1247
- if (auto LineBufSizeOk = LinePtrNotNull->assume (*LineBufSizeGtN, true ))
1248
- return LineBufSizeOk;
1249
-
1250
- EmitBugReport (LinePtrNotNull, SizeGreaterThanBufferSize);
1251
- return nullptr ;
1252
- }
1253
- return State;
1254
- }
1255
-
1256
- void StreamChecker::preGetdelim (const FnDescription *Desc,
1257
- const CallEvent &Call,
1258
- CheckerContext &C) const {
1259
- ProgramStateRef State = C.getState ();
1260
- SVal StreamVal = getStreamArg (Desc, Call);
1261
-
1262
- State = ensureStreamNonNull (StreamVal, Call.getArgExpr (Desc->StreamArgNo ), C,
1263
- State);
1264
- if (!State)
1265
- return ;
1266
- State = ensureStreamOpened (StreamVal, C, State);
1267
- if (!State)
1268
- return ;
1269
- State = ensureNoFilePositionIndeterminate (StreamVal, C, State);
1270
- if (!State)
1271
- return ;
1272
-
1273
- // The parameter `n` must not be NULL.
1274
- SVal SizePtrSval = Call.getArgSVal (1 );
1275
- State = ensurePtrNotNull (SizePtrSval, Call.getArgExpr (1 ), C, State, " Size" );
1276
- if (!State)
1277
- return ;
1278
-
1279
- // The parameter `lineptr` must not be NULL.
1280
- SVal LinePtrPtrSVal = Call.getArgSVal (0 );
1281
- State =
1282
- ensurePtrNotNull (LinePtrPtrSVal, Call.getArgExpr (0 ), C, State, " Line" );
1283
- if (!State)
1284
- return ;
1285
-
1286
- State = ensureGetdelimBufferAndSizeCorrect (LinePtrPtrSVal, SizePtrSval,
1287
- Call.getArgExpr (0 ),
1288
- Call.getArgExpr (1 ), C, State);
1289
- if (!State)
1290
- return ;
1291
-
1292
- SymbolRef Sym = StreamVal.getAsSymbol ();
1293
- if (Sym && State->get <StreamMap>(Sym)) {
1294
- const StreamState *SS = State->get <StreamMap>(Sym);
1295
- if (SS->ErrorState & ErrorFEof)
1296
- reportFEofWarning (Sym, C, State);
1297
- }
1298
-
1299
- C.addTransition (State);
1300
- }
1301
-
1302
1182
void StreamChecker::evalGetdelim (const FnDescription *Desc,
1303
1183
const CallEvent &Call,
1304
1184
CheckerContext &C) const {
@@ -1673,31 +1553,27 @@ ProgramStateRef
1673
1553
StreamChecker::ensureStreamNonNull (SVal StreamVal, const Expr *StreamE,
1674
1554
CheckerContext &C,
1675
1555
ProgramStateRef State) const {
1676
- return ensurePtrNotNull (StreamVal, StreamE, C, State, " Stream" , BT_FileNull);
1677
- }
1678
-
1679
- ProgramStateRef StreamChecker::ensurePtrNotNull (
1680
- SVal PtrVal, const Expr *PtrExpr, CheckerContext &C, ProgramStateRef State,
1681
- const StringRef PtrDescr,
1682
- std::optional<std::reference_wrapper<const BugType>> BT) const {
1683
- const auto Ptr = PtrVal.getAs <DefinedSVal>();
1684
- if (!Ptr)
1556
+ auto Stream = StreamVal.getAs <DefinedSVal>();
1557
+ if (!Stream)
1685
1558
return State;
1686
1559
1687
- const auto [PtrNotNull, PtrNull] = State->assume (*Ptr);
1688
- if (!PtrNotNull && PtrNull) {
1689
- if (ExplodedNode *N = C.generateErrorNode (PtrNull)) {
1560
+ ConstraintManager &CM = C.getConstraintManager ();
1561
+
1562
+ ProgramStateRef StateNotNull, StateNull;
1563
+ std::tie (StateNotNull, StateNull) = CM.assumeDual (State, *Stream);
1564
+
1565
+ if (!StateNotNull && StateNull) {
1566
+ if (ExplodedNode *N = C.generateErrorNode (StateNull)) {
1690
1567
auto R = std::make_unique<PathSensitiveBugReport>(
1691
- BT.value_or (std::cref (BT_ArgumentNull)),
1692
- (PtrDescr + " pointer might be NULL." ).str (), N);
1693
- if (PtrExpr)
1694
- bugreporter::trackExpressionValue (N, PtrExpr, *R);
1568
+ BT_FileNull, " Stream pointer might be NULL." , N);
1569
+ if (StreamE)
1570
+ bugreporter::trackExpressionValue (N, StreamE, *R);
1695
1571
C.emitReport (std::move (R));
1696
1572
}
1697
1573
return nullptr ;
1698
1574
}
1699
1575
1700
- return PtrNotNull ;
1576
+ return StateNotNull ;
1701
1577
}
1702
1578
1703
1579
ProgramStateRef StreamChecker::ensureStreamOpened (SVal StreamVal,
0 commit comments