llvm/clang/test/Analysis/stream-error.c

// RUN: %clang_analyze_cc1 -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=unix.Stream \
// RUN: -analyzer-config unix.Stream:Pedantic=true \
// RUN: -analyzer-checker=debug.StreamTester \
// RUN: -analyzer-checker=debug.ExprInspection

#include "Inputs/system-header-simulator.h"

void clang_analyzer_eval(int);
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");
  if (!F)
    return;
  clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
  clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
  fclose(F);
}

void error_fdopen(int fd) {
  FILE *F = fdopen(fd, "r");
  if (!F)
    return;
  clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
  clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
  fclose(F);
}

void error_freopen(void) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  F = freopen(0, "w", F);
  if (!F)
    return;
  clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
  clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
  fclose(F);
}

void stream_error_feof(void) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  StreamTesterChecker_make_feof_stream(F);
  clang_analyzer_eval(feof(F));   // expected-warning {{TRUE}}
  clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
  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);
}

void stream_error_ferror(void) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  StreamTesterChecker_make_ferror_stream(F);
  clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
  clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
  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);
}

void error_fread(void) {
  FILE *F = tmpfile();
  if (!F)
    return;
  char Buf[10];
  int Ret = fread(Buf, 1, 10, F);
  if (Ret == 10) {
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  } else {
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
    if (feof(F)) {
      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
      fread(Buf, 1, 10, F);           // expected-warning {{Read function called when stream is in EOF state}}
      clang_analyzer_eval(feof(F));   // expected-warning {{TRUE}}
      clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
    }
    if (ferror(F)) {
      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
      fread(Buf, 1, 10, F);           // expected-warning {{might be 'indeterminate'}}
    }
  }
  fclose(F);
  Ret = fread(Buf, 1, 10, F); // expected-warning {{Use of a stream that might be already closed}}
}

void error_fwrite(void) {
  FILE *F = tmpfile();
  if (!F)
    return;
  const char *Buf = "123456789";
  int Ret = fwrite(Buf, 1, 10, F);
  if (Ret == 10) {
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  } else {
    clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
    clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
    fwrite(0, 1, 10, F);            // expected-warning {{might be 'indeterminate'}}
  }
  fclose(F);
  Ret = fwrite(0, 1, 10, F); // expected-warning {{Use of a stream that might be already closed}}
}

void error_fgetc(void) {
  FILE *F = tmpfile();
  if (!F)
    return;
  int Ret = fgetc(F);
  if (0 <= Ret && Ret <= 255) {
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  } else {
    clang_analyzer_eval(Ret == EOF);           // expected-warning {{TRUE}}
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
    if (feof(F)) {
      clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
      fgetc(F);                       // expected-warning {{Read function called when stream is in EOF state}}
    } else {
      clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
      fgetc(F);                       // expected-warning {{might be 'indeterminate'}}
    }
  }
  fclose(F);
  fgetc(F); // expected-warning {{Use of a stream that might be already closed}}
}

void error_fgets(void) {
  FILE *F = tmpfile();
  char Buf[256];
  if (!F)
    return;
  char *Ret = fgets(Buf, sizeof(Buf), F);
  if (Ret == Buf) {
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  } else {
    clang_analyzer_eval(Ret == NULL);          // expected-warning {{TRUE}}
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
    if (feof(F)) {
      clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
      fgets(Buf, sizeof(Buf), F);     // expected-warning {{Read function called when stream is in EOF state}}
    } else {
      clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
      fgets(Buf, sizeof(Buf), F);     // expected-warning {{might be 'indeterminate'}}
    }
  }
  fclose(F);
  fgets(Buf, sizeof(Buf), F);         // expected-warning {{Use of a stream that might be already closed}}
}

void error_fputc(int fd) {
  FILE *F = fdopen(fd, "w");
  if (!F)
    return;
  int Ret = fputc('X', F);
  if (Ret == EOF) {
    clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
    clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
    fputc('Y', F);                  // expected-warning {{might be 'indeterminate'}}
  } else {
    clang_analyzer_eval(Ret == 'X');             // expected-warning {{TRUE}}
    clang_analyzer_eval(feof(F) || ferror(F));   // expected-warning {{FALSE}}
    fputc('Y', F);                               // no-warning
  }
  fclose(F);
  fputc('A', F); // expected-warning {{Use of a stream that might be already closed}}
}

