mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 19:16:06 +00:00

Previously alpha.security.ArrayBoundV2 produced very spartan bug reports; this commit ensures that the relevant (and known) details are reported to the user. The logic for detecting bugs is not changed, after this commit the checker will report the same set of issues, but with better messages. To test the details of the message generation this commit adds a new test file 'out-of-bounds-diagnostics.c'. Three of the testcases are added with FIXME notes because they reveal shortcomings of the existing modeling and bounds checking code. I will try to fix them in separate follow-up commits.
139 lines
3.4 KiB
C++
139 lines
3.4 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -analyzer-config alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml -Wno-format-security -verify -std=c++11 %s
|
|
|
|
#define BUFSIZE 10
|
|
int Buffer[BUFSIZE];
|
|
|
|
int scanf(const char*, ...);
|
|
int mySource1();
|
|
int mySource3();
|
|
|
|
typedef struct _FILE FILE;
|
|
extern "C" {
|
|
extern FILE *stdin;
|
|
}
|
|
int fscanf(FILE *stream, const char *format, ...);
|
|
|
|
bool isOutOfRange2(const int*);
|
|
|
|
void mySink2(int);
|
|
|
|
// Test configuration
|
|
namespace myNamespace {
|
|
void scanf(const char*, ...);
|
|
void myScanf(const char*, ...);
|
|
int mySource3();
|
|
|
|
bool isOutOfRange(const int*);
|
|
bool isOutOfRange2(const int*);
|
|
|
|
void mySink(int, int, int);
|
|
void mySink2(int);
|
|
}
|
|
|
|
namespace myAnotherNamespace {
|
|
int mySource3();
|
|
|
|
bool isOutOfRange2(const int*);
|
|
|
|
void mySink2(int);
|
|
}
|
|
|
|
void testConfigurationNamespacePropagation1() {
|
|
int x;
|
|
// The built-in functions should be matched only for functions in
|
|
// the global namespace
|
|
myNamespace::scanf("%d", &x);
|
|
Buffer[x] = 1; // no-warning
|
|
|
|
scanf("%d", &x);
|
|
Buffer[x] = 1; // expected-warning {{Potential out of bound access }}
|
|
}
|
|
|
|
void testConfigurationNamespacePropagation2() {
|
|
int x = mySource3();
|
|
Buffer[x] = 1; // no-warning
|
|
|
|
int y = myNamespace::mySource3();
|
|
Buffer[y] = 1; // expected-warning {{Potential out of bound access }}
|
|
}
|
|
|
|
void testConfigurationNamespacePropagation3() {
|
|
int x = myAnotherNamespace::mySource3();
|
|
Buffer[x] = 1; // expected-warning {{Potential out of bound access }}
|
|
}
|
|
|
|
void testConfigurationNamespacePropagation4() {
|
|
int x;
|
|
// Configured functions without scope should match for all function.
|
|
myNamespace::myScanf("%d", &x);
|
|
Buffer[x] = 1; // expected-warning {{Potential out of bound access }}
|
|
}
|
|
|
|
void testConfigurationNamespaceFilter1() {
|
|
int x = mySource1();
|
|
if (myNamespace::isOutOfRange2(&x))
|
|
return;
|
|
Buffer[x] = 1; // no-warning
|
|
|
|
int y = mySource1();
|
|
if (isOutOfRange2(&y))
|
|
return;
|
|
Buffer[y] = 1; // expected-warning {{Potential out of bound access }}
|
|
}
|
|
|
|
void testConfigurationNamespaceFilter2() {
|
|
int x = mySource1();
|
|
if (myAnotherNamespace::isOutOfRange2(&x))
|
|
return;
|
|
Buffer[x] = 1; // no-warning
|
|
}
|
|
|
|
void testConfigurationNamespaceFilter3() {
|
|
int x = mySource1();
|
|
if (myNamespace::isOutOfRange(&x))
|
|
return;
|
|
Buffer[x] = 1; // no-warning
|
|
}
|
|
|
|
void testConfigurationNamespaceSink1() {
|
|
int x = mySource1();
|
|
mySink2(x); // no-warning
|
|
|
|
int y = mySource1();
|
|
myNamespace::mySink2(y);
|
|
// expected-warning@-1 {{Untrusted data is passed to a user-defined sink}}
|
|
}
|
|
|
|
void testConfigurationNamespaceSink2() {
|
|
int x = mySource1();
|
|
myAnotherNamespace::mySink2(x);
|
|
// expected-warning@-1 {{Untrusted data is passed to a user-defined sink}}
|
|
}
|
|
|
|
void testConfigurationNamespaceSink3() {
|
|
int x = mySource1();
|
|
myNamespace::mySink(x, 0, 1);
|
|
// expected-warning@-1 {{Untrusted data is passed to a user-defined sink}}
|
|
}
|
|
|
|
struct Foo {
|
|
void scanf(const char*, int*);
|
|
void myMemberScanf(const char*, int*);
|
|
};
|
|
|
|
void testConfigurationMemberFunc() {
|
|
int x;
|
|
Foo foo;
|
|
foo.scanf("%d", &x);
|
|
Buffer[x] = 1; // no-warning
|
|
|
|
foo.myMemberScanf("%d", &x);
|
|
Buffer[x] = 1; // expected-warning {{Potential out of bound access }}
|
|
}
|
|
|
|
void testReadingFromStdin(char **p) {
|
|
int n;
|
|
fscanf(stdin, "%d", &n);
|
|
Buffer[n] = 1; // expected-warning {{Potential out of bound access }}
|
|
}
|