1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
// RUN: %clang_analyze_cc1 -std=c++11 -Wno-format-security \
// RUN: -analyzer-checker=core,optin.taint,security.ArrayBound,debug.ExprInspection \
// RUN: -analyzer-config optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml \
// RUN: -verify %s
template <typename T> void clang_analyzer_isTainted(T);
#define BUFSIZE 10
int Buffer[BUFSIZE];
int scanf(const char*, ...);
template <typename T = int> T 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 }}
}
namespace gh114270 {
class Empty {};
class Aggr {
public:
int data;
};
void top() {
int Int = mySource1<int>();
clang_analyzer_isTainted(Int); // expected-warning {{YES}}
Empty E = mySource1<Empty>();
clang_analyzer_isTainted(E); // expected-warning {{YES}}
Aggr A = mySource1<Aggr>();
clang_analyzer_isTainted(A); // expected-warning {{YES}}
clang_analyzer_isTainted(A.data); // expected-warning {{YES}}
}
} // namespace gh114270
namespace format_attribute {
__attribute__((__format__ (__printf__, 1, 2)))
void log_freefunc(const char *fmt, ...);
void test_format_attribute_freefunc() {
int n;
fscanf(stdin, "%d", &n); // Get a tainted value.
log_freefunc("This number is suspicious: %d\n", n); // no-warning
}
struct Foo {
// When the format attribute is applied to a method, argumet '1' is the
// implicit `this`, so e.g. in this case argument '2' specifies `fmt`.
// Specifying '1' instead of '2' would produce a compilation error:
// "format attribute cannot specify the implicit this argument as the format string"
__attribute__((__format__ (__printf__, 2, 3)))
void log_method(const char *fmt, ...);
void test_format_attribute_method() {
int n;
fscanf(stdin, "%d", &n); // Get a tainted value.
// The analyzer used to misinterpret the parameter indices in the format
// attribute when the format attribute is applied to a method.
log_method("This number is suspicious: %d\n", n); // no-warning
}
__attribute__((__format__ (__printf__, 1, 2)))
static void log_static_method(const char *fmt, ...);
void test_format_attribute_static_method() {
int n;
fscanf(stdin, "%d", &n); // Get a tainted value.
log_static_method("This number is suspicious: %d\n", n); // no-warning
}
};
} // namespace format_attribute
|