// 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 \
// RUN: -analyzer-checker=alpha.unix.Errno \
// 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 \
// RUN: -analyzer-checker=alpha.unix.Errno \
// RUN: -DERRNO_FUNC
#include "Inputs/system-header-simulator.h"
#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();
int ErrnoTesterChecker_setErrnoCheckState();
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}}
}
}
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) {
}
}