diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -2358,7 +2358,7 @@ ``fdopen``, ``fopen``, ``freopen``, ``getch``, ``getchar``, ``getchar_unlocked``, ``gets``, ``scanf``, ``socket``, ``wgetch`` Default propagations defined by ``GenericTaintChecker``: -``atoi``, ``atol``, ``atoll``, ``fgetc``, ``fgetln``, ``fgets``, ``fscanf``, ``sscanf``, ``getc``, ``getc_unlocked``, ``getdelim``, ``getline``, ``getw``, ``pread``, ``read``, ``strchr``, ``strrchr``, ``tolower``, ``toupper`` +``atoi``, ``atol``, ``atoll``, ``basename``, ``dirname``, ``fgetc``, ``fgetln``, ``fgets``, ``fnmatch``, ``fread``, ``fscanf``, ``fscanf_s``, ``index``, ``inflate``, ``isalnum``, ``isalpha``, ``isascii``, ``isblank``, ``iscntrl``, ``isdigit``, ``isgraph``, ``islower``, ``isprint``, ``ispunct``, ``isspace``, ``isupper``, ``isxdigit``, ``memchr``, ``memrchr``, ``sscanf``, ``getc``, ``getc_unlocked``, ``getdelim``, ``getline``, ``getw``, ``memcmp``, ``memcpy``, ``memmem``, ``memmove``, ``mbtowc``, ``pread``, ``qsort``, ``qsort_r``, ``rawmemchr``, ``read``, ``readv``, ``recv``, ``recvfrom``, ``rindex``, ``strcasestr``, ``strchr``, ``strchrnul``, ``strcasecmp``, ``strcmp``, ``strcspn``, ``strlen``, ``strncasecmp``, ``strncmp``, ``strndup``, ``strndupa``, ``strpbrk``, ``strrchr``, ``strsep``, ``strspn``, ``strstr``, ``strtol``, ``strtoll``, ``strtoul``, ``strtoull``, ``tolower``, ``toupper``, ``ttyname``, ``ttyname_r``, ``vfscanf``, ``vfscanf``, ``wctomb``, ``wcwidth`` Default sinks defined in ``GenericTaintChecker``: ``printf``, ``setproctitle``, ``system``, ``popen``, ``execl``, ``execle``, ``execlp``, ``execv``, ``execvp``, ``execvP``, ``execve``, ``dlopen``, ``memcpy``, ``memmove``, ``strncpy``, ``strndup``, ``malloc``, ``calloc``, ``alloca``, ``memccpy``, ``realloc``, ``bcopy`` diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -555,7 +555,11 @@ {{"fgetln"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, {{"fgets"}, TR::Prop({{2}}, {{0}, ReturnValueIndex})}, {{"fscanf"}, TR::Prop({{0}}, {{}, 2})}, + {{"fscanf_s"}, TR::Prop({{0}}, {{}, {2}})}, {{"sscanf"}, TR::Prop({{0}}, {{}, 2})}, + {{"vscanf"}, TR::Prop({{0}}, {{}, 1})}, + {{"vfscanf"}, TR::Prop({{0}}, {{}, 2})}, + {{"getc"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, {{"getc_unlocked"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, {{"getdelim"}, TR::Prop({{3}}, {{0}})}, @@ -567,6 +571,73 @@ {{"strrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, {{"tolower"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, {{"toupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"fread"}, TR::Prop({{3}}, {{0, ReturnValueIndex}})}, + {{"readv"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})}, + {{"recv"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})}, + {{"recvfrom"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})}, + + {{"ttyname"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"ttyname_r"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})}, + + {{"dirname"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"basename"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"fnmatch"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"memchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"memrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"rawmemchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + + {{"mbtowc"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})}, + {{"wctomb"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})}, + {{"wcwidth"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + + {{"memcmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})}, + {{"memcpy"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})}, + {{"memmove"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})}, + {{"memmem"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + + {{"strstr"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"strcasestr"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + + {{"strchrnul"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + + {{"index"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"rindex"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + + // FIXME: in case of arrays ,only the first element of the array gets + // tainted. + {{"qsort"}, TR::Prop({{0}}, {{0}})}, + {{"qsort_r"}, TR::Prop({{0}}, {{0}})}, + + {{"strcmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})}, + {{"strcasecmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})}, + {{"strncmp"}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})}, + {{"strncasecmp"}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})}, + {{"strspn"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"strcspn"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"strpbrk"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"strndup"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"strndupa"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"strlen"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"strnlen"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"strtol"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})}, + {{"strtoll"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})}, + {{"strtoul"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})}, + {{"strtoull"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})}, + + {{"isalnum"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"isalpha"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"isascii"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"isblank"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"iscntrl"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"isdigit"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"isgraph"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"islower"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"isprint"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"ispunct"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"isspace"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"isupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"isxdigit"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncat)}}, TR::Prop({{1, 2}}, {{0, ReturnValueIndex}})}, {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcpy)}}, @@ -873,7 +944,6 @@ } /// Checker registration - void ento::registerGenericTaintChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } diff --git a/clang/test/Analysis/taint-generic.c b/clang/test/Analysis/taint-generic.c --- a/clang/test/Analysis/taint-generic.c +++ b/clang/test/Analysis/taint-generic.c @@ -1,11 +1,13 @@ -// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \ +// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \ +// RUN: -Wno-incompatible-library-redeclaration -verify %s \ // RUN: -analyzer-checker=alpha.security.taint \ // RUN: -analyzer-checker=core \ // RUN: -analyzer-checker=alpha.security.ArrayBoundV2 \ // RUN: -analyzer-config \ // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml -// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \ +// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \ +// RUN: -Wno-incompatible-library-redeclaration -verify %s \ // RUN: -DFILE_IS_STRUCT \ // RUN: -analyzer-checker=alpha.security.taint \ // RUN: -analyzer-checker=core \ @@ -13,7 +15,8 @@ // RUN: -analyzer-config \ // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml -// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast -verify %s \ +// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast \ +// RUN: -Wno-incompatible-library-redeclaration -verify %s \ // RUN: -analyzer-checker=alpha.security.taint \ // RUN: -analyzer-config \ // RUN: alpha.security.taint.TaintPropagation:Config=justguessit \ @@ -24,7 +27,8 @@ // CHECK-INVALID-FILE-SAME: that expects a valid filename instead of // CHECK-INVALID-FILE-SAME: 'justguessit' -// RUN: not %clang_analyze_cc1 -verify %s \ +// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \ +// RUN: -verify %s \ // RUN: -analyzer-checker=alpha.security.taint \ // RUN: -analyzer-config \ // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-ill-formed.yaml \ @@ -34,7 +38,8 @@ // CHECK-ILL-FORMED-SAME: 'alpha.security.taint.TaintPropagation:Config', // CHECK-ILL-FORMED-SAME: that expects a valid yaml file: [[MSG]] -// RUN: not %clang_analyze_cc1 -verify %s \ +// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \ +// RUN: -verify %s \ // RUN: -analyzer-checker=alpha.security.taint \ // RUN: -analyzer-config \ // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-invalid-arg.yaml \ @@ -45,6 +50,8 @@ // CHECK-INVALID-ARG-SAME: that expects an argument number for propagation // CHECK-INVALID-ARG-SAME: rules greater or equal to -1 +extern int some_global_flag_to_branch_on; + int scanf(const char *restrict format, ...); char *gets(char *str); int getchar(void); @@ -58,6 +65,8 @@ #define bool _Bool +FILE *fopen(const char *name, const char *mode); + int fscanf(FILE *restrict stream, const char *restrict format, ...); int sprintf(char *str, const char *format, ...); void setproctitle(const char *fmt, ...); @@ -352,6 +361,596 @@ return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}} } +int fscanf_s(FILE *stream, const char *format, ...); +int testFscanf_s(const char *fname, int *d) { + FILE *f = fopen(fname, "r"); + fscanf_s(f, "%d", d); + return 1 / *d; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int vscanf(const char *format, ...); +int testVscanf(int *d) { + char format[10]; + scanf("%9s", format); // fake a tainted a file descriptor + + vscanf(format, &d); + return 1 / *d; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int vfscanf(FILE *stream, const char *format, ...); +int testVfscanf(const char *fname, int *d) { + FILE *f = fopen(fname, "r"); + vfscanf(f, "%d", d); + return 1 / *d; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int fread(void *buffer, size_t size, size_t count, FILE *stream); +int testFread(const char *fname, int *buffer, size_t size, size_t count) { + FILE *f = fopen(fname, "r"); + size_t read = fread(buffer, size, count, f); + + if (some_global_flag_to_branch_on) // just to have 2 branches, and assert 2 division by zero messages + return 1 / *buffer; // expected-warning {{Division by a tainted value, possibly zero}} + + return 1 / read; // expected-warning {{Division by a tainted value, possibly zero}} +} + +struct iovec { + void *iov_base; /* Starting address */ + size_t iov_len; /* Number of bytes to transfer */ +}; +ssize_t readv(int fd, const struct iovec *iov, int iovcnt); +int testReadv(const struct iovec *iov, int iovcnt) { + int fd; + scanf("%d", &fd); // fake a tainted a file descriptor + + size_t read = readv(fd, iov, iovcnt); + // FIXME: should be able to assert that iov is also tainted + return 1 / read; // expected-warning {{Division by a tainted value, possibly zero}} +} + +ssize_t recv(int sockfd, void *buf, size_t len, int flags); +int testRecv(int *buf, size_t len, int flags) { + int fd; + scanf("%d", &fd); // fake a tainted a file descriptor + + size_t read = recv(fd, buf, len, flags); + if (some_global_flag_to_branch_on) // just to have 2 branches, and assert 2 division by zero messages + return 1 / *buf; // expected-warning {{Division by a tainted value, possibly zero}} + + return 1 / read; // expected-warning {{Division by a tainted value, possibly zero}} +} + +ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags, + struct sockaddr *restrict src_addr, + socklen_t *restrict addrlen); +int testRecvfrom(int *restrict buf, size_t len, int flags, + struct sockaddr *restrict src_addr, + socklen_t *restrict addrlen) { + int fd; + scanf("%d", &fd); // fake a tainted a file descriptor + + size_t read = recvfrom(fd, buf, len, flags, src_addr, addrlen); + if (some_global_flag_to_branch_on) // just to have 2 branches, and assert 2 division by zero messages + return 1 / *buf; // expected-warning {{Division by a tainted value, possibly zero}} + + return 1 / read; // expected-warning {{Division by a tainted value, possibly zero}} +} + +char *ttyname(int fd); +int testTtyname() { + int fd; + scanf("%d", &fd); // fake a tainted a file descriptor + + char *name = ttyname(fd); + return system(name); // expected-warning {{Untrusted data is passed to a system call}} +} + +int ttyname_r(int fd, char *buf, size_t buflen); +int testTtyname_r(char *buf, size_t buflen) { + int fd; + scanf("%d", &fd); // fake a tainted a file descriptor + + int result = ttyname_r(fd, buf, buflen); + system(buf); // expected-warning {{Untrusted data is passed to a system call}} + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +char *dirname(char *path); +int testDirname() { + char buf[10]; + scanf("%9s", buf); + + char *name = dirname(buf); + return system(name); // expected-warning {{Untrusted data is passed to a system call}} +} + +char *basename(char *path); +int testBasename() { + char buf[10]; + scanf("%9s", buf); + + char *name = basename(buf); + return system(name); // expected-warning {{Untrusted data is passed to a system call}} +} + +int fnmatch(const char *pattern, const char *string, int flags); +int testFnmatch(const char *string, int flags) { + char buf[10]; + scanf("%9s", buf); + + int result = fnmatch(buf, string, flags); + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +void *memchr(const void *s, int c, size_t n); +int testMemchr(int c, size_t n) { + char buf[10]; + scanf("%9s", buf); + + char *result = memchr(buf, c, n); + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +void *memrchr(const void *s, int c, size_t n); +int testMemrchr(int c, size_t n) { + char buf[10]; + scanf("%9s", buf); + + char *result = memrchr(buf, c, n); + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +void *rawmemchr(const void *s, int c); +int testRawmemchr(int c) { + char buf[10]; + scanf("%9s", buf); + + char *result = rawmemchr(buf, c); + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +typedef char wchar_t; +int mbtowc(wchar_t *pwc, const char *s, size_t n); +int testMbtowc(wchar_t *pwc, size_t n) { + char buf[10]; + scanf("%9s", buf); + + int result = mbtowc(pwc, buf, n); + if (some_global_flag_to_branch_on) // just to have 2 branches, and assert 2 division by zero messages + return 1 / *pwc; // expected-warning {{Division by a tainted value, possibly zero}} + + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int wctomb(char *s, wchar_t wc); +int testWctomb(char *buf) { + wchar_t wc; + scanf("%c", &wc); + + int result = wctomb(buf, wc); + if (some_global_flag_to_branch_on) // just to have 2 branches, and assert 2 division by zero messages + return 1 / *buf; // expected-warning {{Division by a tainted value, possibly zero}} + + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int wcwidth(wchar_t c); +int testWcwidth() { + wchar_t wc; + scanf("%c", &wc); + + int width = wcwidth(wc); + return 1 / width; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int memcmp(const void *s1, const void *s2, size_t n); +int testMemcmpWithLHSTainted(size_t n, char *rhs) { + char lhs[10]; + scanf("%9s", lhs); + + int cmp_result = memcmp(lhs, rhs, n); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int testMemcmpWithRHSTainted(size_t n, char *lhs) { + char rhs[10]; + scanf("%9s", rhs); + + int cmp_result = memcmp(lhs, rhs, n); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +void *memcpy(void *restrict dest, const void *restrict src, size_t n); +int testMemcpy(char *dst, size_t n) { + char src[10]; + scanf("%9s", src); + + char *result = memcpy(dst, src, n); + + system(dst); // expected-warning {{Untrusted data is passed to a system call}} + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +void *memmove(void *dest, const void *src, size_t n); +int testMemmove(char *dst, size_t n) { + char src[10]; + scanf("%9s", src); + + char *result = memmove(dst, src, n); + + system(dst); // expected-warning {{Untrusted data is passed to a system call}} + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); +int testMemmem(const void *needle, size_t needlelen) { + char haystack[10]; + scanf("%9s", haystack); + + char *result = memmem(haystack, 9, needle, needlelen); + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +char *strstr(const char *haystack, const char *needle); +int testStrstr(const char *needle) { + char haystack[10]; + scanf("%9s", haystack); + + char *result = strstr(haystack, needle); + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +char *strcasestr(const char *haystack, const char *needle); +int testStrcasestr(const char *needle) { + char haystack[10]; + scanf("%9s", haystack); + + char *result = strcasestr(haystack, needle); + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +char *strchrnul(const char *s, int c); +int testStrchrnul() { + char s[10]; + scanf("%9s", s); + + char *result = strchrnul(s, 9); + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +char *index(const char *s, int c); +int testIndex() { + char s[10]; + scanf("%9s", s); + + char *result = index(s, 9); + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +char *rindex(const char *s, int c); +int testRindex() { + char s[10]; + scanf("%9s", s); + + char *result = rindex(s, 9); + return system(result); // expected-warning {{Untrusted data is passed to a system call}} +} + +int strcmp(const char *s1, const char *s2); +int testStrcmpWithLHSTainted(char *rhs) { + char lhs[10]; + scanf("%9s", lhs); + + int cmp_result = strcmp(lhs, rhs); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int testStrcmpWithRHSTainted(char *lhs) { + char rhs[10]; + scanf("%9s", rhs); + + int cmp_result = strcmp(lhs, rhs); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} +int strcasecmp(const char *s1, const char *s2); +int testStrcasecmpWithLHSTainted(char *rhs) { + char lhs[10]; + scanf("%9s", lhs); + + int cmp_result = strcasecmp(lhs, rhs); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int testStrcasecmpWithRHSTainted(char *lhs) { + char rhs[10]; + scanf("%9s", rhs); + + int cmp_result = strcasecmp(lhs, rhs); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} +int strncmp(const char *s1, const char *s2, size_t n); +int testStrncmpWithLHSTainted(char *rhs, size_t n) { + char lhs[10]; + scanf("%9s", lhs); + + int cmp_result = strncmp(lhs, rhs, n); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int testStrncmpWithRHSTainted(char *lhs, size_t n) { + char rhs[10]; + scanf("%9s", rhs); + + int cmp_result = strncmp(lhs, rhs, n); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int testStrncmpWithNTainted(char *lhs, char *rhs) { + int n; + scanf("%d", &n); + + int cmp_result = strncmp(lhs, rhs, n); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int strncasecmp(const char *s1, const char *s2, size_t n); +int testStrncasecmpWithLHSTainted(char *rhs, size_t n) { + char lhs[10]; + scanf("%9s", lhs); + + int cmp_result = strncmp(lhs, rhs, n); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int testStrncasecmpWithRHSTainted(char *lhs, size_t n) { + char rhs[10]; + scanf("%9s", rhs); + + int cmp_result = strncmp(lhs, rhs, n); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int testStrncasecmpWithNTainted(char *lhs, char *rhs) { + int n; + scanf("%d", &n); + + int cmp_result = strncmp(lhs, rhs, n); + return 1 / cmp_result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +size_t strspn(const char *s, const char *accept); +int testStrspn(const char *accept) { + char s[10]; + scanf("%9s", s); + + size_t result = strspn(s, accept); + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +size_t strcspn(const char *s, const char *reject); +int testStrcspn(const char *reject) { + char s[10]; + scanf("%9s", s); + + size_t result = strcspn(s, reject); + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +char *strpbrk(const char *s, const char *accept); +int testStrpbrk(const char *accept) { + char s[10]; + scanf("%9s", s); + + char *result = strpbrk(s, accept); + return system(result); // expected-warning {{Untrusted data is passed to a system call}}} +} + +char *strndup(const char *s, size_t n); +int testStrndup(size_t n) { + char s[10]; + scanf("%9s", s); + + char *result = strndup(s, n); + return system(result); // expected-warning {{Untrusted data is passed to a system call}}} +} + +char *strdupa(const char *s); +int testStrdupa() { + char s[10]; + scanf("%9s", s); + + char *result = strdupa(s); + return system(result); // expected-warning {{Untrusted data is passed to a system call}}} +} + +char *strndupa(const char *s, size_t n); +int testStrndupa(size_t n) { + char s[10]; + scanf("%9s", s); + + char *result = strndupa(s, n); + return system(result); // expected-warning {{Untrusted data is passed to a system call}}} +} + +size_t strlen(const char *s); +int testStrlen() { + char s[10]; + scanf("%9s", s); + + size_t result = strlen(s); + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +size_t strnlen(const char *s, size_t maxlen); +int testStrnlen(size_t maxlen) { + char s[10]; + scanf("%9s", s); + + size_t result = strnlen(s, maxlen); + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +long strtol(const char *restrict nptr, char **restrict endptr, int base); +int testStrtol(char **restrict endptr, int base) { + char s[10]; + scanf("%9s", s); + + long result = strtol(s, endptr, base); + system(*endptr); // expected-warning {{Untrusted data is passed to a system call}}} + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +long long strtoll(const char *restrict nptr, char **restrict endptr, int base); +int testStrtoll(char **restrict endptr, int base) { + char s[10]; + scanf("%9s", s); + + long long result = strtoll(s, endptr, base); + system(*endptr); // expected-warning {{Untrusted data is passed to a system call}}} + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +unsigned long int strtoul(const char *nptr, char **endptr, int base); +int testStrtoul(char **restrict endptr, int base) { + char s[10]; + scanf("%9s", s); + + unsigned long result = strtoul(s, endptr, base); + system(*endptr); // expected-warning {{Untrusted data is passed to a system call}}} + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} +unsigned long long int strtoull(const char *nptr, char **endptr, int base); +int testStrtoull(char **restrict endptr, int base) { + char s[10]; + scanf("%9s", s); + + unsigned long long result = strtoull(s, endptr, base); + system(*endptr); // expected-warning {{Untrusted data is passed to a system call}}} + return 1 / result; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int isalnum(int c); +int testIsalnum() { + char c; + scanf("%c", &c); + + return 1 / isalnum(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int isalpha(int c); +int testIsalpha() { + char c; + scanf("%c", &c); + + return 1 / isalpha(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int isascii(int c); +int testIsascii() { + char c; + scanf("%c", &c); + + return 1 / isascii(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int isblank(int c); +int testIsblank() { + char c; + scanf("%c", &c); + + return 1 / isblank(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int iscntrl(int c); +int testIsctrl() { + char c; + scanf("%c", &c); + + return 1 / iscntrl(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int isdigit(int c); +int testIsdigit() { + char c; + scanf("%c", &c); + + return 1 / isdigit(c); // expected-warning {{Division by a tainted value, possibly zero}} +} + +int isgraph(int c); +int testIsgraph() { + char c; + scanf("%c", &c); + + return 1 / isgraph(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int islower(int c); +int testIslower() { + char c; + scanf("%c", &c); + + return 1 / islower(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int isprint(int c); +int testIssprint() { + char c; + scanf("%c", &c); + + return 1 / isprint(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int ispunct(int c); +int testIspunct() { + char c; + scanf("%c", &c); + + return 1 / ispunct(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int isspace(int c); +int testIsspace() { + char c; + scanf("%c", &c); + + return 1 / isspace(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int isupper(int c); +int testIsupper() { + char c; + scanf("%c", &c); + + return 1 / isupper(c); // expected-warning {{Division by a tainted value, possibly zero}} +} +int isxdigit(int c); +int testIsxdigit() { + char c; + scanf("%c", &c); + + return 1 / isxdigit(c); // expected-warning {{Division by a tainted value, possibly zero}} +} + +int cmp_less(const void *lhs, const void *rhs) { + return *(int *)lhs < *(int *)rhs ? -1 : *(int *)lhs > *(int *)rhs ? 1 + : 0; +} +void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); +int testQsort() { + int data[6]; + scanf("%d %d %d %d %d %d", data, data + 1, data + 2, data + 3, data + 4, data + 5); + + qsort(data, sizeof(data), sizeof(data[0]), &cmp_less); + return 1 / data[0]; // expected-warning {{Division by a tainted value, possibly zero}} +} + +int cmp_less_than(const void *lhs, const void *rhs, void *baseline) { + return *(int *)lhs < *(int *)baseline ? -1 : *(int *)lhs > *(int *)baseline ? 1 + : 0; +} +void qsort_r(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *arg); +int testQsort_r() { + int data[6]; + scanf("%d %d %d %d %d %d", data, data + 1, data + 2, data + 3, data + 4, data + 5); + + int baseline = 42; + + qsort_r(data, sizeof(data), sizeof(data[0]), &cmp_less_than, &baseline); + return 1 / data[0]; // expected-warning {{Division by a tainted value, possibly zero}} +} + // Test configuration int mySource1(void); void mySource2(int*);