Author: Balázs Kéri Date: 2021-06-22T11:16:56+02:00 New Revision: d7227a5bc718940fa9bf90ba443e1dff6ded68cc
URL: https://github.com/llvm/llvm-project/commit/d7227a5bc718940fa9bf90ba443e1dff6ded68cc DIFF: https://github.com/llvm/llvm-project/commit/d7227a5bc718940fa9bf90ba443e1dff6ded68cc.diff LOG: [clang][Analyzer] Track null stream argument in alpha.unix.Stream . The checker contains check for passing a NULL stream argument. This change should make more easy to identify where the passed pointer becomes NULL. Reviewed By: NoQ Differential Revision: https://reviews.llvm.org/D104640 Added: Modified: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp clang/test/Analysis/stream-note.c Removed: ################################################################################ diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 6b176b3c4e2b2..75db1e195a432 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -306,7 +306,8 @@ class StreamChecker : public Checker<check::PreCall, eval::Call, /// If it can only be NULL a fatal error is emitted and nullptr returned. /// Otherwise the return value is a new state where the stream is constrained /// to be non-null. - ProgramStateRef ensureStreamNonNull(SVal StreamVal, CheckerContext &C, + ProgramStateRef ensureStreamNonNull(SVal StreamVal, const Expr *StreamE, + CheckerContext &C, ProgramStateRef State) const; /// Check that the stream is the opened state. @@ -472,7 +473,8 @@ void StreamChecker::preFreopen(const FnDescription *Desc, const CallEvent &Call, CheckerContext &C) const { // Do not allow NULL as passed stream pointer but allow a closed stream. ProgramStateRef State = C.getState(); - State = ensureStreamNonNull(getStreamArg(Desc, Call), C, State); + State = ensureStreamNonNull(getStreamArg(Desc, Call), + Call.getArgExpr(Desc->StreamArgNo), C, State); if (!State) return; @@ -549,7 +551,8 @@ void StreamChecker::preFread(const FnDescription *Desc, const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); SVal StreamVal = getStreamArg(Desc, Call); - State = ensureStreamNonNull(StreamVal, C, State); + State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C, + State); if (!State) return; State = ensureStreamOpened(StreamVal, C, State); @@ -573,7 +576,8 @@ void StreamChecker::preFwrite(const FnDescription *Desc, const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); SVal StreamVal = getStreamArg(Desc, Call); - State = ensureStreamNonNull(StreamVal, C, State); + State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C, + State); if (!State) return; State = ensureStreamOpened(StreamVal, C, State); @@ -671,7 +675,8 @@ void StreamChecker::preFseek(const FnDescription *Desc, const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); SVal StreamVal = getStreamArg(Desc, Call); - State = ensureStreamNonNull(StreamVal, C, State); + State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C, + State); if (!State) return; State = ensureStreamOpened(StreamVal, C, State); @@ -790,7 +795,8 @@ void StreamChecker::preDefault(const FnDescription *Desc, const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); SVal StreamVal = getStreamArg(Desc, Call); - State = ensureStreamNonNull(StreamVal, C, State); + State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C, + State); if (!State) return; State = ensureStreamOpened(StreamVal, C, State); @@ -814,7 +820,8 @@ void StreamChecker::evalSetFeofFerror(const FnDescription *Desc, } ProgramStateRef -StreamChecker::ensureStreamNonNull(SVal StreamVal, CheckerContext &C, +StreamChecker::ensureStreamNonNull(SVal StreamVal, const Expr *StreamE, + CheckerContext &C, ProgramStateRef State) const { auto Stream = StreamVal.getAs<DefinedSVal>(); if (!Stream) @@ -827,8 +834,11 @@ StreamChecker::ensureStreamNonNull(SVal StreamVal, CheckerContext &C, if (!StateNotNull && StateNull) { if (ExplodedNode *N = C.generateErrorNode(StateNull)) { - C.emitReport(std::make_unique<PathSensitiveBugReport>( - BT_FileNull, "Stream pointer might be NULL.", N)); + auto R = std::make_unique<PathSensitiveBugReport>( + BT_FileNull, "Stream pointer might be NULL.", N); + if (StreamE) + bugreporter::trackExpressionValue(N, StreamE, *R); + C.emitReport(std::move(R)); } return nullptr; } diff --git a/clang/test/Analysis/stream-note.c b/clang/test/Analysis/stream-note.c index 71a5ba2315d9c..a509bb1b58315 100644 --- a/clang/test/Analysis/stream-note.c +++ b/clang/test/Analysis/stream-note.c @@ -77,3 +77,14 @@ void check_note_leak_2(int c) { fclose(F1); fclose(F2); } + +void check_track_null() { + FILE *F; + F = fopen("foo1.c", "r"); // expected-note {{Value assigned to 'F'}} expected-note {{Assuming pointer value is null}} + if (F != NULL) { // expected-note {{Taking false branch}} expected-note {{'F' is equal to NULL}} + fclose(F); + return; + } + fclose(F); // expected-warning {{Stream pointer might be NULL}} + // expected-note@-1 {{Stream pointer might be NULL}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits