mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
868 lines
15 KiB
C++
868 lines
15 KiB
C++
int source();
|
|
void sink(...);
|
|
|
|
void arithAssignments(int source1, int clean1) {
|
|
sink(clean1); // clean
|
|
clean1 += source1;
|
|
clean1 += 1;
|
|
sink(clean1); // $ ast,ir
|
|
|
|
clean1 = source1 = 1;
|
|
sink(clean1); // clean
|
|
source1 = clean1 = source();
|
|
source1++;
|
|
++source1;
|
|
source1 += 1;
|
|
sink(source1); // $ ast,ir
|
|
sink(++source1); // $ ast,ir
|
|
}
|
|
|
|
// --- globals ---
|
|
|
|
int increment(int x) {return x + 1;}
|
|
int zero(int x) {return 0;}
|
|
|
|
int global1 = 0;
|
|
int global2 = source();
|
|
int global3 = global2 + 1;
|
|
int global4 = increment(source());
|
|
int global5 = zero(source());
|
|
int global6, global7, global8, global9, global10;
|
|
|
|
void do_source()
|
|
{
|
|
global6 = 0;
|
|
global7 = source();
|
|
global8 = global7 + 1;
|
|
global9 = increment(source());
|
|
global10 = zero(source());
|
|
|
|
sink(global6);
|
|
sink(global7); // $ ast,ir
|
|
sink(global8); // $ ast,ir
|
|
sink(global9); // $ ast,ir
|
|
sink(global10);
|
|
}
|
|
|
|
void do_sink()
|
|
{
|
|
sink(global1);
|
|
sink(global2); // $ ir MISSING: ast
|
|
sink(global3); // $ ir MISSING: ast
|
|
sink(global4); // $ ir MISSING: ast
|
|
sink(global5);
|
|
sink(global6);
|
|
sink(global7); // $ ir MISSING: ast
|
|
sink(global8); // $ ir MISSING: ast
|
|
sink(global9); // $ ir MISSING: ast
|
|
sink(global10);
|
|
}
|
|
|
|
void global_test()
|
|
{
|
|
do_source();
|
|
do_sink();
|
|
}
|
|
|
|
// --- class fields ---
|
|
|
|
class MyClass {
|
|
public:
|
|
MyClass() : a(0), b(source()) {
|
|
c = source();
|
|
d = 0;
|
|
}
|
|
|
|
void myMethod() {
|
|
d = source();
|
|
}
|
|
|
|
int a, b, c, d;
|
|
};
|
|
|
|
void class_field_test() {
|
|
MyClass mc1, mc2;
|
|
|
|
mc1.myMethod();
|
|
|
|
sink(mc1.a);
|
|
sink(mc1.b); // $ ast,ir
|
|
sink(mc1.c); // $ ast,ir
|
|
sink(mc1.d); // $ ast,ir
|
|
sink(mc2.a);
|
|
sink(mc2.b); // $ ast,ir
|
|
sink(mc2.c); // $ ast,ir
|
|
sink(mc2.d);
|
|
}
|
|
|
|
// --- arrays ---
|
|
|
|
void array_test(int i) {
|
|
int arr1[10] = {0};
|
|
int arr2[10] = {0};
|
|
int arr3[10] = {0};
|
|
|
|
arr1[5] = source();
|
|
arr2[i] = source();
|
|
arr3[5] = 0;
|
|
|
|
sink(arr1[5]); // $ ast,ir
|
|
sink(arr1[i]); // $ ast,ir
|
|
sink(arr2[5]); // $ ast,ir
|
|
sink(arr2[i]); // $ ast,ir
|
|
sink(arr3[5]);
|
|
sink(arr3[i]);
|
|
}
|
|
|
|
// --- pointers ---
|
|
|
|
void pointer_test() {
|
|
int t1 = source();
|
|
int t2 = 1;
|
|
int t3 = 1;
|
|
int *p1 = &t1;
|
|
int *p2 = &t2;
|
|
int *p3 = &t3;
|
|
|
|
*p2 = source();
|
|
|
|
sink(*p1); // $ ast,ir
|
|
sink(*p2); // $ ast,ir
|
|
sink(*p3);
|
|
|
|
p3 = &t1;
|
|
sink(*p3); // $ ast,ir
|
|
|
|
*p3 = 0;
|
|
sink(*p3); // $ SPURIOUS: ast
|
|
}
|
|
|
|
// --- return values ---
|
|
|
|
int select(int i, int a, int b) {
|
|
if (i == 1) {
|
|
return a;
|
|
} else {
|
|
return b;
|
|
}
|
|
}
|
|
|
|
void fn_test(int i) {
|
|
sink(select(i, 1, source())); // $ ast,ir
|
|
}
|
|
|
|
// --- strings ---
|
|
|
|
char *strcpy(char *destination, const char *source);
|
|
char *strcat(char *destination, const char *source);
|
|
|
|
namespace strings
|
|
{
|
|
char *source(); // char* source
|
|
|
|
void strings_test1() {
|
|
char *tainted = source();
|
|
char buffer[1024] = {0};
|
|
|
|
sink(source()); // $ ast,ir
|
|
sink(tainted); // $ ast,ir
|
|
|
|
strcpy(buffer, "Hello, ");
|
|
sink(buffer);
|
|
strcat(buffer, tainted);
|
|
sink(buffer); // $ ast,ir
|
|
}
|
|
}
|
|
|
|
// --- pass by reference ---
|
|
|
|
namespace refs {
|
|
void callee(int *p) {
|
|
sink(*p); // $ ast,ir
|
|
}
|
|
|
|
void caller() {
|
|
int x = source();
|
|
callee(&x);
|
|
}
|
|
}
|
|
|
|
void *memcpy(void *dest, void *src, int len);
|
|
|
|
void test_memcpy(int *source) {
|
|
int x;
|
|
memcpy(&x, source, sizeof(int));
|
|
sink(x); // $ ast=192:23 ir SPURIOUS: ast=193:6
|
|
}
|
|
|
|
// --- std::swap ---
|
|
|
|
#include "swap.h"
|
|
|
|
|
|
|
|
void test_swap() {
|
|
int x, y;
|
|
|
|
x = source();
|
|
y = 0;
|
|
|
|
sink(x); // $ ast,ir
|
|
sink(y); // clean
|
|
|
|
std::swap(x, y);
|
|
|
|
sink(x); // $ SPURIOUS: ast
|
|
sink(y); // $ ast,ir
|
|
}
|
|
|
|
// --- lambdas ---
|
|
|
|
void test_lambdas()
|
|
{
|
|
int t = source();
|
|
int u = 0;
|
|
int v = 0;
|
|
int w = 0;
|
|
|
|
auto a = [t, u]() -> int {
|
|
sink(t); // $ ast,ir
|
|
sink(u); // clean
|
|
return t;
|
|
};
|
|
sink(a()); // $ ast,ir
|
|
|
|
auto b = [&] {
|
|
sink(t); // $ ast,ir
|
|
sink(u); // clean
|
|
v = source(); // (v is reference captured)
|
|
};
|
|
b();
|
|
sink(v); // $ MISSING: ast,ir
|
|
|
|
auto c = [=] {
|
|
sink(t); // $ ast,ir
|
|
sink(u); // clean
|
|
};
|
|
c();
|
|
|
|
auto d = [](int a, int b) {
|
|
sink(a); // $ ast,ir
|
|
sink(b); // clean
|
|
};
|
|
d(t, u);
|
|
|
|
auto e = [](int &a, int &b, int &c) {
|
|
sink(a); // $ ast,ir
|
|
sink(b); // clean
|
|
c = source();
|
|
};
|
|
e(t, u, w);
|
|
sink(w); // $ ast,ir
|
|
}
|
|
|
|
// --- taint through return value ---
|
|
|
|
int id(int x)
|
|
{
|
|
return x;
|
|
}
|
|
|
|
void test_return()
|
|
{
|
|
int x, y, z, t;
|
|
|
|
t = source();
|
|
x = 0;
|
|
y = 0;
|
|
z = 0;
|
|
|
|
sink(t); // $ ast,ir
|
|
sink(x);
|
|
sink(y);
|
|
sink(z);
|
|
|
|
x = id(t);
|
|
y = id(id(t));
|
|
z = id(z);
|
|
|
|
sink(t); // $ ast,ir
|
|
sink(x); // $ ast,ir
|
|
sink(y); // $ ast,ir
|
|
sink(z);
|
|
}
|
|
|
|
// --- taint through parameters ---
|
|
|
|
void myAssign1(int &a, int &b)
|
|
{
|
|
a = b;
|
|
}
|
|
|
|
void myAssign2(int &a, int b)
|
|
{
|
|
a = b;
|
|
}
|
|
|
|
void myAssign3(int *a, int b)
|
|
{
|
|
*a = b;
|
|
}
|
|
|
|
void myAssign4(int *a, int b)
|
|
{
|
|
int c;
|
|
|
|
c = b + 1;
|
|
*a = c;
|
|
}
|
|
|
|
void myNotAssign(int &a, int &b)
|
|
{
|
|
a = a + 1;
|
|
b = b + 1;
|
|
}
|
|
|
|
void test_outparams()
|
|
{
|
|
int t, a, b, c, d, e;
|
|
|
|
t = source();
|
|
a = 0;
|
|
b = 0;
|
|
c = 0;
|
|
d = 0;
|
|
e = 0;
|
|
|
|
sink(t); // $ ast,ir
|
|
sink(a);
|
|
sink(b);
|
|
sink(c);
|
|
sink(d);
|
|
sink(e);
|
|
|
|
myAssign1(a, t);
|
|
myAssign2(b, t);
|
|
myAssign3(&c, t);
|
|
myAssign4(&d, t);
|
|
myNotAssign(e, t);
|
|
|
|
sink(t); // $ ast,ir
|
|
sink(a); // $ ast,ir
|
|
sink(b); // $ ast,ir
|
|
sink(c); // $ ast,ir
|
|
sink(d); // $ ast,ir
|
|
sink(e);
|
|
}
|
|
|
|
// --- strdup ---
|
|
|
|
typedef unsigned long size_t;
|
|
char *strdup(const char *s1);
|
|
char *strndup(const char *s1, size_t n);
|
|
wchar_t* wcsdup(const wchar_t* s1);
|
|
char *strdupa(const char *s1);
|
|
char *strndupa(const char *s1, size_t n);
|
|
|
|
void test_strdup(char *source)
|
|
{
|
|
char *a, *b, *c;
|
|
|
|
a = strdup(source);
|
|
b = strdup("hello, world");
|
|
c = strndup(source, 100);
|
|
sink(a); // $ ast,ir
|
|
sink(b);
|
|
sink(c); // $ ast,ir
|
|
}
|
|
|
|
void test_strndup(int source)
|
|
{
|
|
char *a;
|
|
|
|
a = strndup("hello, world", source);
|
|
sink(a); // $ ast,ir
|
|
}
|
|
|
|
void test_wcsdup(wchar_t *source)
|
|
{
|
|
wchar_t *a, *b;
|
|
|
|
a = wcsdup(source);
|
|
b = wcsdup(L"hello, world");
|
|
sink(a); // $ ast,ir
|
|
sink(b);
|
|
}
|
|
|
|
void test_strdupa(char *source)
|
|
{
|
|
char *a, *b, *c;
|
|
|
|
a = strdupa(source);
|
|
b = strdupa("hello, world");
|
|
c = strndupa(source, 100);
|
|
sink(a); // $ ast,ir
|
|
sink(b);
|
|
sink(c); // $ ast,ir
|
|
}
|
|
|
|
void test_strndupa(int source)
|
|
{
|
|
char *a;
|
|
|
|
a = strndupa("hello, world", source);
|
|
sink(a); // $ ast,ir
|
|
}
|
|
|
|
// --- qualifiers ---
|
|
|
|
class MyClass2 {
|
|
public:
|
|
MyClass2(int value);
|
|
void setMember(int value);
|
|
int getMember();
|
|
|
|
int member;
|
|
};
|
|
|
|
class MyClass3 {
|
|
public:
|
|
MyClass3(const char *string);
|
|
void setString(const char *string);
|
|
const char *getString();
|
|
|
|
const char *buffer;
|
|
};
|
|
|
|
void test_qualifiers()
|
|
{
|
|
MyClass2 a(0), b(0), *c;
|
|
MyClass3 d("");
|
|
|
|
sink(a);
|
|
sink(a.getMember());
|
|
a.setMember(source());
|
|
sink(a); // $ ast,ir
|
|
sink(a.getMember()); // $ ast,ir
|
|
|
|
sink(b);
|
|
sink(b.getMember());
|
|
b.member = source();
|
|
sink(b); // $ ir MISSING: ast
|
|
sink(b.member); // $ ast,ir
|
|
sink(b.getMember()); // $ MISSING: ir ast
|
|
|
|
c = new MyClass2(0);
|
|
|
|
sink(c);
|
|
sink(c->getMember());
|
|
c->setMember(source());
|
|
sink(c); // $ ast,ir
|
|
sink(c->getMember()); // $ ast,ir
|
|
|
|
delete c;
|
|
|
|
sink(d);
|
|
sink(d.getString());
|
|
d.setString(strings::source());
|
|
sink(d); // $ ast,ir
|
|
sink(d.getString()); // $ ast,ir
|
|
}
|
|
|
|
// --- non-standard swap ---
|
|
|
|
void swop(int &a, int &b)
|
|
{
|
|
int c = a;
|
|
a = b;
|
|
b = c;
|
|
}
|
|
|
|
void test_swop() {
|
|
int x, y;
|
|
|
|
x = source();
|
|
y = 0;
|
|
|
|
sink(x); // $ ast,ir
|
|
sink(y); // clean
|
|
|
|
swop(x, y);
|
|
|
|
sink(x); // $ SPURIOUS: ast,ir
|
|
sink(y); // $ ast,ir
|
|
}
|
|
|
|
// --- getdelim ---
|
|
|
|
struct FILE;
|
|
|
|
int getdelim(char ** lineptr, size_t * n, int delimiter, FILE *stream);
|
|
|
|
void test_getdelim(FILE* source1) {
|
|
char* line = nullptr;
|
|
size_t n;
|
|
getdelim(&line, &n, '\n', source1);
|
|
|
|
sink(line); // $ ir,ast
|
|
}
|
|
|
|
// --- strtok ---
|
|
|
|
char *strtok(char *str, const char *delim);
|
|
|
|
void test_strtok(char *source) {
|
|
const char* delim = ",.-;:_";
|
|
char* tokenized = strtok(source, delim);
|
|
sink(tokenized); // $ ast,ir
|
|
sink(delim);
|
|
}
|
|
|
|
// --- strset ---
|
|
|
|
char *_strset(char *str, int c);
|
|
|
|
void test_strset_1(char* ptr, char source) {
|
|
_strset(ptr, source);
|
|
sink(ptr); // $ SPURIOUS: ast,ir
|
|
sink(*ptr); // $ ast,ir
|
|
}
|
|
|
|
void test_strset_2(char* source) {
|
|
_strset(source, 0);
|
|
sink(source); // $ ast,ir
|
|
}
|
|
|
|
// --- mempcpy ---
|
|
|
|
void *mempcpy(void *dest, const void *src, size_t n);
|
|
|
|
void test_mempcpy(int *source) {
|
|
int x;
|
|
mempcpy(&x, source, sizeof(int));
|
|
sink(x); // $ ast=540:24 ir SPURIOUS: ast=541:6
|
|
}
|
|
|
|
// --- memccpy ---
|
|
|
|
void *memccpy(void *dest, const void *src, int c, size_t n);
|
|
|
|
void test_memccpy(int *source) {
|
|
int dest[16];
|
|
memccpy(dest, source, 42, sizeof(dest));
|
|
sink(dest); // $ ast=550:24 ir SPURIOUS: ast=551:6
|
|
}
|
|
|
|
// --- strcat and related functions ---
|
|
|
|
char* strcat (char*, const char*);
|
|
|
|
void test_strcat(char* dest1, char* dest2, char* clean, char* source) {
|
|
strcat(dest1, source);
|
|
sink(dest1); // $ ast,ir
|
|
|
|
strcat(dest2, clean);
|
|
sink(dest2);
|
|
}
|
|
|
|
typedef void* _locale_t;
|
|
|
|
unsigned char *_mbsncat_l(unsigned char *, const unsigned char *, int, _locale_t);
|
|
|
|
void test__mbsncat_l(unsigned char* dest1, unsigned const char* ptr, unsigned char* dest3,
|
|
_locale_t clean, _locale_t source, int n) {
|
|
unsigned char* dest2 = _mbsncat_l(dest1, ptr, n, source);
|
|
sink(dest1); // $ SPURIOUS: ast,ir
|
|
sink(*dest1); // $ ast,ir
|
|
sink(dest2); // $ SPURIOUS: ast,ir
|
|
sink(*dest2); // $ ast,ir
|
|
|
|
unsigned char* dest4 = _mbsncat_l(dest3, ptr, n, clean);
|
|
sink(dest3);
|
|
sink(*dest3);
|
|
sink(dest4);
|
|
sink(*dest4);
|
|
}
|
|
|
|
// --- strsep ---
|
|
|
|
char *strsep(char**, const char *);
|
|
|
|
void test_strsep(char *source) {
|
|
const char* delim = ",.-;:_";
|
|
char* tokenized;
|
|
while(tokenized = strsep(&source, delim)) {
|
|
sink(tokenized); // $ ast,ir
|
|
sink(*tokenized); // $ ast,ir
|
|
}
|
|
}
|
|
|
|
// --- _strinc and related functions ---
|
|
|
|
char* _strinc(const char*, _locale_t);
|
|
unsigned char* _mbsinc(const unsigned char*);
|
|
unsigned char *_strdec(const unsigned char*, const unsigned char*);
|
|
|
|
void test__strinc(char* source, char* clean, char* dest1, char* dest2, _locale_t locale) {
|
|
dest1 = _strinc(source, locale);
|
|
sink(dest1); // $ ast,ir
|
|
sink(*dest1); // $ ast,ir
|
|
|
|
dest2 = _strinc(clean, locale);
|
|
sink(dest2);
|
|
sink(*dest2);
|
|
}
|
|
|
|
void test__mbsinc(unsigned char* source_unsigned, char* source, unsigned char* dest_unsigned, char* dest) {
|
|
dest_unsigned = _mbsinc(source_unsigned);
|
|
sink(dest_unsigned); // $ ast,ir
|
|
sink(*dest_unsigned); // $ ast,ir
|
|
|
|
dest = (char*)_mbsinc((unsigned char*)source);
|
|
sink(dest); // $ ast,ir
|
|
sink(*dest); // $ ast,ir
|
|
}
|
|
|
|
void test__strdec(const unsigned char* source, unsigned char* clean, unsigned char* dest1, unsigned char* dest2, unsigned char* dest3) {
|
|
dest1 = _strdec(source + 12, source);
|
|
sink(dest1); // $ ast,ir
|
|
sink(*dest1); // $ ast,ir
|
|
|
|
// If `clean` does not precede `source` this technically breaks the precondition of _strdec.
|
|
// We would still like to have taint, though.
|
|
dest2 = _strdec(clean, source);
|
|
sink(dest2); // $ ast,ir
|
|
sink(*dest2); // $ ast,ir
|
|
|
|
// Also breaks the precondition on _strdec.
|
|
dest3 = _strdec(source, clean);
|
|
sink(dest3); // $ ast,ir
|
|
sink(*dest3); // $ ast,ir
|
|
}
|
|
|
|
// --- strnextc ---
|
|
|
|
unsigned int _strnextc(const char*);
|
|
|
|
void test__strnextc(const char* source) {
|
|
unsigned c = 0;
|
|
do {
|
|
c = _strnextc(source++);
|
|
sink(c); // $ ast,ir
|
|
} while(c != '\0');
|
|
c = _strnextc("");
|
|
sink(c);
|
|
}
|
|
|
|
// --- taint through const specified function ---
|
|
|
|
class C_no_const_member_function {
|
|
char* data_;
|
|
public:
|
|
char* data() { return data_; }
|
|
};
|
|
|
|
void test_no_const_member(char* source) {
|
|
C_no_const_member_function c;
|
|
memcpy(c.data(), source, 16);
|
|
sink(c.data()); // $ ast,ir
|
|
}
|
|
|
|
class C_const_member_function {
|
|
char* data_;
|
|
public:
|
|
char* data() const { return data_; }
|
|
};
|
|
|
|
void test_with_const_member(char* source) {
|
|
C_const_member_function c;
|
|
memcpy(c.data(), source, 16);
|
|
sink(c.data()); // $ ast,ir
|
|
}
|
|
|
|
void argument_source(void*);
|
|
|
|
struct two_members {
|
|
char *x, *y;
|
|
};
|
|
|
|
void test_argument_source_field_to_obj() {
|
|
two_members s;
|
|
argument_source(s.x);
|
|
|
|
sink(s); // $ SPURIOUS: ast,ir
|
|
sink(s.x); // $ ast,ir
|
|
sink(s.y); // clean
|
|
}
|
|
|
|
namespace strings {
|
|
void test_write_to_read_then_incr_then_deref() {
|
|
char* s = source();
|
|
char* p;
|
|
*p++ = *s;
|
|
sink(p); // $ ast ir
|
|
}
|
|
}
|
|
|
|
char * strncpy (char *, const char *, unsigned long);
|
|
|
|
void test_strncpy(char* d, char* s) {
|
|
argument_source(s);
|
|
strncpy(d, s, 16);
|
|
sink(d); // $ ast ir
|
|
}
|
|
|
|
char* indirect_source();
|
|
|
|
void test_strtok_indirect() {
|
|
char *source = indirect_source();
|
|
const char* delim = ",.-;:_";
|
|
char* tokenized = strtok(source, delim);
|
|
sink(*tokenized); // $ ir MISSING: ast
|
|
sink(*delim);
|
|
}
|
|
|
|
long int strtol(const char*, char**, int);
|
|
|
|
void test_strtol(char *source) {
|
|
char* endptr = nullptr;
|
|
long l = strtol(source, &endptr, 10);
|
|
sink(l); // $ ast,ir
|
|
sink(endptr); // $ ast,ir
|
|
sink(*endptr); // $ ast,ir
|
|
}
|
|
|
|
void *malloc(size_t);
|
|
void *realloc(void *, size_t);
|
|
|
|
void test_realloc() {
|
|
char *source = indirect_source();
|
|
char *dest = (char*)realloc(source, 16);
|
|
sink(dest); // $ ir MISSING: ast
|
|
}
|
|
|
|
void test_realloc_2_indirections(int **buffer) {
|
|
**buffer = source();
|
|
buffer = (int**)realloc(buffer, 16);
|
|
sink(**buffer); // $ ir MISSING: ast
|
|
}
|
|
|
|
void test_realloc_struct_field() {
|
|
struct A { int x; };
|
|
A* a = (A*)malloc(sizeof(A));
|
|
a->x = source();
|
|
A* a2 = (A*)realloc(a, sizeof(A));
|
|
sink(a2->x); // $ ir MISSING: ast
|
|
}
|
|
|
|
int sprintf(char *, const char *, ...);
|
|
|
|
void call_sprintf_twice(char* path, char* data) {
|
|
sprintf(path, "%s", "abc");
|
|
sprintf(path, "%s", data);
|
|
}
|
|
|
|
void test_call_sprintf() {
|
|
char path[10];
|
|
call_sprintf_twice(path, indirect_source());
|
|
sink(*path); // $ ast,ir
|
|
}
|
|
|
|
struct TaintInheritingContentObject {
|
|
int flowFromObject;
|
|
};
|
|
|
|
TaintInheritingContentObject source(bool);
|
|
|
|
void test_TaintInheritingContent() {
|
|
TaintInheritingContentObject obj = source(true);
|
|
sink(obj.flowFromObject); // $ ir MISSING: ast
|
|
}
|
|
|
|
FILE* fopen(const char*, const char*);
|
|
int fopen_s(FILE** pFile, const char *filename, const char *mode);
|
|
|
|
void fopen_test(char* source) {
|
|
FILE* f = fopen(source, "r");
|
|
sink(f); // $ ast,ir
|
|
|
|
FILE* f2;
|
|
fopen_s(&f2, source, "r");
|
|
sink(f2); // $ ast,ir
|
|
}
|
|
|
|
typedef wchar_t OLECHAR;
|
|
typedef OLECHAR* LPOLESTR;
|
|
typedef const LPOLESTR LPCOLESTR;
|
|
typedef OLECHAR* BSTR;
|
|
typedef const char* LPCSTR;
|
|
|
|
BSTR SysAllocString(const OLECHAR *);
|
|
BSTR SysAllocStringByteLen(LPCSTR, unsigned );
|
|
BSTR SysAllocStringLen(const OLECHAR *,unsigned);
|
|
|
|
void test_sysalloc() {
|
|
auto p1 = SysAllocString((LPOLESTR)indirect_source());
|
|
sink(*p1); // $ ir MISSING: ast
|
|
|
|
auto p2 = SysAllocStringByteLen(indirect_source(), 10);
|
|
sink(*p2); // $ ir MISSING: ast
|
|
|
|
auto p3 = SysAllocStringLen((LPOLESTR)indirect_source(), 10);
|
|
sink(*p3); // $ ir MISSING: ast
|
|
}
|
|
|
|
char* strchr(const char*, int);
|
|
|
|
void write_to_const_ptr_ptr(const char **p_out, const char **p_in) {
|
|
const char* q = *p_in;
|
|
*p_out = strchr(q, '/');
|
|
}
|
|
|
|
void take_const_ptr(const char *out, const char *in) {
|
|
// NOTE: We take the address of `out` in `take_const_ptr`'s stack space.
|
|
// Assigning to this pointer does not change `out` in
|
|
// `test_write_to_const_ptr_ptr`.
|
|
write_to_const_ptr_ptr(&out, &in);
|
|
}
|
|
|
|
void test_write_to_const_ptr_ptr() {
|
|
const char* in = indirect_source();
|
|
const char* out;
|
|
take_const_ptr(out, in);
|
|
sink(out); // $ SPURIOUS: ast
|
|
}
|
|
|
|
void indirect_sink(FILE *fp);
|
|
int fprintf(FILE *fp, const char *format, ...);
|
|
|
|
int f7(void)
|
|
{
|
|
FILE* fp = (FILE*)indirect_source();
|
|
fprintf(fp, "");
|
|
indirect_sink(fp); // $ ir MISSING: ast
|
|
return 0;
|
|
}
|
|
|
|
int toupper(int);
|
|
int tolower(int);
|
|
|
|
void test_toupper_and_tolower() {
|
|
int s = source();
|
|
int u = toupper(s);
|
|
sink(u); // $ MISSING: ast,ir
|
|
int l = tolower(s);
|
|
sink(l); // $ MISSING: ast,ir
|
|
}
|
|
|
|
typedef int iconv_t;
|
|
size_t iconv(iconv_t cd, char **, size_t *, char **, size_t *);
|
|
|
|
void test_iconv(size_t size) {
|
|
char* s = indirect_source();
|
|
char out[10];
|
|
char* p = out;
|
|
size_t size_out;
|
|
iconv(0, &s, &size, &p, &size_out);
|
|
sink(*p); // $ MISSING: ast,ir
|
|
} |