diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index ebf6fa41898dc4..e487b0f1d4b5d6 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -35,6 +35,7 @@ jobs: prepare: name: Prepare to build binaries runs-on: ubuntu-22.04 + if: github.repository == 'llvm/llvm-project' outputs: release-version: ${{ steps.vars.outputs.release-version }} flags: ${{ steps.vars.outputs.flags }} @@ -85,6 +86,7 @@ jobs: name: "Fill Cache ${{ matrix.os }}" needs: prepare runs-on: ${{ matrix.os }} + if: github.repository == 'llvm/llvm-project' strategy: matrix: os: @@ -119,6 +121,7 @@ jobs: - prepare - fill-cache runs-on: ${{ matrix.target.runs-on }} + if: github.repository == 'llvm/llvm-project' strategy: fail-fast: false matrix: 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(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof), + std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof, + false), 0}}, {{{"StreamTesterChecker_make_ferror_stream"}, 1}, {nullptr, std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4, - ErrorFError), + ErrorFError, false), + 0}}, + {{{"StreamTesterChecker_make_ferror_indeterminate_stream"}, 1}, + {nullptr, + std::bind(&StreamChecker::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 &Call, + CheckerContext &C) 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 &Call, CheckerContext &C, bool IsFread) const { @@ -1496,14 +1517,16 @@ void StreamChecker::preDefault(const FnDescription *Desc, const CallEvent &Call, void StreamChecker::evalSetFeofFerror(const FnDescription *Desc, const CallEvent &Call, CheckerContext &C, - const StreamErrorState &ErrorKind) const { + const StreamErrorState &ErrorKind, + 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 error_fscanf(int *A) { fscanf(F, "ccc"); // expected-warning {{Stream might be already closed}} } -void error_ungetc() { +void error_ungetc(int TestIndeterminate) { FILE *F = tmpfile(); if (!F) return; @@ -245,8 +250,12 @@ void error_ungetc() { clang_analyzer_eval(Ret == 'X'); // expected-warning {{TRUE}} } fputc('Y', F); // no-warning + if (TestIndeterminate) { + StreamTesterChecker_make_ferror_indeterminate_stream(F); + ungetc('X', F); // expected-warning {{might be 'indeterminate'}} + } fclose(F); - ungetc('A', F); // expected-warning {{Stream might be already closed}} + ungetc('A', F); // expected-warning {{Stream might be already closed}} } void error_getdelim(char *P, size_t Sz) { @@ -449,7 +458,7 @@ void error_fseeko_0(void) { fclose(F); } -void error_ftell(void) { +void error_ftell(int TestIndeterminate) { FILE *F = fopen("file", "r"); if (!F) return; @@ -467,10 +476,14 @@ void error_ftell(void) { rc = ftell(F); clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}} + if (TestIndeterminate) { + StreamTesterChecker_make_ferror_indeterminate_stream(F); + ftell(F); // expected-warning {{might be 'indeterminate'}} + } fclose(F); } -void error_ftello(void) { +void error_ftello(int TestIndeterminate) { FILE *F = fopen("file", "r"); if (!F) return; @@ -488,6 +501,10 @@ void error_ftello(void) { rc = ftello(F); clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}} + if (TestIndeterminate) { + StreamTesterChecker_make_ferror_indeterminate_stream(F); + ftell(F); // expected-warning {{might be 'indeterminate'}} + } fclose(F); } @@ -506,6 +523,8 @@ void error_fileno(void) { N = fileno(F); clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}} + StreamTesterChecker_make_ferror_indeterminate_stream(F); + fileno(F); // no warning fclose(F); }