forked from OSchip/llvm-project
[clang][Analyzer] Add errno state to standard functions modeling.
This updates StdLibraryFunctionsChecker to set the state of 'errno' by using the new errno_modeling functionality. The errno value is set in the PostCall callback. Setting it in call::Eval did not work for some reason and then every function should be EvalCallAsPure which may be bad to do. Now the errno value and state is not allowed to be checked in any PostCall checker callback because it is unspecified if the errno was set already or will be set later by this checker. Reviewed By: martong, steakhal Differential Revision: https://reviews.llvm.org/D125400
This commit is contained in:
parent
ed8fceaa09
commit
957014da2d
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,49 @@
|
|||
// RUN: %clang_analyze_cc1 -verify -analyzer-output text %s \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-checker=debug.ExprInspection \
|
||||
// RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \
|
||||
// RUN: -analyzer-checker=apiModeling.Errno \
|
||||
// RUN: -analyzer-checker=alpha.unix.Errno \
|
||||
// RUN: -analyzer-config apiModeling.StdCLibraryFunctions:ModelPOSIX=true
|
||||
|
||||
#include "Inputs/errno_var.h"
|
||||
|
||||
int access(const char *path, int amode);
|
||||
|
||||
void clang_analyzer_warnIfReached();
|
||||
|
||||
void test1() {
|
||||
access("path", 0); // no note here
|
||||
access("path", 0);
|
||||
// expected-note@-1{{Assuming that function 'access' is successful, in this case the value 'errno' may be undefined after the call and should not be used}}
|
||||
if (errno != 0) {
|
||||
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
||||
// expected-note@-2{{An undefined value may be read from 'errno'}}
|
||||
}
|
||||
}
|
||||
|
||||
void test2() {
|
||||
if (access("path", 0) == -1) {
|
||||
// expected-note@-1{{Taking true branch}}
|
||||
// Failure path.
|
||||
if (errno != 0) {
|
||||
// expected-note@-1{{'errno' is not equal to 0}}
|
||||
// expected-note@-2{{Taking true branch}}
|
||||
clang_analyzer_warnIfReached(); // expected-note {{REACHABLE}} expected-warning {{REACHABLE}}
|
||||
} else {
|
||||
clang_analyzer_warnIfReached(); // no-warning: We are on the failure path.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test3() {
|
||||
if (access("path", 0) != -1) {
|
||||
// Success path.
|
||||
// expected-note@-2{{Assuming that function 'access' is successful, in this case the value 'errno' may be undefined after the call and should not be used}}
|
||||
// expected-note@-3{{Taking true branch}}
|
||||
if (errno != 0) {
|
||||
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
||||
// expected-note@-2{{An undefined value may be read from 'errno'}}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// RUN: %clang_analyze_cc1 -verify %s \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-checker=debug.ExprInspection \
|
||||
// RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \
|
||||
// RUN: -analyzer-checker=apiModeling.Errno \
|
||||
// RUN: -analyzer-checker=alpha.unix.Errno \
|
||||
// RUN: -analyzer-config apiModeling.StdCLibraryFunctions:ModelPOSIX=true
|
||||
|
||||
#include "Inputs/errno_var.h"
|
||||
|
||||
typedef typeof(sizeof(int)) size_t;
|
||||
typedef __typeof(sizeof(int)) off_t;
|
||||
typedef size_t ssize_t;
|
||||
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
|
||||
off_t lseek(int fildes, off_t offset, int whence);
|
||||
|
||||
void clang_analyzer_warnIfReached();
|
||||
void clang_analyzer_eval(int);
|
||||
|
||||
int unsafe_errno_read(int sock, void *data, int data_size) {
|
||||
if (send(sock, data, data_size, 0) != data_size) {
|
||||
if (errno == 1) {
|
||||
// expected-warning@-1{{An undefined value may be read from 'errno'}}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int errno_lseek(int fildes, off_t offset) {
|
||||
off_t result = lseek(fildes, offset, 0);
|
||||
if (result == (off_t)-1) {
|
||||
// Failure path.
|
||||
// check if the function is modeled
|
||||
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
|
||||
return 2;
|
||||
}
|
||||
if (result != offset) {
|
||||
// Not success path (?)
|
||||
// not sure if this is a valid case, allow to check 'errno'
|
||||
if (errno == 1) { // no warning
|
||||
return 1;
|
||||
}
|
||||
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
|
||||
}
|
||||
if (result == offset) {
|
||||
// The checker does not differentiate for this case.
|
||||
// In general case no relation exists between the arg 2 and the returned
|
||||
// value, only for SEEK_SET.
|
||||
if (errno == 1) { // no warning
|
||||
return 1;
|
||||
}
|
||||
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue