[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
https://github.com/balazske closed https://github.com/llvm/llvm-project/pull/84191 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
https://github.com/benshi001 approved this pull request. After eliminating `std::bind`, I hope there can be further solutions to reduce duplications. https://github.com/llvm/llvm-project/pull/84191 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
https://github.com/steakhal approved this pull request. I haven't gone deep into this PR, but it looks good to me. Please wait for someone else to sign it too. https://github.com/llvm/llvm-project/pull/84191 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
https://github.com/NagyDonat edited https://github.com/llvm/llvm-project/pull/84191 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
https://github.com/NagyDonat edited https://github.com/llvm/llvm-project/pull/84191 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
@@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, } } +void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent , NagyDonat wrote: I agree that `std::bind` is hard to follow, and dedicated handlers dispatching to common implementations is a better model. The "Copy-pasting their implementation while specializing it" could be even better if the common parts are lifted out into helper functions; but I strongly suggest that we should avoid code duplication. https://github.com/llvm/llvm-project/pull/84191 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
@@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, } } +void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent , steakhal wrote: Let me share my experience with `std::bind` and with this checker. Unfortunately, we also have/had a couple (<10) conflicting patches to this checker, and I had to rebase 16 times to clang-18. This is fine, but when I this many `std::binds`, and sometimes changes where the railing "bool" flag meaning was changed, I really had to be on my toes when resolving syntactic & semantic conflicts. I feel the `std::bind` usage got out of hand here, and I now regret not pushing back. The bottom line is, that I think having dedicated handlers dispatching to common implementations, or just copy-pasting their implementation while specializing it leads to cleaner code than using `std::bind` and directly binding to the generic implementation. https://github.com/llvm/llvm-project/pull/84191 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
@@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, } } +void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent , balazske wrote: The `CallDescriptionMap` was uncomfortable to handle because too many `std::bind` functions. https://github.com/llvm/llvm-project/pull/84191 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
https://github.com/balazske updated https://github.com/llvm/llvm-project/pull/84191 From dbaf3348510582c013254ed48b69663b42816be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= Date: Wed, 6 Mar 2024 16:01:01 +0100 Subject: [PATCH] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. These functions should not be allowed if the file position is indeterminate (they return the file position). This condition is now checked, and tests are improved to check it. --- .../StaticAnalyzer/Checkers/StreamChecker.cpp | 91 --- clang/test/Analysis/stream-error.c| 27 +- 2 files changed, 80 insertions(+), 38 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 2ec47bf55df76b..10972158f39862 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -307,64 +307,64 @@ class StreamChecker : public Checker FnTestDescriptions = { {{{"StreamTesterChecker_make_feof_stream"}, 1}, {nullptr, -std::bind(::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof), +std::bind(::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof, + false), 0}}, {{{"StreamTesterChecker_make_ferror_stream"}, 1}, {nullptr, std::bind(::evalSetFeofFerror, _1, _2, _3, _4, - ErrorFError), + ErrorFError, false), +0}}, + {{{"StreamTesterChecker_make_ferror_indeterminate_stream"}, 1}, + {nullptr, +std::bind(::evalSetFeofFerror, _1, _2, _3, _4, + ErrorFError, true), 0}}, }; @@ -415,8 +421,11 @@ class StreamChecker : public CheckerStreamArgNo), C, @@ -865,11 +873,6 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, if (!State) return; - if (!IsRead) { -C.addTransition(State); -return; - } - SymbolRef Sym = StreamVal.getAsSymbol(); if (Sym && State->get(Sym)) { const StreamState *SS = State->get(Sym); @@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, } } +void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent , + CheckerContext ) const { + ProgramStateRef State = C.getState(); + SVal StreamVal = getStreamArg(Desc, Call); + State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C, + State); + if (!State) +return; + State = ensureStreamOpened(StreamVal, C, State); + if (!State) +return; + State = ensureNoFilePositionIndeterminate(StreamVal, C, State); + if (!State) +return; + + C.addTransition(State); +} + void StreamChecker::evalFreadFwrite(const FnDescription *Desc, const CallEvent , CheckerContext , bool IsFread) const { @@ -1496,14 +1517,16 @@ void StreamChecker::preDefault(const FnDescription *Desc, const CallEvent , void StreamChecker::evalSetFeofFerror(const FnDescription *Desc, const CallEvent , CheckerContext , - const StreamErrorState ) const { + const StreamErrorState , + bool Indeterminate) const { ProgramStateRef State = C.getState(); SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol(); assert(StreamSym && "Operation not permitted on non-symbolic stream value."); const StreamState *SS = State->get(StreamSym); assert(SS && "Stream should be tracked by the checker."); State = State->set( - StreamSym, StreamState::getOpened(SS->LastOperation, ErrorKind)); + StreamSym, + StreamState::getOpened(SS->LastOperation, ErrorKind, Indeterminate)); C.addTransition(State); } diff --git a/clang/test/Analysis/stream-error.c b/clang/test/Analysis/stream-error.c index ac31083bfc691f..88f7de4234ffb4 100644 --- a/clang/test/Analysis/stream-error.c +++ b/clang/test/Analysis/stream-error.c @@ -11,6 +11,7 @@ void clang_analyzer_dump(int); void clang_analyzer_warnIfReached(void); void StreamTesterChecker_make_feof_stream(FILE *); void StreamTesterChecker_make_ferror_stream(FILE *); +void StreamTesterChecker_make_ferror_indeterminate_stream(FILE *); void error_fopen(void) { FILE *F = fopen("file", "r"); @@ -52,6 +53,8 @@ void stream_error_feof(void) { clearerr(F); clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + StreamTesterChecker_make_ferror_indeterminate_stream(F); + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} fclose(F); } @@ -65,6 +68,8 @@ void stream_error_ferror(void) { clearerr(F); clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} clang_analyzer_eval(ferror(F)); //
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
@@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, } } +void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent , benshi001 wrote: Why we need a separated `preWrite` ? The original `preReadWrite` also works. https://github.com/llvm/llvm-project/pull/84191 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Balázs Kéri (balazske) Changes These functions should not be allowed if the file position is indeterminate (they return the file position). This condition is now checked, and tests are improved to check it. --- Full diff: https://github.com/llvm/llvm-project/pull/84191.diff 2 Files Affected: - (modified) clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp (+53-30) - (modified) clang/test/Analysis/stream-error.c (+23-4) ``diff diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 2ec47bf55df76b..346d4ae8db2dfe 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -307,64 +307,64 @@ class StreamChecker : public Checker FnTestDescriptions = { {{{"StreamTesterChecker_make_feof_stream"}, 1}, {nullptr, -std::bind(::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof), +std::bind(::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof, + false), 0}}, {{{"StreamTesterChecker_make_ferror_stream"}, 1}, {nullptr, std::bind(::evalSetFeofFerror, _1, _2, _3, _4, - ErrorFError), + ErrorFError, false), +0}}, + {{{"StreamTesterChecker_make_ferror_indeterminate_stream"}, 1}, + {nullptr, +std::bind(::evalSetFeofFerror, _1, _2, _3, _4, + ErrorFError, true), 0}}, }; @@ -415,8 +421,11 @@ class StreamChecker : public CheckerStreamArgNo), C, @@ -865,11 +873,6 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, if (!State) return; - if (!IsRead) { -C.addTransition(State); -return; - } - SymbolRef Sym = StreamVal.getAsSymbol(); if (Sym && State->get(Sym)) { const StreamState *SS = State->get(Sym); @@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, } } +void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent , + CheckerContext ) const { + ProgramStateRef State = C.getState(); + SVal StreamVal = getStreamArg(Desc, Call); + State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C, + State); + if (!State) +return; + State = ensureStreamOpened(StreamVal, C, State); + if (!State) +return; + State = ensureNoFilePositionIndeterminate(StreamVal, C, State); + if (!State) +return; + + C.addTransition(State); +} + void StreamChecker::evalFreadFwrite(const FnDescription *Desc, const CallEvent , CheckerContext , bool IsFread) const { @@ -1496,14 +1517,16 @@ void StreamChecker::preDefault(const FnDescription *Desc, const CallEvent , void StreamChecker::evalSetFeofFerror(const FnDescription *Desc, const CallEvent , CheckerContext , - const StreamErrorState ) const { + const StreamErrorState , + bool Indeterminate) const { ProgramStateRef State = C.getState(); SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol(); assert(StreamSym && "Operation not permitted on non-symbolic stream value."); const StreamState *SS = State->get(StreamSym); assert(SS && "Stream should be tracked by the checker."); State = State->set( - StreamSym, StreamState::getOpened(SS->LastOperation, ErrorKind)); + StreamSym, + StreamState::getOpened(SS->LastOperation, ErrorKind, Indeterminate)); C.addTransition(State); } diff --git a/clang/test/Analysis/stream-error.c b/clang/test/Analysis/stream-error.c index ac31083bfc691f..88f7de4234ffb4 100644 --- a/clang/test/Analysis/stream-error.c +++ b/clang/test/Analysis/stream-error.c @@ -11,6 +11,7 @@ void clang_analyzer_dump(int); void clang_analyzer_warnIfReached(void); void StreamTesterChecker_make_feof_stream(FILE *); void StreamTesterChecker_make_ferror_stream(FILE *); +void StreamTesterChecker_make_ferror_indeterminate_stream(FILE *); void error_fopen(void) { FILE *F = fopen("file", "r"); @@ -52,6 +53,8 @@ void stream_error_feof(void) { clearerr(F); clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + StreamTesterChecker_make_ferror_indeterminate_stream(F); + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} fclose(F); } @@ -65,6 +68,8 @@ void stream_error_ferror(void) { clearerr(F); clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + StreamTesterChecker_make_ferror_indeterminate_stream(F); + clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}} fclose(F); } @@ -233,7 +238,7 @@ void
[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)
https://github.com/balazske created https://github.com/llvm/llvm-project/pull/84191 These functions should not be allowed if the file position is indeterminate (they return the file position). This condition is now checked, and tests are improved to check it. From f5e2ba88eb79d778daf9d3e8f55a57c15db961a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= Date: Wed, 6 Mar 2024 16:01:01 +0100 Subject: [PATCH] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. These functions should not be allowed if the file position is indeterminate (they return the file position). This condition is now checked, and tests are improved to check it. --- .../StaticAnalyzer/Checkers/StreamChecker.cpp | 83 --- clang/test/Analysis/stream-error.c| 27 +- 2 files changed, 76 insertions(+), 34 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 2ec47bf55df76b..346d4ae8db2dfe 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -307,64 +307,64 @@ class StreamChecker : public Checker FnTestDescriptions = { {{{"StreamTesterChecker_make_feof_stream"}, 1}, {nullptr, -std::bind(::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof), +std::bind(::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof, + false), 0}}, {{{"StreamTesterChecker_make_ferror_stream"}, 1}, {nullptr, std::bind(::evalSetFeofFerror, _1, _2, _3, _4, - ErrorFError), + ErrorFError, false), +0}}, + {{{"StreamTesterChecker_make_ferror_indeterminate_stream"}, 1}, + {nullptr, +std::bind(::evalSetFeofFerror, _1, _2, _3, _4, + ErrorFError, true), 0}}, }; @@ -415,8 +421,11 @@ class StreamChecker : public CheckerStreamArgNo), C, @@ -865,11 +873,6 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, if (!State) return; - if (!IsRead) { -C.addTransition(State); -return; - } - SymbolRef Sym = StreamVal.getAsSymbol(); if (Sym && State->get(Sym)) { const StreamState *SS = State->get(Sym); @@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc, } } +void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent , + CheckerContext ) const { + ProgramStateRef State = C.getState(); + SVal StreamVal = getStreamArg(Desc, Call); + State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C, + State); + if (!State) +return; + State = ensureStreamOpened(StreamVal, C, State); + if (!State) +return; + State = ensureNoFilePositionIndeterminate(StreamVal, C, State); + if (!State) +return; + + C.addTransition(State); +} + void StreamChecker::evalFreadFwrite(const FnDescription *Desc, const CallEvent , CheckerContext , bool IsFread) const { @@ -1496,14 +1517,16 @@ void StreamChecker::preDefault(const FnDescription *Desc, const CallEvent , void StreamChecker::evalSetFeofFerror(const FnDescription *Desc, const CallEvent , CheckerContext , - const StreamErrorState ) const { + const StreamErrorState , + bool Indeterminate) const { ProgramStateRef State = C.getState(); SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol(); assert(StreamSym && "Operation not permitted on non-symbolic stream value."); const StreamState *SS = State->get(StreamSym); assert(SS && "Stream should be tracked by the checker."); State = State->set( - StreamSym, StreamState::getOpened(SS->LastOperation, ErrorKind)); + StreamSym, + StreamState::getOpened(SS->LastOperation, ErrorKind, Indeterminate)); C.addTransition(State); } diff --git a/clang/test/Analysis/stream-error.c b/clang/test/Analysis/stream-error.c index ac31083bfc691f..88f7de4234ffb4 100644 --- a/clang/test/Analysis/stream-error.c +++ b/clang/test/Analysis/stream-error.c @@ -11,6 +11,7 @@ void clang_analyzer_dump(int); void clang_analyzer_warnIfReached(void); void StreamTesterChecker_make_feof_stream(FILE *); void StreamTesterChecker_make_ferror_stream(FILE *); +void StreamTesterChecker_make_ferror_indeterminate_stream(FILE *); void error_fopen(void) { FILE *F = fopen("file", "r"); @@ -52,6 +53,8 @@ void stream_error_feof(void) { clearerr(F); clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + StreamTesterChecker_make_ferror_indeterminate_stream(F); + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}