From f1e22687ab579892fb2b9ce6ecebf7a2c268809f Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 8 Oct 2024 20:09:31 +0200 Subject: [PATCH 1/2] C++: Fix ODR violations in tests In QLtest we do not have linkage awareness, so having multiple functions with the same name in the same test causes ODR violations. --- .../CWE/CWE-125/semmle/tests/test.cpp | 28 +++++++-------- .../CWE/CWE-125/semmle/tests/test1.cpp | 20 +++++------ .../CWE/CWE-125/semmle/tests/test2.cpp | 22 ++++++------ .../CWE/CWE-125/semmle/tests/test3.cpp | 10 +++--- .../CWE-131/NoSpaceForZeroTerminator/test.c | 18 +++++----- .../CWE-131/NoSpaceForZeroTerminator/test.cpp | 26 +++++++------- .../NoSpaceForZeroTerminator/test2.cpp | 10 +++--- .../semmle/tainted/ArithmeticTainted.expected | 36 +++++++------------ .../tainted/IntegerOverflowTainted.expected | 17 ++++----- .../CWE/CWE-190/semmle/tainted/main.cpp | 12 +++++++ .../CWE/CWE-190/semmle/tainted/test.c | 2 +- .../CWE/CWE-190/semmle/tainted/test3.c | 2 +- .../CWE/CWE-190/semmle/tainted/test4.cpp | 2 +- .../CWE/CWE-497/semmle/tests/tests2.cpp | 2 +- 14 files changed, 101 insertions(+), 106 deletions(-) create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/main.cpp diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test.cpp index b5e8096af2ac..b4f0830039d8 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test.cpp @@ -6,7 +6,7 @@ int wprintf (const wchar_t* format, ...); int strlen( const char * string ); int checkErrors(); -void goodTest0() +static void goodTest0() { char * ptr = "123456789"; int ret; @@ -17,7 +17,7 @@ void goodTest0() ptr += ret; } } -void goodTest1(const char* ptr) +static void goodTest1(const char* ptr) { int ret; int len; @@ -27,7 +27,7 @@ void goodTest1(const char* ptr) ptr += ret; } } -void goodTest2(char* ptr) +static void goodTest2(char* ptr) { int ret; ptr[10]=0; @@ -38,7 +38,7 @@ void goodTest2(char* ptr) } } -void goodTest3(const char* ptr) +static void goodTest3(const char* ptr) { int ret; int len; @@ -48,7 +48,7 @@ void goodTest3(const char* ptr) ptr += ret; } } -void goodTest4(const char* ptr) +static void goodTest4(const char* ptr) { int ret; int len; @@ -58,7 +58,7 @@ void goodTest4(const char* ptr) ptr += ret; } } -void badTest1(const char* ptr) +static void badTest1(const char* ptr) { int ret; int len; @@ -68,7 +68,7 @@ void badTest1(const char* ptr) ptr += ret; } } -void badTest2(const char* ptr) +static void badTest2(const char* ptr) { int ret; int len; @@ -79,7 +79,7 @@ void badTest2(const char* ptr) } } -void goodTest5(const char* ptr,wchar_t *wc,int wc_len) +static void goodTest5(const char* ptr,wchar_t *wc,int wc_len) { int ret; int len; @@ -96,7 +96,7 @@ void goodTest5(const char* ptr,wchar_t *wc,int wc_len) } } -void badTest3(const char* ptr,int wc_len) +static void badTest3(const char* ptr,int wc_len) { int ret; int len; @@ -113,7 +113,7 @@ void badTest3(const char* ptr,int wc_len) wc++; } } -void badTest4(const char* ptr,int wc_len) +static void badTest4(const char* ptr,int wc_len) { int ret; int len; @@ -130,7 +130,7 @@ void badTest4(const char* ptr,int wc_len) wc++; } } -void badTest5(const char* ptr,int wc_len) +static void badTest5(const char* ptr,int wc_len) { int ret; int len; @@ -148,7 +148,7 @@ void badTest5(const char* ptr,int wc_len) } } -void badTest6(const char* ptr,int wc_len) +static void badTest6(const char* ptr,int wc_len) { int ret; int len; @@ -171,7 +171,7 @@ void badTest6(const char* ptr,int wc_len) ptr+=ret; } } -void badTest7(const char* ptr,int wc_len) +static void badTest7(const char* ptr,int wc_len) { int ret; int len; @@ -188,7 +188,7 @@ void badTest7(const char* ptr,int wc_len) ptr+=ret; } } -void badTest8(const char* ptr,wchar_t *wc) +static void badTest8(const char* ptr,wchar_t *wc) { int ret; int len; diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test1.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test1.cpp index 828b91a44f19..d66f36d38b97 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test1.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test1.cpp @@ -24,7 +24,7 @@ typedef unsigned int size_t; void* calloc (size_t num, size_t size); void* malloc (size_t size); -void badTest1(void *src, int size) { +static void badTest1(void *src, int size) { WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, (LPSTR)src, size, 0, 0); // BAD MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, (LPCWSTR)src, 30); // BAD } @@ -39,43 +39,43 @@ void goodTest2(){ } printf("%s\n", dst); } -void badTest2(){ +static void badTest2(){ wchar_t src[] = L"0123456789ABCDEF"; char dst[16]; WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, 16, NULL, NULL); // BAD printf("%s\n", dst); } -void goodTest3(){ +static void goodTest3(){ char src[] = "0123456789ABCDEF"; int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0); wchar_t * dst = (wchar_t*)calloc(size + 1, sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // GOOD } -void badTest3(){ +static void badTest3(){ char src[] = "0123456789ABCDEF"; int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0); wchar_t * dst = (wchar_t*)calloc(size + 1, 1); MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // BAD } -void goodTest4(){ +static void goodTest4(){ char src[] = "0123456789ABCDEF"; int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0); wchar_t * dst = (wchar_t*)malloc((size + 1)*sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // GOOD } -void badTest4(){ +static void badTest4(){ char src[] = "0123456789ABCDEF"; int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0); wchar_t * dst = (wchar_t*)malloc(size + 1); MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // BAD } -int goodTest5(void *src){ +static int goodTest5(void *src){ return WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, 0, 0, 0, 0); // GOOD } -int badTest5 (void *src) { +static int badTest5 (void *src) { return WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, 0, 3, 0, 0); // BAD } -void goodTest6(WCHAR *src) +static void goodTest6(WCHAR *src) { int size; char dst[5] =""; @@ -87,7 +87,7 @@ void goodTest6(WCHAR *src) WideCharToMultiByte(CP_ACP, 0, src, -1, dst, sizeof(dst), 0, 0); // GOOD printf("%s\n", dst); } -void badTest6(WCHAR *src) +static void badTest6(WCHAR *src) { char dst[5] =""; WideCharToMultiByte(CP_ACP, 0, src, -1, dst, 260, 0, 0); // BAD diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test2.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test2.cpp index 99dc3e47e5ba..65e5a9ee275f 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test2.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test2.cpp @@ -11,14 +11,14 @@ size_t _mbstowcs_l(wchar_t *wcstr,const char *mbstr,size_t count, _locale_t loca size_t mbsrtowcs(wchar_t *wcstr,const char *mbstr,size_t count, mbstate_t *mbstate); -void badTest1(void *src, int size) { +static void badTest1(void *src, int size) { mbstowcs((wchar_t*)src,(char*)src,size); // BAD _locale_t locale; _mbstowcs_l((wchar_t*)src,(char*)src,size,locale); // BAD mbstate_t *mbstate; mbsrtowcs((wchar_t*)src,(char*)src,size,mbstate); // BAD } -void goodTest2(){ +static void goodTest2(){ char src[] = "0123456789ABCDEF"; wchar_t dst[16]; int res = mbstowcs(dst, src,16); // GOOD @@ -29,43 +29,43 @@ void goodTest2(){ } printf("%s\n", dst); } -void badTest2(){ +static void badTest2(){ char src[] = "0123456789ABCDEF"; wchar_t dst[16]; mbstowcs(dst, src,16); // BAD printf("%s\n", dst); } -void goodTest3(){ +static void goodTest3(){ char src[] = "0123456789ABCDEF"; int size = mbstowcs(NULL, src,NULL); wchar_t * dst = (wchar_t*)calloc(size + 1, sizeof(wchar_t)); mbstowcs(dst, src,size+1); // GOOD } -void badTest3(){ +static void badTest3(){ char src[] = "0123456789ABCDEF"; int size = mbstowcs(NULL, src,NULL); wchar_t * dst = (wchar_t*)calloc(size + 1, 1); mbstowcs(dst, src,size+1); // BAD } -void goodTest4(){ +static void goodTest4(){ char src[] = "0123456789ABCDEF"; int size = mbstowcs(NULL, src,NULL); wchar_t * dst = (wchar_t*)malloc((size + 1)*sizeof(wchar_t)); mbstowcs(dst, src,size+1); // GOOD } -void badTest4(){ +static void badTest4(){ char src[] = "0123456789ABCDEF"; int size = mbstowcs(NULL, src,NULL); wchar_t * dst = (wchar_t*)malloc(size + 1); mbstowcs(dst, src,size+1); // BAD } -int goodTest5(void *src){ +static int goodTest5(void *src){ return mbstowcs(NULL, (char*)src,NULL); // GOOD } -int badTest5 (void *src) { +static int badTest5 (void *src) { return mbstowcs(NULL, (char*)src,3); // BAD } -void goodTest6(void *src){ +static void goodTest6(void *src){ wchar_t dst[5]; int size = mbstowcs(NULL, (char*)src,NULL); if(size>=sizeof(dst)){ @@ -75,7 +75,7 @@ void goodTest6(void *src){ mbstowcs(dst, (char*)src,sizeof(dst)); // GOOD printf("%s\n", dst); } -void badTest6(void *src){ +static void badTest6(void *src){ wchar_t dst[5]; mbstowcs(dst, (char*)src,260); // BAD printf("%s\n", dst); diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test3.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test3.cpp index e37052e839b1..662cdfc7be81 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test3.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-125/semmle/tests/test3.cpp @@ -9,14 +9,14 @@ void goodTest1(unsigned char *src){ unsigned char dst[50]; _mbsnbcpy(dst,src,sizeof(dst)); // GOOD } -size_t badTest1(unsigned char *src){ +static size_t badTest1(unsigned char *src){ int cb = 0; unsigned char dst[50]; while( cb < sizeof(dst) ) dst[cb++]=*src++; // BAD return _mbclen(dst); } -void goodTest2(unsigned char *src){ +static void goodTest2(unsigned char *src){ int cb = 0; unsigned char dst[50]; @@ -27,7 +27,7 @@ void goodTest2(unsigned char *src){ src=_mbsinc(src); } } -void badTest2(unsigned char *src){ +static void badTest2(unsigned char *src){ int cb = 0; unsigned char dst[50]; @@ -38,11 +38,11 @@ void badTest2(unsigned char *src){ src=_mbsinc(src); } } -void goodTest3(){ +static void goodTest3(){ wchar_t name[50]; name[sizeof(name) / sizeof(*name) - 1] = L'\0'; // GOOD } -void badTest3(){ +static void badTest3(){ wchar_t name[50]; name[sizeof(name) - 1] = L'\0'; // BAD } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test.c index 21dcad6f2fd5..551b2441a41c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test.c @@ -11,14 +11,14 @@ char *strcpy(char *s1, const char *s2); //// Test code ///// -void bad0(char *str) { +static void bad0(char *str) { // BAD -- Not allocating space for '\0' terminator char *buffer = malloc(strlen(str)); strcpy(buffer, str); free(buffer); } -void good0(char *str) { +static void good0(char *str) { // GOOD -- Allocating extra byte for terminator char *buffer = malloc(strlen(str)+1); strcpy(buffer, str); @@ -26,7 +26,7 @@ void good0(char *str) { } -void bad1(char *str) { +static void bad1(char *str) { int len = strlen(str); // BAD -- Not allocating space for '\0' terminator char *buffer = malloc(len); @@ -34,7 +34,7 @@ void bad1(char *str) { free(buffer); } -void good1(char *str) { +static void good1(char *str) { int len = strlen(str); // GOOD -- Allocating extra byte for terminator char *buffer = malloc(len+1); @@ -43,7 +43,7 @@ void good1(char *str) { } -void bad2(char *str) { +static void bad2(char *str) { int len = strlen(str); // BAD -- Not allocating space for '\0' terminator char *buffer = malloc(len); @@ -51,7 +51,7 @@ void bad2(char *str) { free(buffer); } -void good2(char *str) { +static void good2(char *str) { int len = strlen(str)+1; // GOOD -- Allocating extra byte for terminator char *buffer = malloc(len); @@ -59,14 +59,14 @@ void good2(char *str) { free(buffer); } -void bad3(char *str) { +static void bad3(char *str) { // BAD -- Not allocating space for '\0' terminator char *buffer = malloc(strlen(str) * sizeof(char)); strcpy(buffer, str); free(buffer); } -void good3(char *str) { +static void good3(char *str) { // GOOD -- Allocating extra byte for terminator char *buffer = malloc((strlen(str) + 1) * sizeof(char)); strcpy(buffer, str); @@ -75,7 +75,7 @@ void good3(char *str) { void *memcpy(void *s1, const void *s2, size_t n); -void good4(char *str) { +static void good4(char *str) { // GOOD -- allocating a non zero-terminated string int len = strlen(str); char *buffer = malloc(len); diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test.cpp index 63b2b4e760a7..24032a91ef15 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test.cpp @@ -19,28 +19,28 @@ int strcmp(const char *s1, const char *s2); //// Test code ///// -void bad1(wchar_t *wstr) { +static void bad1(wchar_t *wstr) { // BAD -- Not allocating space for '\0' terminator wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr)); wcscpy(wbuffer, wstr); free(wbuffer); } -void bad2(wchar_t *wstr) { +static void bad2(wchar_t *wstr) { // BAD -- Not allocating space for '\0' terminator wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr) * sizeof(wchar_t)); wcscpy(wbuffer, wstr); free(wbuffer); } -void good1(wchar_t *wstr) { +static void good1(wchar_t *wstr) { // GOOD -- Allocating extra character for terminator wchar_t *wbuffer = (wchar_t *)malloc((wcslen(wstr) + 1) * sizeof(wchar_t)); wcscpy(wbuffer, wstr); free(wbuffer); } -void bad3(char *str) { +static void bad3(char *str) { // BAD -- zero-termination proved by sprintf (as destination) char *buffer = (char *)malloc(strlen(str)); sprintf(buffer, "%s", str); @@ -50,7 +50,7 @@ void bad3(char *str) { void decode(char *dest, char *src); void wdecode(wchar_t *dest, wchar_t *src); -void bad4(char *str) { +static void bad4(char *str) { // BAD -- zero-termination proved by wprintf (as parameter) char *buffer = (char *)malloc(strlen(str)); decode(buffer, str); @@ -58,7 +58,7 @@ void bad4(char *str) { free(buffer); } -void bad5(char *str) { +static void bad5(char *str) { // BAD -- zero-termination proved by strcat (as destination) char *buffer = (char *)malloc(strlen(str)); buffer[0] = 0; @@ -66,7 +66,7 @@ void bad5(char *str) { free(buffer); } -void bad6(char *str, char *dest) { +static void bad6(char *str, char *dest) { // BAD -- zero-termination proved by strcat (as source) char *buffer = (char *)malloc(strlen(str)); decode(buffer, str); @@ -74,7 +74,7 @@ void bad6(char *str, char *dest) { free(buffer); } -void bad7(char *str, char *str2) { +static void bad7(char *str, char *str2) { // BAD -- zero-termination proved by strcmp char *buffer = (char *)malloc(strlen(str)); decode(buffer, str); @@ -84,7 +84,7 @@ void bad7(char *str, char *str2) { free(buffer); } -void bad8(wchar_t *str) { +static void bad8(wchar_t *str) { // BAD -- zero-termination proved by wcslen wchar_t *wbuffer = (wchar_t *)malloc(wcslen(str)); wdecode(wbuffer, str); @@ -94,21 +94,21 @@ void bad8(wchar_t *str) { free(wbuffer); } -void good2(char *str, char *dest) { +static void good2(char *str, char *dest) { // GOOD -- zero-termination not proven char *buffer = (char *)malloc(strlen(str)); decode(buffer, str); free(buffer); } -void bad9(wchar_t *wstr) { +static void bad9(wchar_t *wstr) { // BAD -- using new wchar_t *wbuffer = new wchar_t[wcslen(wstr)]; wcscpy(wbuffer, wstr); delete wbuffer; } -void good3(char *str) { +static void good3(char *str) { // GOOD -- zero-termination not required for this printf char *buffer = (char *)malloc(strlen(str)); decode(buffer, str); @@ -116,7 +116,7 @@ void good3(char *str) { free(buffer); } -void good4(char *str) { +static void good4(char *str) { // GOOD -- zero-termination not required for this printf char *buffer = (char *)malloc(strlen(str)); decode(buffer, str); diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test2.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test2.cpp index 3b02e89b8525..7c7f74066976 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test2.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/NoSpaceForZeroTerminator/test2.cpp @@ -38,35 +38,35 @@ namespace std //// Test code ///// -void bad1(char *str) { +static void bad1(char *str) { // BAD -- Not allocating space for '\0' terminator [NOT DETECTED] char *buffer = (char *)malloc(strlen(str)); std::string str2(buffer); free(buffer); } -void good1(char *str) { +static void good1(char *str) { // GOOD --- copy does not overrun due to size limit char *buffer = (char *)malloc(strlen(str)); std::string str2(buffer, strlen(str)); free(buffer); } -void bad2(wchar_t *str) { +static void bad2(wchar_t *str) { // BAD -- Not allocating space for '\0' terminator [NOT DETECTED] wchar_t *buffer = (wchar_t *)calloc(wcslen(str), sizeof(wchar_t)); wcscpy(buffer, str); free(buffer); } -void bad3(wchar_t *str) { +static void bad3(wchar_t *str) { // BAD -- Not allocating space for '\0' terminator wchar_t *buffer = (wchar_t *)calloc(sizeof(wchar_t), wcslen(str)); wcscpy(buffer, str); free(buffer); } -void bad4(char *str) { +static void bad4(char *str) { // BAD -- Not allocating space for '\0' terminator char *buffer = (char *)realloc(0, strlen(str)); strcpy(buffer, str); diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected index c60b26aae407..34aa8a7a7e4a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected @@ -1,4 +1,6 @@ edges +| main.cpp:7:27:7:30 | **argv | main.cpp:8:17:8:20 | **argv | provenance | | +| main.cpp:8:17:8:20 | **argv | test.c:10:28:10:31 | **argv | provenance | | | test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v | provenance | | | test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:13:27:13 | v | provenance | | | test2.cpp:27:13:27:13 | v | test2.cpp:12:21:12:21 | v | provenance | | @@ -6,18 +8,15 @@ edges | test2.cpp:38:13:38:16 | call to atoi | test2.cpp:39:3:39:18 | ... = ... | provenance | | | test2.cpp:38:13:38:16 | call to atoi | test2.cpp:39:9:39:11 | num | provenance | | | test2.cpp:39:3:39:18 | ... = ... | test2.cpp:40:3:40:5 | num | provenance | | -| test3.c:10:27:10:30 | **argv | test.c:11:24:11:27 | call to atoi | provenance | TaintFunction | -| test3.c:10:27:10:30 | **argv | test.c:41:5:41:24 | ... = ... | provenance | TaintFunction | -| test3.c:10:27:10:30 | **argv | test.c:51:5:51:24 | ... = ... | provenance | TaintFunction | | test5.cpp:5:5:5:17 | *getTaintedInt | test5.cpp:17:6:17:18 | call to getTaintedInt | provenance | | | test5.cpp:5:5:5:17 | *getTaintedInt | test5.cpp:18:6:18:18 | call to getTaintedInt | provenance | | | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:10:9:10:27 | call to strtoul | provenance | TaintFunction | | test5.cpp:10:9:10:27 | call to strtoul | test5.cpp:5:5:5:17 | *getTaintedInt | provenance | | | test5.cpp:18:2:18:20 | ... = ... | test5.cpp:19:6:19:6 | y | provenance | | | test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:18:2:18:20 | ... = ... | provenance | | -| test.c:10:27:10:30 | **argv | test.c:11:24:11:27 | call to atoi | provenance | TaintFunction | -| test.c:10:27:10:30 | **argv | test.c:41:5:41:24 | ... = ... | provenance | TaintFunction | -| test.c:10:27:10:30 | **argv | test.c:51:5:51:24 | ... = ... | provenance | TaintFunction | +| test.c:10:28:10:31 | **argv | test.c:11:24:11:27 | call to atoi | provenance | TaintFunction | +| test.c:10:28:10:31 | **argv | test.c:41:5:41:24 | ... = ... | provenance | TaintFunction | +| test.c:10:28:10:31 | **argv | test.c:51:5:51:24 | ... = ... | provenance | TaintFunction | | test.c:11:24:11:27 | call to atoi | test.c:14:15:14:28 | maxConnections | provenance | | | test.c:41:5:41:24 | ... = ... | test.c:44:7:44:10 | len2 | provenance | | | test.c:41:5:41:24 | ... = ... | test.c:44:7:44:12 | ... -- | provenance | | @@ -26,6 +25,8 @@ edges | test.c:51:5:51:24 | ... = ... | test.c:54:7:54:12 | ... -- | provenance | | | test.c:54:7:54:12 | ... -- | test.c:54:7:54:10 | len3 | provenance | | nodes +| main.cpp:7:27:7:30 | **argv | semmle.label | **argv | +| main.cpp:8:17:8:20 | **argv | semmle.label | **argv | | test2.cpp:12:21:12:21 | v | semmle.label | v | | test2.cpp:14:11:14:11 | v | semmle.label | v | | test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument | @@ -35,7 +36,6 @@ nodes | test2.cpp:39:3:39:18 | ... = ... | semmle.label | ... = ... | | test2.cpp:39:9:39:11 | num | semmle.label | num | | test2.cpp:40:3:40:5 | num | semmle.label | num | -| test3.c:10:27:10:30 | **argv | semmle.label | **argv | | test5.cpp:5:5:5:17 | *getTaintedInt | semmle.label | *getTaintedInt | | test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument | | test5.cpp:10:9:10:27 | call to strtoul | semmle.label | call to strtoul | @@ -43,7 +43,7 @@ nodes | test5.cpp:18:2:18:20 | ... = ... | semmle.label | ... = ... | | test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt | | test5.cpp:19:6:19:6 | y | semmle.label | y | -| test.c:10:27:10:30 | **argv | semmle.label | **argv | +| test.c:10:28:10:31 | **argv | semmle.label | **argv | | test.c:11:24:11:27 | call to atoi | semmle.label | call to atoi | | test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections | | test.c:41:5:41:24 | ... = ... | semmle.label | ... = ... | @@ -61,19 +61,7 @@ subpaths | test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets | | test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets | | test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets | -| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | **argv | a command-line argument | -| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument | -| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | **argv | a command-line argument | -| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument | -| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument | -| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument | -| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument | -| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument | +| test.c:14:15:14:28 | maxConnections | main.cpp:7:27:7:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | main.cpp:7:27:7:30 | **argv | a command-line argument | +| test.c:14:15:14:28 | maxConnections | main.cpp:7:27:7:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | main.cpp:7:27:7:30 | **argv | a command-line argument | +| test.c:44:7:44:10 | len2 | main.cpp:7:27:7:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | main.cpp:7:27:7:30 | **argv | a command-line argument | +| test.c:54:7:54:10 | len3 | main.cpp:7:27:7:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | main.cpp:7:27:7:30 | **argv | a command-line argument | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected index a79144feaca0..ae20929d7b8a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected @@ -4,20 +4,15 @@ | test2.cpp:17:11:17:22 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf | | test2.cpp:39:9:39:18 | ... + ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets | | test2.cpp:40:3:40:13 | ... += ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets | -| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument | -| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument | -| test4.cpp:13:7:13:20 | access to array | $@ flows an expression which might overflow negatively. | test4.cpp:8:27:8:30 | **argv | a command-line argument | +| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument | +| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument | +| test4.cpp:13:7:13:20 | access to array | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument | | test5.cpp:10:9:10:27 | call to strtoul | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets | | test5.cpp:17:6:17:27 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets | | test5.cpp:19:6:19:13 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets | | test6.cpp:11:10:11:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf | | test6.cpp:16:10:16:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf | | test6.cpp:30:11:30:16 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf | -| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test.c:10:27:10:30 | **argv | a command-line argument | -| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument | -| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument | -| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument | +| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | main.cpp:7:27:7:30 | **argv | a command-line argument | +| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument | +| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/main.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/main.cpp new file mode 100644 index 000000000000..645b5893deaa --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/main.cpp @@ -0,0 +1,12 @@ +extern "C" { +int main1(int argc, char** argv); +int main3(int argc, char** argv); +} +int main4(int argc, char** argv); + +int main(int argc, char** argv) { + main1(argc, argv); + main3(argc, argv); + main4(argc, argv); + return 0; +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test.c index 29ab7cc8f25c..b39e54084ac3 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test.c @@ -7,7 +7,7 @@ void startServer(int heapSize); typedef unsigned long size_t; size_t strlen(const char *s); -int main(int argc, char** argv) { +int main1(int argc, char** argv) { int maxConnections = atoi(argv[1]); // BAD: arithmetic on a user input without any validation diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test3.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test3.c index 57c3b529f586..a8116e058530 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test3.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test3.c @@ -7,7 +7,7 @@ // Regression test for ODASA-6054: IntegerOverflowTainted should // not report a result if the overflow happens in a macro expansion // from a macro that is defined in a system header. -int main(int argc, char **argv) { +int main3(int argc, char **argv) { char *cmd = argv[0]; int x = (int)(unsigned char)*cmd; // BAD: overflow int y = CAST(*cmd); // BAD: overflow in macro expansion (macro is not from a system header) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test4.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test4.cpp index 054aea93fbad..ad4cc80d30ac 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test4.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test4.cpp @@ -5,7 +5,7 @@ // by comparing the value to 0. This means that the cast cannot overflow, // regardless of what the input type is. -int main(int argc, char **argv) { +int main4(int argc, char **argv) { char *p = argv[0]; if (!p[0]) { // GOOD: cast to bool. return 1; diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-497/semmle/tests/tests2.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-497/semmle/tests/tests2.cpp index 4c72bc61f31d..c22d74b7a758 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-497/semmle/tests/tests2.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-497/semmle/tests/tests2.cpp @@ -50,7 +50,7 @@ int val(); const char *global1 = mysql_get_client_info(); const char *global2 = "abc"; -void test1() +void test7() { int sock = socket(val(), val(), val()); From c90d0faaf6d49931ce9a8f68d46cdabcf34912ec Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 8 Oct 2024 20:34:20 +0200 Subject: [PATCH 2/2] C++: Fix ODR violations in dataflow tests --- .../dataflow/dataflow-tests/flowOut.cpp | 4 ++-- .../dataflow/dataflow-tests/self-Iterator.cpp | 2 +- .../dataflow-tests/true_upon_entry.cpp | 22 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/flowOut.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/flowOut.cpp index d6a06361524e..a60a20f12e3a 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/flowOut.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/flowOut.cpp @@ -78,7 +78,7 @@ int* deref(int** p) { // $ ast-def=p ir-def=*p ir-def=**p return q; } -void test1() { +void flowout_test1() { int x = 0; int* p = &x; deref(&p)[0] = source(); @@ -95,7 +95,7 @@ void addtaint2(int** p) { // $ ast-def=p ir-def=*p ir-def=**p addtaint1(q); } -void test2() { +void flowout_test2() { int x = 0; int* p = &x; addtaint2(&p); diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp index cac7f222c302..3303a250ccc6 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp @@ -15,7 +15,7 @@ template<> struct std::iterator_traits }; -int test() { +int iterator_test() { unsigned long x = source(); sink(x); // $ ast ir } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/true_upon_entry.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/true_upon_entry.cpp index 923a7c0513d7..cb97ce325d20 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/true_upon_entry.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/true_upon_entry.cpp @@ -5,7 +5,7 @@ int source(); void sink(...); bool random(); -void test1() { +void on_entry_test1() { int x = source(); for (int i = 0; i < 10; i++) { x = 0; @@ -13,7 +13,7 @@ void test1() { sink(x); // $ SPURIOUS: ir } -void test2(int iterations) { +void on_entry_test2(int iterations) { int x = source(); for (int i = 0; i < iterations; i++) { x = 0; @@ -21,7 +21,7 @@ void test2(int iterations) { sink(x); // $ ast,ir } -void test3() { +void on_entry_test3() { int x = 0; for (int i = 0; i < 10; i++) { x = source(); @@ -29,7 +29,7 @@ void test3() { sink(x); // $ ast,ir } -void test4() { +void on_entry_test4() { int x = source(); for (int i = 0; i < 10; i++) { if (random()) @@ -39,7 +39,7 @@ void test4() { sink(x); // $ ast,ir } -void test5() { +void on_entry_test5() { int x = source(); for (int i = 0; i < 10; i++) { if (random()) @@ -49,7 +49,7 @@ void test5() { sink(x); // $ ast,ir } -void test6() { +void on_entry_test6() { int y; int x = source(); for (int i = 0; i < 10 && (y = 1); i++) { @@ -57,7 +57,7 @@ void test6() { sink(x); // $ ast,ir } -void test7() { +void on_entry_test7() { int y; int x = source(); for (int i = 0; i < 10 && (y = 1); i++) { @@ -66,7 +66,7 @@ void test7() { sink(x); // $ SPURIOUS: ir } -void test8() { +void on_entry_test8() { int x = source(); // It appears to the analysis that the condition can exit after `i < 10` // without having assigned to `x`. That is an effect of how the @@ -78,7 +78,7 @@ void test8() { sink(x); // $ SPURIOUS: ast,ir } -void test9() { +void on_entry_test9() { int y; int x = source(); for (int i = 0; (y = 1) && i < 10; i++) { @@ -86,14 +86,14 @@ void test9() { sink(x); // $ ast,ir } -void test10() { +void on_entry_test10() { int x = source(); for (int i = 0; (x = 1) && i < 10; i++) { } sink(x); // no flow } -void test10(int b, int d) { +void on_entry_test10(int b, int d) { int i = 0; int x = source(); if (b)