The stream handling functions `ftell`, `rewind`, `fgetpos`, `fsetpos` are evaluated in the checker more exactly than before. New tests are added to test behavior of the checker together with StdLibraryFunctionsChecker. The option ModelPOSIX of that checker affects if (most of) the stream functions are recognized, and checker StdLibraryFunctionArgs generates warnings if constraints for arguments are not satisfied. The state of `errno` is set by StdLibraryFunctionsChecker too for every case in the stream functions. StreamChecker works with the stream state only, does not set the errno state, and is not dependent on other checkers. Reviewed By: Szelethus Differential Revision: https://reviews.llvm.org/D140395
225 lines
5.2 KiB
C
225 lines
5.2 KiB
C
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.Stream,alpha.unix.Errno,apiModeling.StdCLibraryFunctions,debug.ExprInspection \
|
|
// RUN: -analyzer-config apiModeling.StdCLibraryFunctions:ModelPOSIX=true -verify %s
|
|
|
|
#include "Inputs/system-header-simulator.h"
|
|
#include "Inputs/errno_func.h"
|
|
|
|
extern void clang_analyzer_eval(int);
|
|
extern void clang_analyzer_dump(int);
|
|
extern void clang_analyzer_printState();
|
|
|
|
void check_fopen(void) {
|
|
FILE *F = fopen("xxx", "r");
|
|
if (!F) {
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
return;
|
|
}
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno' [alpha.unix.Errno]}}
|
|
}
|
|
|
|
void check_tmpfile(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F) {
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
return;
|
|
}
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno' [alpha.unix.Errno]}}
|
|
}
|
|
|
|
void check_freopen(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
F = freopen("xxx", "w", F);
|
|
if (!F) {
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
return;
|
|
}
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|
|
|
|
void check_fclose(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
int Ret = fclose(F);
|
|
if (Ret == EOF) {
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
return;
|
|
}
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|
|
|
|
void check_fread_size0(void) {
|
|
char Buf[10];
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
fread(Buf, 0, 1, F);
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|
|
|
|
void check_fread_nmemb0(void) {
|
|
char Buf[10];
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
fread(Buf, 1, 0, F);
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|
|
|
|
void check_fread(void) {
|
|
char Buf[10];
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
|
|
int R = fread(Buf, 1, 10, F);
|
|
if (R < 10) {
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
fclose(F);
|
|
return;
|
|
}
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|
|
|
|
void check_fwrite_size0(void) {
|
|
char Buf[] = "0123456789";
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
fwrite(Buf, 0, 1, F);
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|
|
|
|
void check_fwrite_nmemb0(void) {
|
|
char Buf[] = "0123456789";
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
fwrite(Buf, 1, 0, F);
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|
|
|
|
void check_fwrite(void) {
|
|
char Buf[] = "0123456789";
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
|
|
int R = fwrite(Buf, 1, 10, F);
|
|
if (R < 10) {
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
fclose(F);
|
|
return;
|
|
}
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|
|
|
|
void check_fseek(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
int S = fseek(F, 11, SEEK_SET);
|
|
if (S != 0) {
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
fclose(F);
|
|
return;
|
|
}
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|
|
|
|
void check_no_errno_change(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
errno = 1;
|
|
clearerr(F);
|
|
if (errno) {} // no-warning
|
|
feof(F);
|
|
if (errno) {} // no-warning
|
|
ferror(F);
|
|
if (errno) {} // no-warning
|
|
clang_analyzer_eval(errno == 1); // expected-warning{{TRUE}}
|
|
fclose(F);
|
|
}
|
|
|
|
void check_fgetpos(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
errno = 0;
|
|
fpos_t Pos;
|
|
int Ret = fgetpos(F, &Pos);
|
|
if (Ret)
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
else
|
|
clang_analyzer_eval(errno == 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
fclose(F);
|
|
}
|
|
|
|
void check_fsetpos(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
errno = 0;
|
|
fpos_t Pos;
|
|
int Ret = fsetpos(F, &Pos);
|
|
if (Ret)
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
else
|
|
clang_analyzer_eval(errno == 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
fclose(F);
|
|
}
|
|
|
|
void check_ftell(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
errno = 0;
|
|
long Ret = ftell(F);
|
|
if (Ret == -1) {
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
} else {
|
|
clang_analyzer_eval(errno == 0); // expected-warning{{TRUE}}
|
|
clang_analyzer_eval(Ret >= 0); // expected-warning{{TRUE}}
|
|
}
|
|
if (errno) {} // no-warning
|
|
fclose(F);
|
|
}
|
|
|
|
void check_rewind(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
errno = 0;
|
|
rewind(F);
|
|
clang_analyzer_eval(errno == 0);
|
|
// expected-warning@-1{{FALSE}}
|
|
// expected-warning@-2{{TRUE}}
|
|
fclose(F);
|
|
}
|
|
|
|
void check_fileno(void) {
|
|
FILE *F = tmpfile();
|
|
if (!F)
|
|
return;
|
|
int N = fileno(F);
|
|
if (N == -1) {
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
if (errno) {} // no-warning
|
|
fclose(F);
|
|
return;
|
|
}
|
|
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
|
|
}
|