void error_fputs(void) {
  FILE *F = tmpfile();
  if (!F)
    return;
  int Ret = fputs("XYZ", F);
  if (Ret >= 0) {
    clang_analyzer_eval(feof(F) || ferror(F));   // expected-warning {{FALSE}}
    fputs("QWD", F);                             // no-warning
  } else {
    clang_analyzer_eval(Ret == EOF); // expected-warning {{TRUE}}
    clang_analyzer_eval(ferror(F));  // expected-warning {{TRUE}}
    clang_analyzer_eval(feof(F));    // expected-warning {{FALSE}}
    fputs("QWD", F);                 // expected-warning {{might be 'indeterminate'}}
  }
  fclose(F);
  fputs("ABC", F); // expected-warning {{Use of a stream that might be already closed}}
}

void error_fprintf(void) {
  FILE *F = tmpfile();
  if (!F)
    return;
  int Ret = fprintf(F, "aaa");
  if (Ret >= 0) {
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
    fprintf(F, "bbb");                         // no-warning
  } else {
    clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
    clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
    fprintf(F, "bbb");              // expected-warning {{might be 'indeterminate'}}
  }
  fclose(F);
  fprintf(F, "ccc"); // expected-warning {{Use of a stream that might be already closed}}
}

void error_fscanf(int *A) {
  FILE *F = tmpfile();
  if (!F)
    return;
  int Ret = fscanf(F, "a%ib", A);
  if (Ret >= 0) {
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
    fscanf(F, "bbb");                          // no-warning
  } else {
    if (ferror(F)) {
      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
      fscanf(F, "bbb");               // expected-warning {{might be 'indeterminate'}}
    } else if (feof(F)) {
      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
      fscanf(F, "bbb");               // expected-warning {{is in EOF state}}
      clang_analyzer_eval(feof(F));   // expected-warning {{TRUE}}
    } else {
      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
      fscanf(F, "bbb");               // expected-warning {{might be 'indeterminate'}}
    }
  }
  fclose(F);
  fscanf(F, "ccc"); // expected-warning {{Use of a stream that might be already closed}}
}

void error_ungetc(int TestIndeterminate) {
  FILE *F = tmpfile();
  if (!F)
    return;
  int Ret = ungetc('X', F);
  clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  if (Ret == EOF) {
    clang_analyzer_warnIfReached();          // expected-warning {{REACHABLE}}
  } else {
    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 {{Use of a stream that might be already closed}}
}

void error_getdelim(char *P, size_t Sz) {
  FILE *F = tmpfile();
  if (!F)
    return;
  ssize_t Ret = getdelim(&P, &Sz, '\t', F);
  if (Ret >= 0) {
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  } else {
    clang_analyzer_eval(Ret == -1);            // expected-warning {{TRUE}}
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
    if (feof(F)) {
      clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
      getdelim(&P, &Sz, '\n', F);     // expected-warning {{Read function called when stream is in EOF state}}
    } else {
      clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
      getdelim(&P, &Sz, '\n', F);     // expected-warning {{might be 'indeterminate'}}
    }
  }
  fclose(F);
  getdelim(&P, &Sz, '\n', F);         // expected-warning {{Use of a stream that might be already closed}}
}

void error_getline(char *P, size_t Sz) {
  FILE *F = tmpfile();
  if (!F)
    return;
  ssize_t Ret = getline(&P, &Sz, F);
  if (Ret >= 0) {
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  } else {
    clang_analyzer_eval(Ret == -1);            // expected-warning {{TRUE}}
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
    if (feof(F)) {
      clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
      getline(&P, &Sz, F);            // expected-warning {{Read function called when stream is in EOF state}}
    } else {
      clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
      getline(&P, &Sz, F);            // expected-warning {{might be 'indeterminate'}}
    }
  }
  fclose(F);
  getline(&P, &Sz, F);                // expected-warning {{Use of a stream that might be already closed}}
}

void write_after_eof_is_allowed(void) {
  FILE *F = tmpfile();
  if (!F)
    return;
  StreamTesterChecker_make_feof_stream(F);
  if (fputs("QWD", F) >= 0)                    // no-warning
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  StreamTesterChecker_make_feof_stream(F);
  if (fputc('Q', F) == 'Q')                    // no-warning
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  StreamTesterChecker_make_feof_stream(F);
  if (fwrite("012345678", 1, 10, F) == 10)     // no-warning
    clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
  fclose(F);
}

void freadwrite_zerosize(FILE *F) {
  size_t Ret;
  Ret = fwrite(0, 1, 0, F);
  clang_analyzer_dump(Ret); // expected-warning {{0 }}
  Ret = fwrite(0, 0, 1, F);
  clang_analyzer_dump(Ret); // expected-warning {{0 }}
  Ret = fread(0, 1, 0, F);
  clang_analyzer_dump(Ret); // expected-warning {{0 }}
  Ret = fread(0, 0, 1, F);
  clang_analyzer_dump(Ret); // expected-warning {{0 }}
}

void freadwrite_zerosize_eofstate(FILE *F) {
  fwrite(0, 1, 0, F);
  fwrite(0, 0, 1, F);
  fread(0, 1, 0, F); // expected-warning {{Read function called when stream is in EOF state}}
  fread(0, 0, 1, F); // expected-warning {{Read function called when stream is in EOF state}}
}

void error_fread_fwrite_zerosize(void) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;

  freadwrite_zerosize(F);
  clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
  clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}

  StreamTesterChecker_make_ferror_stream(F);
  freadwrite_zerosize(F);
  clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
  clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}

  StreamTesterChecker_make_feof_stream(F);
  freadwrite_zerosize_eofstate(F);
  clang_analyzer_eval(feof(F));   // expected-warning {{TRUE}}
  clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}

  fclose(F);
}

