2022-02-25 17:15:06 +08:00
|
|
|
// RUN: %clang_analyze_cc1 -verify %s \
|
|
|
|
// RUN: -analyzer-checker=core \
|
|
|
|
// RUN: -analyzer-checker=apiModeling.Errno \
|
|
|
|
// RUN: -analyzer-checker=debug.ExprInspection \
|
|
|
|
// RUN: -analyzer-checker=debug.ErrnoTest \
|
2022-06-20 15:42:19 +08:00
|
|
|
// RUN: -analyzer-checker=alpha.unix.Errno \
|
2022-02-25 17:15:06 +08:00
|
|
|
// RUN: -DERRNO_VAR
|
|
|
|
|
|
|
|
// RUN: %clang_analyze_cc1 -verify %s \
|
|
|
|
// RUN: -analyzer-checker=core \
|
|
|
|
// RUN: -analyzer-checker=apiModeling.Errno \
|
|
|
|
// RUN: -analyzer-checker=debug.ExprInspection \
|
|
|
|
// RUN: -analyzer-checker=debug.ErrnoTest \
|
2022-06-20 15:42:19 +08:00
|
|
|
// RUN: -analyzer-checker=alpha.unix.Errno \
|
2022-02-25 17:15:06 +08:00
|
|
|
// RUN: -DERRNO_FUNC
|
|
|
|
|
2022-06-20 15:42:19 +08:00
|
|
|
#include "Inputs/system-header-simulator.h"
|
2022-02-25 17:15:06 +08:00
|
|
|
#ifdef ERRNO_VAR
|
|
|
|
#include "Inputs/errno_var.h"
|
|
|
|
#endif
|
|
|
|
#ifdef ERRNO_FUNC
|
|
|
|
#include "Inputs/errno_func.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void clang_analyzer_eval(int);
|
|
|
|
void ErrnoTesterChecker_setErrno(int);
|
|
|
|
int ErrnoTesterChecker_getErrno();
|
|
|
|
int ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
int ErrnoTesterChecker_setErrnoIfErrorRange();
|
2022-06-20 15:42:19 +08:00
|
|
|
int ErrnoTesterChecker_setErrnoCheckState();
|
2022-02-25 17:15:06 +08:00
|
|
|
|
|
|
|
void something();
|
|
|
|
|
|
|
|
void test() {
|
|
|
|
// Test if errno is initialized.
|
|
|
|
clang_analyzer_eval(errno == 0); // expected-warning{{TRUE}}
|
|
|
|
|
|
|
|
ErrnoTesterChecker_setErrno(1);
|
|
|
|
// Test if errno was recognized and changed.
|
|
|
|
clang_analyzer_eval(errno == 1); // expected-warning{{TRUE}}
|
|
|
|
clang_analyzer_eval(ErrnoTesterChecker_getErrno() == 1); // expected-warning{{TRUE}}
|
|
|
|
|
|
|
|
something();
|
|
|
|
|
|
|
|
// Test if errno was invalidated.
|
|
|
|
clang_analyzer_eval(errno); // expected-warning{{UNKNOWN}}
|
|
|
|
clang_analyzer_eval(ErrnoTesterChecker_getErrno()); // expected-warning{{UNKNOWN}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testRange(int X) {
|
|
|
|
if (X > 0) {
|
|
|
|
ErrnoTesterChecker_setErrno(X);
|
|
|
|
clang_analyzer_eval(errno > 0); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testIfError() {
|
|
|
|
if (ErrnoTesterChecker_setErrnoIfError())
|
|
|
|
clang_analyzer_eval(errno == 11); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testIfErrorRange() {
|
|
|
|
if (ErrnoTesterChecker_setErrnoIfErrorRange()) {
|
|
|
|
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
|
|
|
clang_analyzer_eval(errno == 1); // expected-warning{{FALSE}} expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
}
|
2022-06-20 15:42:19 +08:00
|
|
|
|
|
|
|
void testErrnoCheck0() {
|
|
|
|
// If the function returns a success result code, value of 'errno'
|
|
|
|
// is unspecified and it is unsafe to make any decision with it.
|
|
|
|
// The function did not promise to not change 'errno' if no failure happens.
|
|
|
|
int X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 0) {
|
|
|
|
if (errno) { // expected-warning{{An undefined value may be read from 'errno' [alpha.unix.Errno]}}
|
|
|
|
}
|
|
|
|
if (errno) { // no warning for second time (analysis stops at the first warning)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 0) {
|
|
|
|
if (errno) { // expected-warning{{An undefined value may be read from 'errno' [alpha.unix.Errno]}}
|
|
|
|
}
|
|
|
|
errno = 0;
|
|
|
|
}
|
|
|
|
X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 0) {
|
|
|
|
errno = 0;
|
|
|
|
if (errno) { // no warning after overwritten 'errno'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testErrnoCheck1() {
|
|
|
|
// If the function returns error result code that is out-of-band (not a valid
|
|
|
|
// non-error return value) the value of 'errno' can be checked but it is not
|
|
|
|
// required to do so.
|
|
|
|
int X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 1) {
|
|
|
|
if (errno) { // no warning
|
|
|
|
}
|
|
|
|
}
|
|
|
|
X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 1) {
|
|
|
|
errno = 0; // no warning
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testErrnoCheck2() {
|
|
|
|
// If the function returns an in-band error result the value of 'errno' is
|
|
|
|
// required to be checked to verify if error happened.
|
|
|
|
// The same applies to other functions that can indicate failure only by
|
|
|
|
// change of 'errno'.
|
|
|
|
int X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 2) {
|
|
|
|
errno = 0; // expected-warning{{Value of 'errno' was not checked and is overwritten here [alpha.unix.Errno]}}
|
|
|
|
errno = 0;
|
|
|
|
}
|
|
|
|
X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 2) {
|
|
|
|
errno = 0; // expected-warning{{Value of 'errno' was not checked and is overwritten here [alpha.unix.Errno]}}
|
|
|
|
if (errno) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testErrnoCheck3() {
|
|
|
|
int X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 2) {
|
|
|
|
if (errno) {
|
|
|
|
}
|
|
|
|
errno = 0; // no warning after 'errno' was read
|
|
|
|
}
|
|
|
|
X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 2) {
|
|
|
|
int A = errno;
|
|
|
|
errno = 0; // no warning after 'errno' was read
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testErrnoCheckUndefinedLoad() {
|
|
|
|
int X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 0) {
|
|
|
|
if (errno) { // expected-warning{{An undefined value may be read from 'errno' [alpha.unix.Errno]}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testErrnoNotCheckedAtSystemCall() {
|
|
|
|
int X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 2) {
|
|
|
|
printf("%i", 1); // expected-warning{{Value of 'errno' was not checked and may be overwritten by function 'printf' [alpha.unix.Errno]}}
|
|
|
|
printf("%i", 1); // no warning ('printf' does not change errno state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testErrnoCheckStateInvalidate() {
|
|
|
|
int X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 0) {
|
|
|
|
something();
|
|
|
|
if (errno) { // no warning after an invalidating function call
|
|
|
|
}
|
|
|
|
}
|
|
|
|
X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 0) {
|
|
|
|
printf("%i", 1);
|
|
|
|
if (errno) { // no warning after an invalidating standard function call
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testErrnoCheckStateInvalidate1() {
|
|
|
|
int X = ErrnoTesterChecker_setErrnoCheckState();
|
|
|
|
if (X == 2) {
|
|
|
|
clang_analyzer_eval(errno); // expected-warning{{TRUE}}
|
|
|
|
something();
|
|
|
|
clang_analyzer_eval(errno); // expected-warning{{UNKNOWN}}
|
|
|
|
errno = 0; // no warning after invalidation
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_if_cond_in_expr() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
if (errno + 10 > 2) {
|
|
|
|
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_for_cond() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
for (; errno != 0;) {
|
|
|
|
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_do_cond() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
do {
|
|
|
|
} while (errno != 0);
|
|
|
|
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_while_cond() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
while (errno != 0) {
|
|
|
|
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_switch_cond() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
switch (errno) {}
|
|
|
|
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_conditional_cond() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
int A = errno ? 1 : 2;
|
|
|
|
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_binary_conditional_cond() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
int A = errno ?: 2;
|
|
|
|
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_errno_store_into_variable() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
int a = errno; // AllowNonConditionErrnoRead is on by default, no warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_errno_store_into_variable_in_expr() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
int a = errno > 1; // AllowNonConditionErrnoRead is on by default, no warning
|
|
|
|
}
|
|
|
|
|
|
|
|
int test_errno_return() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_errno_pointer1() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
int *ErrnoP = &errno;
|
|
|
|
int A = errno ? 1 : 2;
|
|
|
|
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_errno_pointer2() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
int *ErrnoP = &errno;
|
|
|
|
int A = (*ErrnoP) ? 1 : 2;
|
|
|
|
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
|
|
|
}
|
|
|
|
|
|
|
|
int f(int);
|
|
|
|
|
|
|
|
void test_errno_in_condition_in_function_call() {
|
|
|
|
ErrnoTesterChecker_setErrnoIfError();
|
|
|
|
if (f(errno) != 0) {
|
|
|
|
}
|
|
|
|
}
|