@@ -307,64 +307,64 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
307
307
{{{" fclose" }, 1 },
308
308
{&StreamChecker::preDefault, &StreamChecker::evalFclose, 0 }},
309
309
{{{" fread" }, 4 },
310
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, true ) ,
310
+ {&StreamChecker::preRead ,
311
311
std::bind (&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, true ), 3 }},
312
312
{{{" fwrite" }, 4 },
313
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, false ) ,
313
+ {&StreamChecker::preWrite ,
314
314
std::bind (&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, false ), 3 }},
315
315
{{{" fgetc" }, 1 },
316
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, true ) ,
316
+ {&StreamChecker::preRead ,
317
317
std::bind (&StreamChecker::evalFgetx, _1, _2, _3, _4, true ), 0 }},
318
318
{{{" fgets" }, 3 },
319
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, true ) ,
319
+ {&StreamChecker::preRead ,
320
320
std::bind (&StreamChecker::evalFgetx, _1, _2, _3, _4, false ), 2 }},
321
321
{{{" getc" }, 1 },
322
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, true ) ,
322
+ {&StreamChecker::preRead ,
323
323
std::bind (&StreamChecker::evalFgetx, _1, _2, _3, _4, true ), 0 }},
324
324
{{{" fputc" }, 2 },
325
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, false ) ,
325
+ {&StreamChecker::preWrite ,
326
326
std::bind (&StreamChecker::evalFputx, _1, _2, _3, _4, true ), 1 }},
327
327
{{{" fputs" }, 2 },
328
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, false ) ,
328
+ {&StreamChecker::preWrite ,
329
329
std::bind (&StreamChecker::evalFputx, _1, _2, _3, _4, false ), 1 }},
330
330
{{{" putc" }, 2 },
331
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, false ) ,
331
+ {&StreamChecker::preWrite ,
332
332
std::bind (&StreamChecker::evalFputx, _1, _2, _3, _4, true ), 1 }},
333
333
{{{" fprintf" }},
334
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, false ) ,
334
+ {&StreamChecker::preWrite ,
335
335
std::bind (&StreamChecker::evalFprintf, _1, _2, _3, _4), 0 }},
336
336
{{{" vfprintf" }, 3 },
337
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, false ) ,
337
+ {&StreamChecker::preWrite ,
338
338
std::bind (&StreamChecker::evalFprintf, _1, _2, _3, _4), 0 }},
339
339
{{{" fscanf" }},
340
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, true ) ,
340
+ {&StreamChecker::preRead ,
341
341
std::bind (&StreamChecker::evalFscanf, _1, _2, _3, _4), 0 }},
342
342
{{{" vfscanf" }, 3 },
343
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, true ) ,
343
+ {&StreamChecker::preRead ,
344
344
std::bind (&StreamChecker::evalFscanf, _1, _2, _3, _4), 0 }},
345
345
{{{" ungetc" }, 2 },
346
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, false ) ,
346
+ {&StreamChecker::preWrite ,
347
347
std::bind (&StreamChecker::evalUngetc, _1, _2, _3, _4), 1 }},
348
348
{{{" getdelim" }, 4 },
349
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, true ) ,
349
+ {&StreamChecker::preRead ,
350
350
std::bind (&StreamChecker::evalGetdelim, _1, _2, _3, _4), 3 }},
351
351
{{{" getline" }, 3 },
352
- {std::bind ( &StreamChecker::preReadWrite, _1, _2, _3, _4, true ) ,
352
+ {&StreamChecker::preRead ,
353
353
std::bind (&StreamChecker::evalGetdelim, _1, _2, _3, _4), 2 }},
354
354
{{{" fseek" }, 3 },
355
355
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0 }},
356
356
{{{" fseeko" }, 3 },
357
357
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0 }},
358
358
{{{" ftell" }, 1 },
359
- {&StreamChecker::preDefault , &StreamChecker::evalFtell, 0 }},
359
+ {&StreamChecker::preWrite , &StreamChecker::evalFtell, 0 }},
360
360
{{{" ftello" }, 1 },
361
- {&StreamChecker::preDefault , &StreamChecker::evalFtell, 0 }},
361
+ {&StreamChecker::preWrite , &StreamChecker::evalFtell, 0 }},
362
362
{{{" fflush" }, 1 },
363
363
{&StreamChecker::preFflush, &StreamChecker::evalFflush, 0 }},
364
364
{{{" rewind" }, 1 },
365
365
{&StreamChecker::preDefault, &StreamChecker::evalRewind, 0 }},
366
366
{{{" fgetpos" }, 2 },
367
- {&StreamChecker::preDefault , &StreamChecker::evalFgetpos, 0 }},
367
+ {&StreamChecker::preWrite , &StreamChecker::evalFgetpos, 0 }},
368
368
{{{" fsetpos" }, 2 },
369
369
{&StreamChecker::preDefault, &StreamChecker::evalFsetpos, 0 }},
370
370
{{{" clearerr" }, 1 },
@@ -384,12 +384,18 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
384
384
CallDescriptionMap<FnDescription> FnTestDescriptions = {
385
385
{{{" StreamTesterChecker_make_feof_stream" }, 1 },
386
386
{nullptr ,
387
- std::bind (&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof),
387
+ std::bind (&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof,
388
+ false ),
388
389
0 }},
389
390
{{{" StreamTesterChecker_make_ferror_stream" }, 1 },
390
391
{nullptr ,
391
392
std::bind (&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4,
392
- ErrorFError),
393
+ ErrorFError, false ),
394
+ 0 }},
395
+ {{{" StreamTesterChecker_make_ferror_indeterminate_stream" }, 1 },
396
+ {nullptr ,
397
+ std::bind (&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4,
398
+ ErrorFError, true ),
393
399
0 }},
394
400
};
395
401
@@ -415,8 +421,11 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
415
421
void evalFclose (const FnDescription *Desc, const CallEvent &Call,
416
422
CheckerContext &C) const ;
417
423
418
- void preReadWrite (const FnDescription *Desc, const CallEvent &Call,
419
- CheckerContext &C, bool IsRead) const ;
424
+ void preRead (const FnDescription *Desc, const CallEvent &Call,
425
+ CheckerContext &C) const ;
426
+
427
+ void preWrite (const FnDescription *Desc, const CallEvent &Call,
428
+ CheckerContext &C) const ;
420
429
421
430
void evalFreadFwrite (const FnDescription *Desc, const CallEvent &Call,
422
431
CheckerContext &C, bool IsFread) const ;
@@ -467,8 +476,8 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
467
476
const StreamErrorState &ErrorKind) const ;
468
477
469
478
void evalSetFeofFerror (const FnDescription *Desc, const CallEvent &Call,
470
- CheckerContext &C,
471
- const StreamErrorState &ErrorKind ) const ;
479
+ CheckerContext &C, const StreamErrorState &ErrorKind,
480
+ bool Indeterminate ) const ;
472
481
473
482
void preFflush (const FnDescription *Desc, const CallEvent &Call,
474
483
CheckerContext &C) const ;
@@ -849,9 +858,8 @@ void StreamChecker::evalFclose(const FnDescription *Desc, const CallEvent &Call,
849
858
C.addTransition (E.bindReturnValue (State, C, *EofVal));
850
859
}
851
860
852
- void StreamChecker::preReadWrite (const FnDescription *Desc,
853
- const CallEvent &Call, CheckerContext &C,
854
- bool IsRead) const {
861
+ void StreamChecker::preRead (const FnDescription *Desc, const CallEvent &Call,
862
+ CheckerContext &C) const {
855
863
ProgramStateRef State = C.getState ();
856
864
SVal StreamVal = getStreamArg (Desc, Call);
857
865
State = ensureStreamNonNull (StreamVal, Call.getArgExpr (Desc->StreamArgNo ), C,
@@ -865,11 +873,6 @@ void StreamChecker::preReadWrite(const FnDescription *Desc,
865
873
if (!State)
866
874
return ;
867
875
868
- if (!IsRead) {
869
- C.addTransition (State);
870
- return ;
871
- }
872
-
873
876
SymbolRef Sym = StreamVal.getAsSymbol ();
874
877
if (Sym && State->get <StreamMap>(Sym)) {
875
878
const StreamState *SS = State->get <StreamMap>(Sym);
@@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc,
880
883
}
881
884
}
882
885
886
+ void StreamChecker::preWrite (const FnDescription *Desc, const CallEvent &Call,
887
+ CheckerContext &C) const {
888
+ ProgramStateRef State = C.getState ();
889
+ SVal StreamVal = getStreamArg (Desc, Call);
890
+ State = ensureStreamNonNull (StreamVal, Call.getArgExpr (Desc->StreamArgNo ), C,
891
+ State);
892
+ if (!State)
893
+ return ;
894
+ State = ensureStreamOpened (StreamVal, C, State);
895
+ if (!State)
896
+ return ;
897
+ State = ensureNoFilePositionIndeterminate (StreamVal, C, State);
898
+ if (!State)
899
+ return ;
900
+
901
+ C.addTransition (State);
902
+ }
903
+
883
904
void StreamChecker::evalFreadFwrite (const FnDescription *Desc,
884
905
const CallEvent &Call, CheckerContext &C,
885
906
bool IsFread) const {
@@ -1496,14 +1517,16 @@ void StreamChecker::preDefault(const FnDescription *Desc, const CallEvent &Call,
1496
1517
1497
1518
void StreamChecker::evalSetFeofFerror (const FnDescription *Desc,
1498
1519
const CallEvent &Call, CheckerContext &C,
1499
- const StreamErrorState &ErrorKind) const {
1520
+ const StreamErrorState &ErrorKind,
1521
+ bool Indeterminate) const {
1500
1522
ProgramStateRef State = C.getState ();
1501
1523
SymbolRef StreamSym = getStreamArg (Desc, Call).getAsSymbol ();
1502
1524
assert (StreamSym && " Operation not permitted on non-symbolic stream value." );
1503
1525
const StreamState *SS = State->get <StreamMap>(StreamSym);
1504
1526
assert (SS && " Stream should be tracked by the checker." );
1505
1527
State = State->set <StreamMap>(
1506
- StreamSym, StreamState::getOpened (SS->LastOperation , ErrorKind));
1528
+ StreamSym,
1529
+ StreamState::getOpened (SS->LastOperation , ErrorKind, Indeterminate));
1507
1530
C.addTransition (State);
1508
1531
}
1509
1532
0 commit comments