void error_fseek(void) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  int rc = fseek(F, 1, SEEK_SET);
  if (rc) {
    clang_analyzer_eval(rc == -1);     // expected-warning {{TRUE}}
    int IsFEof = feof(F), IsFError = ferror(F);
    // Get ferror or no error.
    clang_analyzer_eval(IsFError);     // expected-warning {{FALSE}} \
                                       // expected-warning {{TRUE}}
    clang_analyzer_eval(IsFEof);       // expected-warning {{FALSE}}
    // Error flags should not change.
    clang_analyzer_eval(feof(F));      // expected-warning {{FALSE}}
    if (IsFError)
      clang_analyzer_eval(ferror(F));  // expected-warning {{TRUE}}
  } else {
    clang_analyzer_eval(feof(F));      // expected-warning {{FALSE}}
    clang_analyzer_eval(ferror(F));    // expected-warning {{FALSE}}
    // Error flags should not change.
    clang_analyzer_eval(feof(F));      // expected-warning {{FALSE}}
    clang_analyzer_eval(ferror(F));    // expected-warning {{FALSE}}
  }
  fclose(F);
}

void error_fseeko(void) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  int rc = fseeko(F, 1, SEEK_SET);
  if (rc) {
    // Get ferror or no error.
    clang_analyzer_eval(ferror(F));  // expected-warning {{FALSE}} \
                                     // expected-warning {{TRUE}}
    clang_analyzer_eval(feof(F));    // expected-warning {{FALSE}}
  } else {
    clang_analyzer_eval(feof(F));    // expected-warning {{FALSE}}
    clang_analyzer_eval(ferror(F));  // expected-warning {{FALSE}}
  }
  fclose(F);
}

void error_fseek_0(void) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  int rc = fseek(F, 0, SEEK_SET);
  if (rc == -1) {
    int IsFEof = feof(F), IsFError = ferror(F);
    // Get ferror or no error, but not feof.
    clang_analyzer_eval(IsFError);
    // expected-warning@-1 {{FALSE}}
    // expected-warning@-2 {{TRUE}}
    clang_analyzer_eval(IsFEof);
    // expected-warning@-1 {{FALSE}}
    // Error flags should not change.
    clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
    if (IsFError)
      clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
    else
      clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
  } else {
    clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
    clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
    // Error flags should not change.
    clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
    clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
  }
  fclose(F);
}

void error_fseeko_0(void) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  int rc = fseeko(F, 0, SEEK_SET);
  if (rc) {
    int IsFEof = feof(F), IsFError = ferror(F);
    // Get ferror or no error, but not feof.
    clang_analyzer_eval(IsFError);
    // expected-warning@-1 {{FALSE}}
    // expected-warning@-2 {{TRUE}}
    clang_analyzer_eval(IsFEof);
    // expected-warning@-1 {{FALSE}}
  } else {
    clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
    clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
  }
  fclose(F);
}

void error_ftell(int TestIndeterminate) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  long rc = ftell(F);
  if (rc >= 0)
    clang_analyzer_warnIfReached();          // expected-warning {{REACHABLE}}
  else
    clang_analyzer_eval(rc == -1);           // expected-warning {{TRUE}}
  clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}}
  StreamTesterChecker_make_feof_stream(F);
  rc = ftell(F);
  clang_analyzer_eval(feof(F));              // expected-warning {{TRUE}}
  clang_analyzer_eval(ferror(F));            // expected-warning {{FALSE}}
  StreamTesterChecker_make_ferror_stream(F);
  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(int TestIndeterminate) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  off_t rc = ftello(F);
  if (rc >= 0)
    clang_analyzer_warnIfReached();          // expected-warning {{REACHABLE}}
  else
    clang_analyzer_eval(rc == -1);           // expected-warning {{TRUE}}
  clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}}
  StreamTesterChecker_make_feof_stream(F);
  rc = ftello(F);
  clang_analyzer_eval(feof(F));              // expected-warning {{TRUE}}
  clang_analyzer_eval(ferror(F));            // expected-warning {{FALSE}}
  StreamTesterChecker_make_ferror_stream(F);
  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);
}

