Files
clang-p2996/clang/test/Analysis/stream-error.c
Balázs Kéri c2067c1f47 [clang][analyzer] Add "pedantic" mode to StreamChecker. (#87322)
The checker may create failure branches for all stream write operations
only if the new option "pedantic" is set to true.
Result of the write operations is often not checked in typical code. If
failure branches are created the checker will warn for unchecked write
operations and generate a lot of "false positives" (these are valid
warnings but the programmer does not care about this problem).
2024-04-08 12:19:03 +02:00

632 lines
21 KiB
C

// RUN: %clang_analyze_cc1 -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.unix.Stream \
// RUN: -analyzer-config alpha.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 {{Stream 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 {{Stream 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 {{Stream 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 {{Stream 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 {{Stream 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 {{Stream 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 {{Stream 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 {{Stream 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 {{Stream 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 {{Stream 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 {{Stream 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);
}