void error_fileno(void) {
  FILE *F = fopen("file", "r");
  if (!F)
    return;
  int N = fileno(F);
  clang_analyzer_eval(N >= 0); // expected-warning {{TRUE}}
  clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}}
  StreamTesterChecker_make_feof_stream(F);
  N = fileno(F);
  clang_analyzer_eval(feof(F));              // expected-warning {{TRUE}}
  clang_analyzer_eval(ferror(F));            // expected-warning {{FALSE}}
  StreamTesterChecker_make_ferror_stream(F);
  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);
}

void error_fflush_on_non_null_stream_clear_error_states(void) {
  FILE *F0 = tmpfile(), *F1 = tmpfile();
  // `fflush` clears a non-EOF stream's error state.
  if (F0) {
    StreamTesterChecker_make_ferror_stream(F0);
    if (fflush(F0) == 0) {             // no-warning
      clang_analyzer_eval(ferror(F0)); // expected-warning {{FALSE}}
      clang_analyzer_eval(feof(F0));   // expected-warning {{FALSE}}
    }
    fclose(F0);
  }
  // `fflush` clears an EOF stream's error state.
  if (F1) {
    StreamTesterChecker_make_feof_stream(F1);
    if (fflush(F1) == 0) {             // no-warning
      clang_analyzer_eval(ferror(F1)); // expected-warning {{FALSE}}
      clang_analyzer_eval(feof(F1));   // expected-warning {{TRUE}}
    }
    fclose(F1);
  }
}

void error_fflush_on_null_stream_clear_error_states(void) {
  FILE *F0 = tmpfile(), *F1 = tmpfile();
  // `fflush` clears all stream's error states, while retains their EOF states.
  if (F0 && F1) {
    StreamTesterChecker_make_ferror_stream(F0);
    StreamTesterChecker_make_feof_stream(F1);
    if (fflush(NULL) == 0) {           // no-warning
      clang_analyzer_eval(ferror(F0)); // expected-warning {{FALSE}}
      clang_analyzer_eval(feof(F0));   // expected-warning {{FALSE}}
      clang_analyzer_eval(ferror(F1)); // expected-warning {{FALSE}}
      clang_analyzer_eval(feof(F1));   // expected-warning {{TRUE}}
    }
  }
  if (F0)
    fclose(F0);
  if (F1)
    fclose(F1);
}

void error_indeterminate(void) {
  FILE *F = fopen("file", "r+");
  if (!F)
    return;
  const char *Buf = "123456789";
  int rc = fseek(F, 0, SEEK_SET);
  if (rc) {
    if (feof(F)) {
      fwrite(Buf, 1, 10, F); // no warning
    } else if (ferror(F)) {
      fwrite(Buf, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
    } else {
      fwrite(Buf, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
    }
  }
  fclose(F);
}

void error_indeterminate_clearerr(void) {
  FILE *F = fopen("file", "r+");
  if (!F)
    return;
  const char *Buf = "123456789";
  int rc = fseek(F, 0, SEEK_SET);
  if (rc) {
    if (feof(F)) {
      clearerr(F);
      fwrite(Buf, 1, 10, F); // no warning
    } else if (ferror(F)) {
      clearerr(F);
      fwrite(Buf, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
    } else {
      clearerr(F);
      fwrite(Buf, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
    }
  }
  fclose(F);
}

void error_indeterminate_feof1(void) {
  FILE *F = fopen("file", "r+");
  if (!F)
    return;
  char Buf[10];
  if (fread(Buf, 1, 10, F) < 10) {
    if (feof(F)) {
      // error is feof, should be non-indeterminate
      fwrite("1", 1, 1, F); // no warning
    }
  }
  fclose(F);
}

void error_indeterminate_feof2(void) {
  FILE *F = fopen("file", "r+");
  if (!F)
    return;
  char Buf[10];
  if (fread(Buf, 1, 10, F) < 10) {
    if (ferror(F) == 0) {
      // error is feof, should be non-indeterminate
      fwrite("1", 1, 1, F); // no warning
    }
  }
  fclose(F);
}