From 84f908656c52f1ec3413d850a9ffb73536c164ef Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 1 Aug 2023 21:21:12 +0100 Subject: [PATCH 01/16] Correct errno headers. This should have no impact on tests, but addresses an incompatibility with the standard library structure. --- cpp/common/test/includes/standard-library/cerrno | 3 +-- cpp/common/test/includes/standard-library/errno.h | 8 +++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cerrno b/cpp/common/test/includes/standard-library/cerrno index f1957abe6a..679ce128ea 100644 --- a/cpp/common/test/includes/standard-library/cerrno +++ b/cpp/common/test/includes/standard-library/cerrno @@ -1,2 +1 @@ -int __errno; -#define errno __errno \ No newline at end of file +#include \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/errno.h b/cpp/common/test/includes/standard-library/errno.h index 96195e6e19..be17eeb0b5 100644 --- a/cpp/common/test/includes/standard-library/errno.h +++ b/cpp/common/test/includes/standard-library/errno.h @@ -1,3 +1,5 @@ -namespace std { -typedef int errno_t; -} // namespace std \ No newline at end of file +#ifndef _GHLIBCPP_ERRNO +#define _GHLIBCPP_ERRNO +int __errno; +#define errno __errno +#endif // _GHLIBCPP_ERRNO \ No newline at end of file From 3e2f72b55d514170f620fa8f75a717ed59abb160 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 1 Aug 2023 22:05:53 +0100 Subject: [PATCH 02/16] Address string related compiler compatibility issues. This commit restructures the string, string.h and cstring headers to match the expected headers and namespaces of C++ standard declarations. This addresses compatibility issues with real compilers because our test cases expected to access C string functionality through the "#include " header include, which is not the case in practice. This commit addresses compiler compatibility issues in the following rules: * A12-0-2 * A27-0-2 * M16-0-5 * M18-0-5 * DCL55-CPP * EXP62-CPP * OOP57-CPP * STR50-CPP --- cpp/autosar/test/rules/A12-0-2/test.cpp | 2 +- cpp/autosar/test/rules/M18-0-5/test.cpp | 2 +- cpp/cert/test/rules/EXP62-CPP/test.cpp | 2 +- cpp/cert/test/rules/OOP57-CPP/test.cpp | 2 +- .../test/includes/standard-library/cstring.h | 27 +- .../test/includes/standard-library/istream.h | 4 +- .../test/includes/standard-library/string | 251 ++++++++++++++++- .../test/includes/standard-library/string.h | 258 +----------------- .../test.cpp | 2 +- ...nformationLeakageAcrossBoundaries.expected | 6 +- .../interprocedural.cpp | 2 +- .../multilayer.cpp | 2 +- .../test.cpp | 4 +- .../memcmpusedtocomparepaddingdata/test.cpp | 2 +- .../test.cpp | 2 +- .../test.cpp | 2 +- 16 files changed, 295 insertions(+), 275 deletions(-) diff --git a/cpp/autosar/test/rules/A12-0-2/test.cpp b/cpp/autosar/test/rules/A12-0-2/test.cpp index 50dfe4a101..6e640e62d4 100644 --- a/cpp/autosar/test/rules/A12-0-2/test.cpp +++ b/cpp/autosar/test/rules/A12-0-2/test.cpp @@ -1,5 +1,5 @@ #include -#include +#include class A { public: diff --git a/cpp/autosar/test/rules/M18-0-5/test.cpp b/cpp/autosar/test/rules/M18-0-5/test.cpp index 521326bef7..37ea1f6415 100644 --- a/cpp/autosar/test/rules/M18-0-5/test.cpp +++ b/cpp/autosar/test/rules/M18-0-5/test.cpp @@ -1,4 +1,4 @@ -#include +#include void test_unbounded_str_funs() { char str1[] = "Sample string"; diff --git a/cpp/cert/test/rules/EXP62-CPP/test.cpp b/cpp/cert/test/rules/EXP62-CPP/test.cpp index 1f80dc04c2..ebda14e624 100644 --- a/cpp/cert/test/rules/EXP62-CPP/test.cpp +++ b/cpp/cert/test/rules/EXP62-CPP/test.cpp @@ -1,4 +1,4 @@ -#include +#include struct S1 { int i, j, k; diff --git a/cpp/cert/test/rules/OOP57-CPP/test.cpp b/cpp/cert/test/rules/OOP57-CPP/test.cpp index 02059f98cc..430c910985 100644 --- a/cpp/cert/test/rules/OOP57-CPP/test.cpp +++ b/cpp/cert/test/rules/OOP57-CPP/test.cpp @@ -1,4 +1,4 @@ -#include +#include class trivial {}; diff --git a/cpp/common/test/includes/standard-library/cstring.h b/cpp/common/test/includes/standard-library/cstring.h index 8c34428fa8..2f3ffd393e 100644 --- a/cpp/common/test/includes/standard-library/cstring.h +++ b/cpp/common/test/includes/standard-library/cstring.h @@ -1,8 +1,29 @@ #ifndef _GHLIBCPP_CSTRING #define _GHLIBCPP_CSTRING -typedef unsigned long size_t; + +#include + namespace std { -void *memcpy(void *, const void *, size_t); -size_t strlen(const char *); +using ::memcmp; +using ::memcpy; +using ::memmove; +using ::memset; +using ::size_t; +using ::strcat; +using ::strchr; +using ::strcmp; +using ::strcoll; +using ::strcpy; +using ::strcspn; +using ::strlen; +using ::strncat; +using ::strncmp; +using ::strncpy; +using ::strpbrk; +using ::strrchr; +using ::strspn; +using ::strstr; +using ::strtok; +using ::strxfrm; } // namespace std #endif // _GHLIBCPP_CSTRING diff --git a/cpp/common/test/includes/standard-library/istream.h b/cpp/common/test/includes/standard-library/istream.h index f1758e6930..f56e67b8c5 100644 --- a/cpp/common/test/includes/standard-library/istream.h +++ b/cpp/common/test/includes/standard-library/istream.h @@ -1,8 +1,8 @@ #ifndef _GHLIBCPP_ISTREAM #define _GHLIBCPP_ISTREAM -#include "ios.h" -#include "string.h" +#include +#include namespace std { template diff --git a/cpp/common/test/includes/standard-library/string b/cpp/common/test/includes/standard-library/string index de6c8e145a..8759804234 100644 --- a/cpp/common/test/includes/standard-library/string +++ b/cpp/common/test/includes/standard-library/string @@ -1 +1,250 @@ -#include \ No newline at end of file +#ifndef _GHLIBCPP_STRING +#define _GHLIBCPP_STRING +#include "initializer_list" +#include "iosfwd.h" +#include "iterator.h" +#include "stddef.h" + +namespace std { +template struct char_traits; + +template class allocator { +public: + allocator() throw(); + typedef size_t size_type; +}; + +template , + class Allocator = allocator> +class basic_string { +public: + using value_type = charT; + using reference = value_type &; + using const_reference = const value_type &; + typedef typename Allocator::size_type size_type; + static const size_type npos = -1; + + basic_string() : basic_string(Allocator()) {} + explicit basic_string(const Allocator &a); + basic_string(const basic_string &str); + basic_string(basic_string &&str) noexcept; + basic_string(const charT *s, size_type n, const Allocator &a = Allocator()); + basic_string(const charT *s, const Allocator &a = Allocator()); + basic_string(size_type n, charT c, const Allocator &a = Allocator()); + template + basic_string(InputIterator begin, InputIterator end, + const Allocator &a = Allocator()); + + ~basic_string(); + basic_string &operator=(const basic_string &str); + basic_string &operator=(basic_string &&str) noexcept; + basic_string &operator=(const charT *s); + basic_string &operator=(charT c); + basic_string &operator=(initializer_list); + + const charT *c_str() const; + charT *data() noexcept; + size_type size() const noexcept; + size_type length() const noexcept; + + typedef __iterator iterator; + typedef __iterator const_iterator; + + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + const_iterator cbegin() const; + const_iterator cend() const; + + const charT &front() const; + charT &front(); + const charT &back() const; + charT &back(); + + const_reference operator[](size_type pos) const; + reference operator[](size_type pos); + const_reference at(size_type n) const; + reference at(size_type n); + basic_string &operator+=(const basic_string &str); + basic_string &operator+=(const charT *s); + basic_string &operator+=(charT c); + basic_string &operator+=(initializer_list); + basic_string &append(const basic_string &str); + basic_string &append(const basic_string &str, size_type pos, + size_type n = npos); + basic_string &append(const charT *s, size_type n); + basic_string &append(const charT *s); + basic_string &append(size_type n, charT c); + template + basic_string &append(InputIterator first, InputIterator last); + basic_string &append(initializer_list); + void push_back(charT c); + basic_string &assign(const basic_string &str); + basic_string &assign(basic_string &&str) noexcept; + basic_string &assign(const basic_string &str, size_type pos, + size_type n = npos); + basic_string &assign(const charT *s, size_type n); + basic_string &assign(const charT *s); + basic_string &assign(size_type n, charT c); + template + basic_string &assign(InputIterator first, InputIterator last); + basic_string &assign(initializer_list); + basic_string &insert(size_type pos1, const basic_string &str); + basic_string &insert(size_type pos1, const basic_string &str, size_type pos2, + size_type n = npos); + basic_string &insert(size_type pos, const charT *s, size_type n); + basic_string &insert(size_type pos, const charT *s); + basic_string &insert(size_type pos, size_type n, charT c); + iterator insert(const_iterator p, charT c); + iterator insert(const_iterator p, size_type n, charT c); + template + iterator insert(const_iterator p, InputIterator first, InputIterator last); + iterator insert(const_iterator p, initializer_list); + basic_string &erase(size_type pos = 0, size_type n = npos); + iterator erase(const_iterator p); + iterator erase(const_iterator first, const_iterator last); + basic_string &replace(size_type pos1, size_type n1, const basic_string &str); + basic_string &replace(size_type pos1, size_type n1, const basic_string &str, + size_type pos2, size_type n2 = npos); + basic_string &replace(size_type pos, size_type n1, const charT *s, + size_type n2); + basic_string &replace(size_type pos, size_type n1, const charT *s); + basic_string &replace(size_type pos, size_type n1, size_type n2, charT c); + basic_string &replace(const_iterator i1, const_iterator i2, + const basic_string &str); + basic_string &replace(const_iterator i1, const_iterator i2, const charT *s, + size_type n); + basic_string &replace(const_iterator i1, const_iterator i2, const charT *s); + basic_string &replace(const_iterator i1, const_iterator i2, size_type n, + charT c); + template + basic_string &replace(const_iterator i1, const_iterator i2, InputIterator j1, + InputIterator j2); + basic_string &replace(const_iterator, const_iterator, + initializer_list); + + size_type copy(charT *s, size_type n, size_type pos = 0) const; + void clear() noexcept; + void swap(basic_string &s) noexcept; + + size_type find(const basic_string &str, size_type pos = 0) const noexcept; + size_type find(const charT *s, size_type pos, size_type n) const; + size_type find(const charT *s, size_type pos = 0) const; + size_type find(charT c, size_type pos = 0) const; + size_type rfind(const basic_string &str, size_type pos = npos) const noexcept; + size_type rfind(const charT *s, size_type pos, size_type n) const; + size_type rfind(const charT *s, size_type pos = npos) const; + size_type rfind(charT c, size_type pos = npos) const; + size_type find_first_of(const basic_string &str, + size_type pos = 0) const noexcept; + size_type find_first_of(const charT *s, size_type pos, size_type n) const; + size_type find_first_of(const charT *s, size_type pos = 0) const; + size_type find_first_of(charT c, size_type pos = 0) const; + size_type find_last_of(const basic_string &str, + size_type pos = npos) const noexcept; + size_type find_last_of(const charT *s, size_type pos, size_type n) const; + size_type find_last_of(const charT *s, size_type pos = npos) const; + size_type find_last_of(charT c, size_type pos = npos) const; + size_type find_first_not_of(const basic_string &str, + size_type pos = 0) const noexcept; + size_type find_first_not_of(const charT *s, size_type pos, size_type n) const; + size_type find_first_not_of(const charT *s, size_type pos = 0) const; + size_type find_first_not_of(charT c, size_type pos = 0) const; + size_type find_last_not_of(const basic_string &str, + + size_type pos = npos) const noexcept; + size_type find_last_not_of(const charT *s, size_type pos, size_type n) const; + size_type find_last_not_of(const charT *s, size_type pos = npos) const; + size_type find_last_not_of(charT c, size_type pos = npos) const; + basic_string substr(size_type pos = 0, size_type n = npos) const; + int compare(const basic_string &str) const noexcept; + int compare(size_type pos1, size_type n1, const basic_string &str) const; + int compare(size_type pos1, size_type n1, const basic_string &str, + size_type pos2, size_type n2 = npos) const; + int compare(const charT *s) const; + int compare(size_type pos1, size_type n1, const charT *s) const; + int compare(size_type pos1, size_type n1, const charT *s, size_type n2) const; +}; + +template +basic_string +operator+(const basic_string &lhs, + const basic_string &rhs); +template +basic_string +operator+(const basic_string &lhs, const charT *rhs); +template +basic_string +operator+(const charT *lhs, const basic_string &rhs); + +template +bool operator==(const basic_string &lhs, + const basic_string &rhs) noexcept; +template +bool operator==(const charT *lhs, + const basic_string &rhs); +template +bool operator==(const basic_string &lhs, + const charT *rhs); +template +bool operator!=(const basic_string &lhs, + const basic_string &rhs) noexcept; +template +bool operator!=(const charT *lhs, + const basic_string &rhs); +template +bool operator!=(const basic_string &lhs, + const charT *rhs); +template +bool operator<(const basic_string &lhs, + const basic_string &rhs) noexcept; +template +bool operator<(const basic_string &lhs, + const charT *rhs); +template +bool operator<(const charT *lhs, + const basic_string &rhs); +template +bool operator>(const basic_string &lhs, + const basic_string &rhs) noexcept; +template +bool operator>(const basic_string &lhs, + const charT *rhs); +template +bool operator>(const charT *lhs, + const basic_string &rhs); +template +bool operator<=(const basic_string &lhs, + const basic_string &rhs) noexcept; +template +bool operator<=(const basic_string &lhs, + const charT *rhs); +template +bool operator<=(const charT *lhs, + const basic_string &rhs); +template +bool operator>=(const basic_string &lhs, + const basic_string &rhs) noexcept; +template +bool operator>=(const basic_string &lhs, + const charT *rhs); +template +bool operator>=(const charT *lhs, + const basic_string &rhs); + +typedef basic_string string; + +int stoi(const string &str, size_t *idx = 0, int base = 10); +long stol(const string &str, size_t *idx = 0, int base = 10); +unsigned long stoul(const string &str, size_t *idx = 0, int base = 10); +long long stoll(const string &str, size_t *idx = 0, int base = 10); +unsigned long long stoull(const string &str, size_t *idx = 0, int base = 10); +float stof(const string &str, size_t *idx = 0); +double stod(const string &str, size_t *idx = 0); +long double stold(const string &str, size_t *idx = 0); + +std::string to_string(int value); +} // namespace std + +#endif // _GHLIBCPP_STRING \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/string.h b/cpp/common/test/includes/standard-library/string.h index f514394688..c4d06b6e7b 100644 --- a/cpp/common/test/includes/standard-library/string.h +++ b/cpp/common/test/includes/standard-library/string.h @@ -1,242 +1,10 @@ -#ifndef _GHLIBCPP_STRING -#define _GHLIBCPP_STRING -#include "errno.h" -#include "initializer_list" -#include "iosfwd.h" -#include "iterator.h" -#include "stddef.h" - -namespace std { -template struct char_traits; - -template class allocator { -public: - allocator() throw(); - typedef size_t size_type; -}; - -template , - class Allocator = allocator> -class basic_string { -public: - using value_type = charT; - using reference = value_type &; - using const_reference = const value_type &; - typedef typename Allocator::size_type size_type; - static const size_type npos = -1; - - basic_string() : basic_string(Allocator()) {} - explicit basic_string(const Allocator &a); - basic_string(const basic_string &str); - basic_string(basic_string &&str) noexcept; - basic_string(const charT *s, size_type n, const Allocator &a = Allocator()); - basic_string(const charT *s, const Allocator &a = Allocator()); - basic_string(size_type n, charT c, const Allocator &a = Allocator()); - template - basic_string(InputIterator begin, InputIterator end, - const Allocator &a = Allocator()); - - ~basic_string(); - basic_string &operator=(const basic_string &str); - basic_string &operator=(basic_string &&str) noexcept; - basic_string &operator=(const charT *s); - basic_string &operator=(charT c); - basic_string &operator=(initializer_list); - - const charT *c_str() const; - charT *data() noexcept; - size_type size() const noexcept; - size_type length() const noexcept; - - typedef __iterator iterator; - typedef __iterator const_iterator; - - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; - const_iterator cbegin() const; - const_iterator cend() const; - - const charT &front() const; - charT &front(); - const charT &back() const; - charT &back(); - - const_reference operator[](size_type pos) const; - reference operator[](size_type pos); - const_reference at(size_type n) const; - reference at(size_type n); - basic_string &operator+=(const basic_string &str); - basic_string &operator+=(const charT *s); - basic_string &operator+=(charT c); - basic_string &operator+=(initializer_list); - basic_string &append(const basic_string &str); - basic_string &append(const basic_string &str, size_type pos, - size_type n = npos); - basic_string &append(const charT *s, size_type n); - basic_string &append(const charT *s); - basic_string &append(size_type n, charT c); - template - basic_string &append(InputIterator first, InputIterator last); - basic_string &append(initializer_list); - void push_back(charT c); - basic_string &assign(const basic_string &str); - basic_string &assign(basic_string &&str) noexcept; - basic_string &assign(const basic_string &str, size_type pos, - size_type n = npos); - basic_string &assign(const charT *s, size_type n); - basic_string &assign(const charT *s); - basic_string &assign(size_type n, charT c); - template - basic_string &assign(InputIterator first, InputIterator last); - basic_string &assign(initializer_list); - basic_string &insert(size_type pos1, const basic_string &str); - basic_string &insert(size_type pos1, const basic_string &str, size_type pos2, - size_type n = npos); - basic_string &insert(size_type pos, const charT *s, size_type n); - basic_string &insert(size_type pos, const charT *s); - basic_string &insert(size_type pos, size_type n, charT c); - iterator insert(const_iterator p, charT c); - iterator insert(const_iterator p, size_type n, charT c); - template - iterator insert(const_iterator p, InputIterator first, InputIterator last); - iterator insert(const_iterator p, initializer_list); - basic_string &erase(size_type pos = 0, size_type n = npos); - iterator erase(const_iterator p); - iterator erase(const_iterator first, const_iterator last); - basic_string &replace(size_type pos1, size_type n1, const basic_string &str); - basic_string &replace(size_type pos1, size_type n1, const basic_string &str, - size_type pos2, size_type n2 = npos); - basic_string &replace(size_type pos, size_type n1, const charT *s, - size_type n2); - basic_string &replace(size_type pos, size_type n1, const charT *s); - basic_string &replace(size_type pos, size_type n1, size_type n2, charT c); - basic_string &replace(const_iterator i1, const_iterator i2, - const basic_string &str); - basic_string &replace(const_iterator i1, const_iterator i2, const charT *s, - size_type n); - basic_string &replace(const_iterator i1, const_iterator i2, const charT *s); - basic_string &replace(const_iterator i1, const_iterator i2, size_type n, - charT c); - template - basic_string &replace(const_iterator i1, const_iterator i2, InputIterator j1, - InputIterator j2); - basic_string &replace(const_iterator, const_iterator, - initializer_list); +#ifndef _GHLIBCPP_STRINGH +#define _GHLIBCPP_STRINGH - size_type copy(charT *s, size_type n, size_type pos = 0) const; - void clear() noexcept; - void swap(basic_string &s) noexcept; - - size_type find(const basic_string &str, size_type pos = 0) const noexcept; - size_type find(const charT *s, size_type pos, size_type n) const; - size_type find(const charT *s, size_type pos = 0) const; - size_type find(charT c, size_type pos = 0) const; - size_type rfind(const basic_string &str, size_type pos = npos) const noexcept; - size_type rfind(const charT *s, size_type pos, size_type n) const; - size_type rfind(const charT *s, size_type pos = npos) const; - size_type rfind(charT c, size_type pos = npos) const; - size_type find_first_of(const basic_string &str, - size_type pos = 0) const noexcept; - size_type find_first_of(const charT *s, size_type pos, size_type n) const; - size_type find_first_of(const charT *s, size_type pos = 0) const; - size_type find_first_of(charT c, size_type pos = 0) const; - size_type find_last_of(const basic_string &str, - size_type pos = npos) const noexcept; - size_type find_last_of(const charT *s, size_type pos, size_type n) const; - size_type find_last_of(const charT *s, size_type pos = npos) const; - size_type find_last_of(charT c, size_type pos = npos) const; - size_type find_first_not_of(const basic_string &str, - size_type pos = 0) const noexcept; - size_type find_first_not_of(const charT *s, size_type pos, size_type n) const; - size_type find_first_not_of(const charT *s, size_type pos = 0) const; - size_type find_first_not_of(charT c, size_type pos = 0) const; - size_type find_last_not_of(const basic_string &str, - - size_type pos = npos) const noexcept; - size_type find_last_not_of(const charT *s, size_type pos, size_type n) const; - size_type find_last_not_of(const charT *s, size_type pos = npos) const; - size_type find_last_not_of(charT c, size_type pos = npos) const; - basic_string substr(size_type pos = 0, size_type n = npos) const; - int compare(const basic_string &str) const noexcept; - int compare(size_type pos1, size_type n1, const basic_string &str) const; - int compare(size_type pos1, size_type n1, const basic_string &str, - size_type pos2, size_type n2 = npos) const; - int compare(const charT *s) const; - int compare(size_type pos1, size_type n1, const charT *s) const; - int compare(size_type pos1, size_type n1, const charT *s, size_type n2) const; -}; - -template -basic_string -operator+(const basic_string &lhs, - const basic_string &rhs); -template -basic_string -operator+(const basic_string &lhs, const charT *rhs); -template -basic_string -operator+(const charT *lhs, const basic_string &rhs); - -template -bool operator==(const basic_string &lhs, - const basic_string &rhs) noexcept; -template -bool operator==(const charT *lhs, - const basic_string &rhs); -template -bool operator==(const basic_string &lhs, - const charT *rhs); -template -bool operator!=(const basic_string &lhs, - const basic_string &rhs) noexcept; -template -bool operator!=(const charT *lhs, - const basic_string &rhs); -template -bool operator!=(const basic_string &lhs, - const charT *rhs); -template -bool operator<(const basic_string &lhs, - const basic_string &rhs) noexcept; -template -bool operator<(const basic_string &lhs, - const charT *rhs); -template -bool operator<(const charT *lhs, - const basic_string &rhs); -template -bool operator>(const basic_string &lhs, - const basic_string &rhs) noexcept; -template -bool operator>(const basic_string &lhs, - const charT *rhs); -template -bool operator>(const charT *lhs, - const basic_string &rhs); -template -bool operator<=(const basic_string &lhs, - const basic_string &rhs) noexcept; -template -bool operator<=(const basic_string &lhs, - const charT *rhs); -template -bool operator<=(const charT *lhs, - const basic_string &rhs); -template -bool operator>=(const basic_string &lhs, - const basic_string &rhs) noexcept; -template -bool operator>=(const basic_string &lhs, - const charT *rhs); -template -bool operator>=(const charT *lhs, - const basic_string &rhs); - -typedef basic_string string; +#include "errno.h" typedef unsigned long size_t; + size_t strlen(const char *str); char *strcpy(char *destination, const char *source); char *strncpy(char *destination, const char *source, size_t num); @@ -273,22 +41,6 @@ void *memset(void *dest, int ch, size_t count); void *memmove(void *dest, const void *src, size_t count); int memcmp(const void *lhs, const void *rhs, size_t count); -errno_t memcpy_s(void *dest, rsize_t destsz, const void *src, rsize_t count); -errno_t memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t count); - -int stoi(const string &str, size_t *idx = 0, int base = 10); -long stol(const string &str, size_t *idx = 0, int base = 10); -unsigned long stoul(const string &str, size_t *idx = 0, int base = 10); -long long stoll(const string &str, size_t *idx = 0, int base = 10); -unsigned long long stoull(const string &str, size_t *idx = 0, int base = 10); -float stof(const string &str, size_t *idx = 0); -double stod(const string &str, size_t *idx = 0); -long double stold(const string &str, size_t *idx = 0); - -std::string to_string(int value); -} // namespace std - -std::errno_t memset_s(void *dest, rsize_t destsz, int ch, rsize_t count); size_t strlen(const char *str); -#endif // _GHLIBCPP_STRING \ No newline at end of file +#endif // _GHLIBCPP_STRINGH \ No newline at end of file diff --git a/cpp/common/test/rules/basicstringmaynotbenullterminated/test.cpp b/cpp/common/test/rules/basicstringmaynotbenullterminated/test.cpp index e903a933af..973a7a4ad1 100644 --- a/cpp/common/test/rules/basicstringmaynotbenullterminated/test.cpp +++ b/cpp/common/test/rules/basicstringmaynotbenullterminated/test.cpp @@ -1,6 +1,6 @@ #include +#include #include -#include void f1() { char a1[7] = "CodeQL"; diff --git a/cpp/common/test/rules/informationleakageacrossboundaries/InformationLeakageAcrossBoundaries.expected b/cpp/common/test/rules/informationleakageacrossboundaries/InformationLeakageAcrossBoundaries.expected index 38fcaf61be..d7a7659f07 100644 --- a/cpp/common/test/rules/informationleakageacrossboundaries/InformationLeakageAcrossBoundaries.expected +++ b/cpp/common/test/rules/informationleakageacrossboundaries/InformationLeakageAcrossBoundaries.expected @@ -15,6 +15,6 @@ | test.cpp:43:12:43:12 | s | 's' may leak information from {x (test.cpp:7)}. Path: s (test.cpp:43) --> & ... (test.cpp:47) | | test.cpp:58:12:58:12 | s | 's' may leak information from {x (test.cpp:7), y (test.cpp:8)}. Path: s (test.cpp:58) --> & ... (test.cpp:59) | | test.cpp:64:12:64:12 | s | 's' may leak information from {y (test.cpp:8)}. Path: s (test.cpp:64) --> & ... (test.cpp:66) | -| test.cpp:112:16:112:16 | s | 's' may leak information from {buf (test.cpp:92)}. Path: s (test.cpp:112) --> & ... (test.cpp:115) | -| test.cpp:128:12:128:12 | s | 's' may leak information from {x (test.cpp:7), y (test.cpp:8)}. Path: s (test.cpp:128) --> & ... (test.cpp:132) | -| test.cpp:157:22:157:22 | s | 's' may leak information from {2 to 2 bytes of padding in has_padding (test.cpp:151)}. Path: s (test.cpp:157) --> & ... (test.cpp:160) | +| test.cpp:110:16:110:16 | s | 's' may leak information from {buf (test.cpp:92)}. Path: s (test.cpp:110) --> & ... (test.cpp:113) | +| test.cpp:126:12:126:12 | s | 's' may leak information from {x (test.cpp:7), y (test.cpp:8)}. Path: s (test.cpp:126) --> & ... (test.cpp:130) | +| test.cpp:155:22:155:22 | s | 's' may leak information from {2 to 2 bytes of padding in has_padding (test.cpp:149)}. Path: s (test.cpp:155) --> & ... (test.cpp:158) | diff --git a/cpp/common/test/rules/informationleakageacrossboundaries/interprocedural.cpp b/cpp/common/test/rules/informationleakageacrossboundaries/interprocedural.cpp index 15e8b81682..016d40baeb 100644 --- a/cpp/common/test/rules/informationleakageacrossboundaries/interprocedural.cpp +++ b/cpp/common/test/rules/informationleakageacrossboundaries/interprocedural.cpp @@ -1,5 +1,5 @@ +#include #include -#include unsigned long copy_to_user(void *to, const void *from, unsigned long n); diff --git a/cpp/common/test/rules/informationleakageacrossboundaries/multilayer.cpp b/cpp/common/test/rules/informationleakageacrossboundaries/multilayer.cpp index 2298895de1..c5a9d29e0f 100644 --- a/cpp/common/test/rules/informationleakageacrossboundaries/multilayer.cpp +++ b/cpp/common/test/rules/informationleakageacrossboundaries/multilayer.cpp @@ -1,5 +1,5 @@ +#include #include -#include unsigned long copy_to_user(void *to, const void *from, unsigned long n); diff --git a/cpp/common/test/rules/informationleakageacrossboundaries/test.cpp b/cpp/common/test/rules/informationleakageacrossboundaries/test.cpp index 3b68ffbd86..9a5fe40ef8 100644 --- a/cpp/common/test/rules/informationleakageacrossboundaries/test.cpp +++ b/cpp/common/test/rules/informationleakageacrossboundaries/test.cpp @@ -1,5 +1,5 @@ +#include #include -#include unsigned long copy_to_user(void *to, const void *from, unsigned long n); @@ -106,8 +106,6 @@ void zero_array_by_ref() { copy_to_user(0, &s, sizeof s); // COMPLIANT } -char *strcpy(char *dst, const char *src); - void use_strcpy() { PascalString s; strcpy(s.buf, "Hello, World"); // does not zero rest of s.buf diff --git a/cpp/common/test/rules/memcmpusedtocomparepaddingdata/test.cpp b/cpp/common/test/rules/memcmpusedtocomparepaddingdata/test.cpp index 9f0ba8cab7..7d004a2a39 100644 --- a/cpp/common/test/rules/memcmpusedtocomparepaddingdata/test.cpp +++ b/cpp/common/test/rules/memcmpusedtocomparepaddingdata/test.cpp @@ -1,4 +1,4 @@ -#include +#include struct S1 { unsigned char buffType; diff --git a/cpp/common/test/rules/operationmaynotnullterminatecstylestring/test.cpp b/cpp/common/test/rules/operationmaynotnullterminatecstylestring/test.cpp index 1b35da9174..7e93427905 100644 --- a/cpp/common/test/rules/operationmaynotnullterminatecstylestring/test.cpp +++ b/cpp/common/test/rules/operationmaynotnullterminatecstylestring/test.cpp @@ -1,7 +1,7 @@ #pragma clang diagnostic ignored "-Wfortify-source" #include +#include #include -#include void f1() { char a1[7] = "CodeQL"; diff --git a/cpp/common/test/rules/preprocessingdirectivewithinmacroargument/test.cpp b/cpp/common/test/rules/preprocessingdirectivewithinmacroargument/test.cpp index a70d631041..f58cb4a442 100644 --- a/cpp/common/test/rules/preprocessingdirectivewithinmacroargument/test.cpp +++ b/cpp/common/test/rules/preprocessingdirectivewithinmacroargument/test.cpp @@ -1,4 +1,4 @@ -#include +#include #define MACROFUNCTION(X) std::strlen(X) void f() { From 769ece525fca9dc9f71d01353b46cc3ce090bd53 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 1 Aug 2023 22:25:43 +0100 Subject: [PATCH 03/16] A1-1-2: Add an options flag for clang clang also supports -w for disabling all options. clang/A1-1-2 was not on the list of open issues, but gcc/A1-1-2 was - I think this is an error in the matrix testing. --- cpp/autosar/test/rules/A1-1-2.3/options.clang | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/autosar/test/rules/A1-1-2.3/options.clang b/cpp/autosar/test/rules/A1-1-2.3/options.clang index e69de29bb2..b45da65784 100644 --- a/cpp/autosar/test/rules/A1-1-2.3/options.clang +++ b/cpp/autosar/test/rules/A1-1-2.3/options.clang @@ -0,0 +1 @@ +-w \ No newline at end of file From 446ebfe3f5aece744d3910c03ee0c96e5617bf75 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 2 Aug 2023 01:04:49 +0100 Subject: [PATCH 04/16] A8-4-13: Fix compiler compatibility FPs Fix false positives identified by compiler compatibility testing on gcc/clang, which identified that shared_ptr used a hidden base class in real compilers causing our detection of modifying function calls to fail. This has been addressed, with a bonus modification to more accurately represent which pointer/reference types are captured. --- .../2023-08-02-a8-4-13-false-positives.md | 1 + ...trPassedToFunctionWithImproperSemantics.ql | 16 +++++++--- .../test/includes/standard-library/memory.h | 31 +++++++++++-------- 3 files changed, 30 insertions(+), 18 deletions(-) create mode 100644 change_notes/2023-08-02-a8-4-13-false-positives.md diff --git a/change_notes/2023-08-02-a8-4-13-false-positives.md b/change_notes/2023-08-02-a8-4-13-false-positives.md new file mode 100644 index 0000000000..669a10c9a0 --- /dev/null +++ b/change_notes/2023-08-02-a8-4-13-false-positives.md @@ -0,0 +1 @@ + - `A8-4-13` - reduce false positives when using gcc/clang where a modifying operation was used on a shared_ptr. \ No newline at end of file diff --git a/cpp/autosar/src/rules/A8-4-13/SharedPtrPassedToFunctionWithImproperSemantics.ql b/cpp/autosar/src/rules/A8-4-13/SharedPtrPassedToFunctionWithImproperSemantics.ql index df757685fb..5a8d06a6da 100644 --- a/cpp/autosar/src/rules/A8-4-13/SharedPtrPassedToFunctionWithImproperSemantics.ql +++ b/cpp/autosar/src/rules/A8-4-13/SharedPtrPassedToFunctionWithImproperSemantics.ql @@ -19,13 +19,19 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers +class AutosarSharedPointerOrDerived extends Type { + AutosarSharedPointerOrDerived() { + this.getUnspecifiedType() instanceof AutosarSharedPointer or + this.getUnspecifiedType().(DerivedType).getBaseType() instanceof AutosarSharedPointer + } +} + Expr underlyingObjectAffectingSharedPointerExpr(Function f) { result = any(VariableAccess va, FunctionCall fc | va.getEnclosingFunction() = f and - // strip the type so as to include reference parameter types - va.getType().stripType() instanceof AutosarSharedPointer and - fc.getTarget().getDeclaringType().stripType() instanceof AutosarSharedPointer and + // The type of the variable is either a shared_ptr, or a reference or pointer to a shared_ptr + va.getType() instanceof AutosarSharedPointerOrDerived and fc.getQualifier() = va and // include only calls to methods which modify the underlying object fc.getTarget().hasName(["operator=", "reset", "swap"]) @@ -36,7 +42,7 @@ Expr underlyingObjectAffectingSharedPointerExpr(Function f) { predicate flowsToUnderlyingObjectAffectingExpr(Parameter p) { // check if a parameter flows locally to an expression which affects smart pointer lifetime - p.getType().stripType() instanceof AutosarSharedPointer and + p.getType() instanceof AutosarSharedPointerOrDerived and localExprFlow(p.getAnAccess(), underlyingObjectAffectingSharedPointerExpr(p.getFunction())) or // else handle nested cases, such as passing smart pointers as reference arguments @@ -54,7 +60,7 @@ predicate flowsToUnderlyingObjectAffectingExpr(Parameter p) { from DefinedSmartPointerParameter p, string problem where not isExcluded(p, SmartPointers1Package::smartPointerAsParameterWithoutLifetimeSemanticsQuery()) and - p.getType().stripType() instanceof AutosarSharedPointer and + p.getType() instanceof AutosarSharedPointerOrDerived and ( // handle the parameter depending on its derived type p.getType() instanceof RValueReferenceType and diff --git a/cpp/common/test/includes/standard-library/memory.h b/cpp/common/test/includes/standard-library/memory.h index cf8be3fade..e88c40b965 100644 --- a/cpp/common/test/includes/standard-library/memory.h +++ b/cpp/common/test/includes/standard-library/memory.h @@ -1,7 +1,7 @@ #ifndef _GHLIBCPP_MEMORY #define _GHLIBCPP_MEMORY -#include "stddef.h" #include "exception.h" +#include "stddef.h" namespace std { @@ -18,6 +18,7 @@ template struct default_delete { template > class unique_ptr { public: + typedef T *pointer; unique_ptr() {} unique_ptr(T *ptr) {} unique_ptr(const unique_ptr &t) = delete; @@ -27,9 +28,7 @@ class unique_ptr { T *operator->() const noexcept { return ptr; } T *get() const noexcept { return ptr; } T *release() { return ptr; } - void reset() {} - void reset(T *ptr) {} - void reset(T ptr) {} + void reset(pointer __p = pointer()) {} T *get() { return ptr; } unique_ptr &operator=(const unique_ptr &) = delete; unique_ptr &operator=(unique_ptr &&) { return *this; } @@ -70,23 +69,29 @@ template class unique_ptr { template unique_ptr make_unique(Args &&...args); template unique_ptr make_unique(size_t n); -template class shared_ptr { +template class __shared_ptr { +public: + void reset() noexcept; + template void reset(Y *p); + template void reset(Y *p, D d); + template void reset(Y *p, D d, A a); +}; + +template class shared_ptr : public __shared_ptr { public: - shared_ptr() {} - shared_ptr(T *ptr) {} + shared_ptr(); + shared_ptr(T *ptr); shared_ptr(const shared_ptr &r) noexcept; template shared_ptr(const shared_ptr &r) noexcept; shared_ptr(shared_ptr &&r) noexcept; template shared_ptr(shared_ptr &&r) noexcept; shared_ptr(unique_ptr &&t) {} ~shared_ptr() {} - T &operator*() const { return *ptr; } - T *operator->() const noexcept { return ptr; } - void reset() {} - void reset(T *pt) {} - void reset(T pt) {} + T &operator*() const noexcept; + T *operator->() const noexcept; + long use_count() const noexcept { return 0; } - T *get() { return ptr; } + T *get() const noexcept { return ptr; } shared_ptr &operator=(const shared_ptr &) {} shared_ptr &operator=(shared_ptr &&) { return *this; } template shared_ptr &operator=(shared_ptr &&) { From 25bc94dfd12a1445596e3195049409a9e0e08661 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 2 Aug 2023 18:19:33 +0100 Subject: [PATCH 05/16] Fixup stubs after changes to string and string.h --- cpp/common/test/includes/standard-library/array | 4 ++-- cpp/common/test/includes/standard-library/deque.h | 4 ++-- cpp/common/test/includes/standard-library/ostream.h | 2 +- cpp/common/test/includes/standard-library/random.h | 2 +- cpp/common/test/includes/standard-library/stdexcept.h | 4 ++-- cpp/common/test/includes/standard-library/vector.h | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/common/test/includes/standard-library/array b/cpp/common/test/includes/standard-library/array index b77ca4ca99..ca4d3291ad 100644 --- a/cpp/common/test/includes/standard-library/array +++ b/cpp/common/test/includes/standard-library/array @@ -1,7 +1,7 @@ #ifndef _GHLIBCPP_ARRAY #define _GHLIBCPP_ARRAY -#include "iterator.h" -#include "string.h" +#include +#include // Note: a few features currently unused by tests are commented out namespace std { diff --git a/cpp/common/test/includes/standard-library/deque.h b/cpp/common/test/includes/standard-library/deque.h index aee0573229..00b44b704a 100644 --- a/cpp/common/test/includes/standard-library/deque.h +++ b/cpp/common/test/includes/standard-library/deque.h @@ -1,7 +1,7 @@ #ifndef _GHLIBCPP_DEQUE #define _GHLIBCPP_DEQUE -#include "iterator.h" -#include "string.h" +#include +#include namespace std { template > class deque { diff --git a/cpp/common/test/includes/standard-library/ostream.h b/cpp/common/test/includes/standard-library/ostream.h index bde2b7a53f..9f2c6d9069 100644 --- a/cpp/common/test/includes/standard-library/ostream.h +++ b/cpp/common/test/includes/standard-library/ostream.h @@ -1,7 +1,7 @@ #ifndef _GHLIBCPP_OSTREAM #define _GHLIBCPP_OSTREAM -#include "string.h" #include +#include namespace std { template diff --git a/cpp/common/test/includes/standard-library/random.h b/cpp/common/test/includes/standard-library/random.h index e3f3dcab0a..1a2b341226 100644 --- a/cpp/common/test/includes/standard-library/random.h +++ b/cpp/common/test/includes/standard-library/random.h @@ -2,7 +2,7 @@ #define _GHLIBCPP_RANDOM #include "cstdint.h" #include "stddef.h" -#include "string.h" +#include namespace std { template diff --git a/cpp/common/test/includes/standard-library/stdexcept.h b/cpp/common/test/includes/standard-library/stdexcept.h index fd9f7f9e6d..cb9af14db2 100644 --- a/cpp/common/test/includes/standard-library/stdexcept.h +++ b/cpp/common/test/includes/standard-library/stdexcept.h @@ -1,7 +1,7 @@ #ifndef _GHLIBCPP_STDEXCEPT #define _GHLIBCPP_STDEXCEPT -#include "exception.h" -#include "string.h" +#include +#include namespace std { class logic_error : public exception { diff --git a/cpp/common/test/includes/standard-library/vector.h b/cpp/common/test/includes/standard-library/vector.h index caa443f641..6d0293f8f5 100644 --- a/cpp/common/test/includes/standard-library/vector.h +++ b/cpp/common/test/includes/standard-library/vector.h @@ -1,7 +1,7 @@ #ifndef _GHLIBCPP_VECTOR #define _GHLIBCPP_VECTOR -#include "iterator.h" -#include "string.h" +#include +#include namespace std { From 7e496865fbf79fff7873b4223b86ff3e6e4e4920 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 2 Aug 2023 18:50:03 +0100 Subject: [PATCH 06/16] A18-1-4: Fix compiler compatibility issues with reset reset() is sometimes declared on a base class. Similar issue to A8-4-13, so I have refactored the SmartPointer class to provide predicates which identify the operations across multiple compilers. --- ...AnElementOfAnArrayPassedToASmartPointer.ql | 9 +----- ...trPassedToFunctionWithImproperSemantics.ql | 32 +++++++------------ .../src/codingstandards/cpp/SmartPointers.qll | 10 ++++++ 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql index 969373d436..5996448a38 100644 --- a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql +++ b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql @@ -46,14 +46,7 @@ class SingleObjectSmartPointerArrayConstructionConfig extends TaintTracking::Con ( sp.getAConstructorCallWithExternalObjectConstruction().getAnArgument() = sink.asExpr() or - sink.asExpr() = - any(FunctionCall fc, MemberFunction mf | - mf = fc.getTarget() and - mf.getDeclaringType() = sp and - mf.getName() = "reset" - | - fc.getArgument(0) - ) + sink.asExpr() = sp.getAResetCall().getArgument(0) ) ) } diff --git a/cpp/autosar/src/rules/A8-4-13/SharedPtrPassedToFunctionWithImproperSemantics.ql b/cpp/autosar/src/rules/A8-4-13/SharedPtrPassedToFunctionWithImproperSemantics.ql index 5a8d06a6da..422818f4c9 100644 --- a/cpp/autosar/src/rules/A8-4-13/SharedPtrPassedToFunctionWithImproperSemantics.ql +++ b/cpp/autosar/src/rules/A8-4-13/SharedPtrPassedToFunctionWithImproperSemantics.ql @@ -19,30 +19,20 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers -class AutosarSharedPointerOrDerived extends Type { - AutosarSharedPointerOrDerived() { - this.getUnspecifiedType() instanceof AutosarSharedPointer or - this.getUnspecifiedType().(DerivedType).getBaseType() instanceof AutosarSharedPointer - } -} - -Expr underlyingObjectAffectingSharedPointerExpr(Function f) { - result = - any(VariableAccess va, FunctionCall fc | - va.getEnclosingFunction() = f and - // The type of the variable is either a shared_ptr, or a reference or pointer to a shared_ptr - va.getType() instanceof AutosarSharedPointerOrDerived and - fc.getQualifier() = va and - // include only calls to methods which modify the underlying object - fc.getTarget().hasName(["operator=", "reset", "swap"]) - | - va - ) +VariableAccess underlyingObjectAffectingSharedPointerExpr(Function f) { + exists(FunctionCall fc | + // Find a call in the function + fc.getEnclosingFunction() = f and + // include only calls to methods which modify the underlying object + fc = any(AutosarSharedPointer s).getAModifyingCall() and + // Report the qualifier + fc.getQualifier() = result + ) } predicate flowsToUnderlyingObjectAffectingExpr(Parameter p) { // check if a parameter flows locally to an expression which affects smart pointer lifetime - p.getType() instanceof AutosarSharedPointerOrDerived and + p.getType().stripType() instanceof AutosarSharedPointer and localExprFlow(p.getAnAccess(), underlyingObjectAffectingSharedPointerExpr(p.getFunction())) or // else handle nested cases, such as passing smart pointers as reference arguments @@ -60,7 +50,7 @@ predicate flowsToUnderlyingObjectAffectingExpr(Parameter p) { from DefinedSmartPointerParameter p, string problem where not isExcluded(p, SmartPointers1Package::smartPointerAsParameterWithoutLifetimeSemanticsQuery()) and - p.getType() instanceof AutosarSharedPointerOrDerived and + p.getType().stripType() instanceof AutosarSharedPointer and ( // handle the parameter depending on its derived type p.getType() instanceof RValueReferenceType and diff --git a/cpp/common/src/codingstandards/cpp/SmartPointers.qll b/cpp/common/src/codingstandards/cpp/SmartPointers.qll index aa9ea420a3..a8bee55f87 100644 --- a/cpp/common/src/codingstandards/cpp/SmartPointers.qll +++ b/cpp/common/src/codingstandards/cpp/SmartPointers.qll @@ -51,6 +51,16 @@ abstract class AutosarSmartPointer extends Class { AutosarSmartPointer ) } + + FunctionCall getAResetCall() { + result.getTarget().hasName("reset") and + result.getQualifier().getType().stripType() = this + } + + FunctionCall getAModifyingCall() { + result.getTarget().hasName(["operator=", "reset", "swap"]) and + result.getQualifier().getType().stripType() = this + } } class AutosarUniquePointer extends AutosarSmartPointer { From a1bf3030b7b7432355d287f821883c0eff1da104 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 2 Aug 2023 23:04:08 +0100 Subject: [PATCH 07/16] A20-8-1/MEM56-CPP: Fix compiler compat issues Fix false negative issues related to the library structure of smart pointers. This commit makes the following changes: * Update `memory` stubs to move more functions to the __shared_ptr base class * Add dataflow summaries for smart pointer constructor calls and smart pointer get calls. * Add sanitizers to prevent flow into library code for the dataflow summaries added above. --- .../src/codingstandards/cpp/SmartPointers.qll | 5 ++++ ...nterValueStoredInUnrelatedSmartPointer.qll | 28 +++++++++++++++++++ .../test/includes/standard-library/memory.h | 5 ++-- ...alueStoredInUnrelatedSmartPointer.expected | 17 ----------- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/SmartPointers.qll b/cpp/common/src/codingstandards/cpp/SmartPointers.qll index a8bee55f87..46d5626a87 100644 --- a/cpp/common/src/codingstandards/cpp/SmartPointers.qll +++ b/cpp/common/src/codingstandards/cpp/SmartPointers.qll @@ -29,6 +29,11 @@ abstract class AutosarSmartPointer extends Class { ) } + FunctionCall getAGetCall() { + result.getTarget().hasName("get") and + result.getQualifier().getType().stripType() = this + } + FunctionCall getAnInitializerExpr() { result = any(FunctionCall fc | diff --git a/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll b/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll index ced6545e39..30caf12d75 100644 --- a/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll @@ -29,6 +29,34 @@ private class PointerToSmartPointerConstructorFlowConfig extends TaintTracking:: cc.getArgument(0) = sink.asExpr() ) } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + // Summarize flow through constructor calls + exists(AutosarSmartPointer sp, ConstructorCall cc | + sp.getAConstructorCall() = cc and + cc = node2.asExpr() and + cc.getArgument(0) = node1.asExpr() + ) + or + // Summarize flow through get() calls + exists(AutosarSmartPointer sp, FunctionCall fc | + sp.getAGetCall() = fc and + fc = node2.asExpr() and + fc.getQualifier() = node1.asExpr() + ) + } + + override predicate isSanitizerIn(DataFlow::Node node) { + // Exclude flow into header files outside the source archive which are summarized by the + // additional taint steps above. + exists(AutosarSmartPointer sp | + sp.getAConstructorCall().getTarget().getAParameter() = node.asParameter() + or + sp.getAGetCall().getTarget().getAParameter() = node.asParameter() + | + not exists(node.getLocation().getFile().getRelativePath()) + ) + } } query predicate problems( diff --git a/cpp/common/test/includes/standard-library/memory.h b/cpp/common/test/includes/standard-library/memory.h index e88c40b965..ba361a4dc6 100644 --- a/cpp/common/test/includes/standard-library/memory.h +++ b/cpp/common/test/includes/standard-library/memory.h @@ -75,6 +75,9 @@ template class __shared_ptr { template void reset(Y *p); template void reset(Y *p, D d); template void reset(Y *p, D d, A a); + + long use_count() const noexcept; + T *get() const noexcept; }; template class shared_ptr : public __shared_ptr { @@ -90,8 +93,6 @@ template class shared_ptr : public __shared_ptr { T &operator*() const noexcept; T *operator->() const noexcept; - long use_count() const noexcept { return 0; } - T *get() const noexcept { return ptr; } shared_ptr &operator=(const shared_ptr &) {} shared_ptr &operator=(shared_ptr &&) { return *this; } template shared_ptr &operator=(shared_ptr &&) { diff --git a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected index a4f85ecb72..d5d138ec19 100644 --- a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected +++ b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected @@ -6,7 +6,6 @@ problems | test.cpp:12:28:12:29 | v2 | test.cpp:10:8:10:17 | new | test.cpp:12:28:12:29 | v2 | Raw pointer flows to initialize multiple unrelated smart pointers. | | test.cpp:17:27:17:28 | v1 | test.cpp:16:13:16:22 | new | test.cpp:17:27:17:28 | v1 | Raw pointer flows to initialize multiple unrelated smart pointers. | edges -| ../../includes/standard-library/memory.h:76:17:76:19 | ptr | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | | test.cpp:3:14:3:15 | v1 | test.cpp:5:27:5:28 | v1 | | test.cpp:3:14:3:15 | v1 | test.cpp:6:31:6:33 | call to get | | test.cpp:3:14:3:15 | v1 | test.cpp:7:28:7:29 | v2 | @@ -14,21 +13,11 @@ edges | test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:31:6:33 | call to get | | test.cpp:8:8:8:14 | 0 | test.cpp:9:28:9:29 | v2 | | test.cpp:10:8:10:17 | new | test.cpp:11:28:11:29 | v2 | -| test.cpp:10:8:10:17 | new | test.cpp:11:28:11:29 | v2 | | test.cpp:10:8:10:17 | new | test.cpp:12:28:12:29 | v2 | -| test.cpp:11:28:11:29 | ref arg v2 | test.cpp:12:28:12:29 | v2 | -| test.cpp:11:28:11:29 | v2 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | -| test.cpp:11:28:11:29 | v2 | test.cpp:11:28:11:29 | ref arg v2 | -| test.cpp:16:13:16:22 | new | test.cpp:17:27:17:28 | v1 | | test.cpp:16:13:16:22 | new | test.cpp:17:27:17:28 | v1 | | test.cpp:16:13:16:22 | new | test.cpp:19:6:19:7 | v1 | -| test.cpp:17:27:17:28 | ref arg v1 | test.cpp:19:6:19:7 | v1 | -| test.cpp:17:27:17:28 | v1 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | -| test.cpp:17:27:17:28 | v1 | test.cpp:17:27:17:28 | ref arg v1 | | test.cpp:19:6:19:7 | v1 | test.cpp:3:14:3:15 | v1 | nodes -| ../../includes/standard-library/memory.h:76:17:76:19 | ptr | semmle.label | ptr | -| ../../includes/standard-library/memory.h:76:17:76:19 | ptr | semmle.label | ptr | | test.cpp:3:14:3:15 | v1 | semmle.label | v1 | | test.cpp:4:13:4:14 | v1 | semmle.label | v1 | | test.cpp:5:27:5:28 | v1 | semmle.label | v1 | @@ -38,15 +27,9 @@ nodes | test.cpp:8:8:8:14 | 0 | semmle.label | 0 | | test.cpp:9:28:9:29 | v2 | semmle.label | v2 | | test.cpp:10:8:10:17 | new | semmle.label | new | -| test.cpp:11:28:11:29 | ref arg v2 | semmle.label | ref arg v2 | -| test.cpp:11:28:11:29 | v2 | semmle.label | v2 | | test.cpp:11:28:11:29 | v2 | semmle.label | v2 | | test.cpp:12:28:12:29 | v2 | semmle.label | v2 | | test.cpp:16:13:16:22 | new | semmle.label | new | -| test.cpp:17:27:17:28 | ref arg v1 | semmle.label | ref arg v1 | -| test.cpp:17:27:17:28 | v1 | semmle.label | v1 | | test.cpp:17:27:17:28 | v1 | semmle.label | v1 | | test.cpp:19:6:19:7 | v1 | semmle.label | v1 | subpaths -| test.cpp:11:28:11:29 | v2 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | test.cpp:11:28:11:29 | ref arg v2 | -| test.cpp:17:27:17:28 | v1 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | test.cpp:17:27:17:28 | ref arg v1 | From bc122b73e8f4486950766ad0e52c54c6f32d19ec Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 2 Aug 2023 23:41:56 +0100 Subject: [PATCH 08/16] Add a change note for A20-8-1/MEM56-CPP/A18-1-4. --- change_notes/2023-08-02-a8-4-13-false-positives.md | 3 ++- change_notes/2023-08-02-smart-pointers.md | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 change_notes/2023-08-02-smart-pointers.md diff --git a/change_notes/2023-08-02-a8-4-13-false-positives.md b/change_notes/2023-08-02-a8-4-13-false-positives.md index 669a10c9a0..1effc84cb7 100644 --- a/change_notes/2023-08-02-a8-4-13-false-positives.md +++ b/change_notes/2023-08-02-a8-4-13-false-positives.md @@ -1 +1,2 @@ - - `A8-4-13` - reduce false positives when using gcc/clang where a modifying operation was used on a shared_ptr. \ No newline at end of file + - `A8-4-13` + - Address false positives caused by missing modelling of modifying operations for smart pointers for some standard libraries (such as libstdc++). \ No newline at end of file diff --git a/change_notes/2023-08-02-smart-pointers.md b/change_notes/2023-08-02-smart-pointers.md new file mode 100644 index 0000000000..f26d1ca27c --- /dev/null +++ b/change_notes/2023-08-02-smart-pointers.md @@ -0,0 +1,5 @@ + - `A20-8-1`/`MEM56-CPP` + - Address false negatives caused by lack of modelling of flow through smart pointers. + - Reduce flow paths through standard library headers to simplify results. + - `A18-1-4` + - Address false positives caused by missing modelling of modifying operations for smart pointers for some standard libraries (such as libstdc++). \ No newline at end of file From 089397a1e6a1385be0c143a8bc1d84fe9e9c62a8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 3 Aug 2023 20:37:09 +0100 Subject: [PATCH 09/16] STR51-CPP: Address false negatives due to incomplete replace modelling The std::string::replace function uses an internal typedef __const_iterator in libstdc++, instead of the const_iterator typedef. --- change_notes/2023-08-03-string-replace.md | 2 ++ .../cpp/standardlibrary/String.qll | 3 ++- cpp/common/test/includes/standard-library/string | 15 ++++++++------- 3 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 change_notes/2023-08-03-string-replace.md diff --git a/change_notes/2023-08-03-string-replace.md b/change_notes/2023-08-03-string-replace.md new file mode 100644 index 0000000000..58e5800003 --- /dev/null +++ b/change_notes/2023-08-03-string-replace.md @@ -0,0 +1,2 @@ + - `STR51-CPP` + - Address false negatives caused by incomplete modelling of the `std::string::replace()` function. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/standardlibrary/String.qll b/cpp/common/src/codingstandards/cpp/standardlibrary/String.qll index ed6a4fc8b2..f233410b89 100644 --- a/cpp/common/src/codingstandards/cpp/standardlibrary/String.qll +++ b/cpp/common/src/codingstandards/cpp/standardlibrary/String.qll @@ -45,7 +45,8 @@ class StdBasicString extends ClassTemplateInstantiation { Type getConstIteratorType() { exists(TypedefType t | t.getDeclaringType() = this and - t.getName() = "const_iterator" and + // Certain compilers user __const_iterator instead of const_iterator. + t.getName() = ["const_iterator", "__const_iterator"] and result = t ) } diff --git a/cpp/common/test/includes/standard-library/string b/cpp/common/test/includes/standard-library/string index 8759804234..ca267f6191 100644 --- a/cpp/common/test/includes/standard-library/string +++ b/cpp/common/test/includes/standard-library/string @@ -48,7 +48,8 @@ public: size_type length() const noexcept; typedef __iterator iterator; - typedef __iterator const_iterator; + typedef __iterator __const_iterator; + typedef __const_iterator const_iterator; iterator begin(); iterator end(); @@ -111,17 +112,17 @@ public: size_type n2); basic_string &replace(size_type pos, size_type n1, const charT *s); basic_string &replace(size_type pos, size_type n1, size_type n2, charT c); - basic_string &replace(const_iterator i1, const_iterator i2, + basic_string &replace(__const_iterator i1, __const_iterator i2, const basic_string &str); - basic_string &replace(const_iterator i1, const_iterator i2, const charT *s, + basic_string &replace(__const_iterator i1, __const_iterator i2, const charT *s, size_type n); - basic_string &replace(const_iterator i1, const_iterator i2, const charT *s); - basic_string &replace(const_iterator i1, const_iterator i2, size_type n, + basic_string &replace(__const_iterator i1, __const_iterator i2, const charT *s); + basic_string &replace(__const_iterator i1, __const_iterator i2, size_type n, charT c); template - basic_string &replace(const_iterator i1, const_iterator i2, InputIterator j1, + basic_string &replace(__const_iterator i1, __const_iterator i2, InputIterator j1, InputIterator j2); - basic_string &replace(const_iterator, const_iterator, + basic_string &replace(__const_iterator, __const_iterator, initializer_list); size_type copy(charT *s, size_type n, size_type pos = 0) const; From 1f9a3b4864e5a7c5fb4980b69127ecea6366a4ae Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 4 Aug 2023 01:15:33 +0100 Subject: [PATCH 10/16] A15-5-1: Clarify message and handle implicit noexcept(true). --- change_notes/2023-08-04-a15-5-1-noexcept.md | 3 +++ ...ialFunctionMissingNoExceptSpecification.ql | 16 +++++++++++--- ...ctionMissingNoExceptSpecification.expected | 22 +++++++++---------- cpp/autosar/test/rules/A15-5-1/test.cpp | 6 ++--- 4 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 change_notes/2023-08-04-a15-5-1-noexcept.md diff --git a/change_notes/2023-08-04-a15-5-1-noexcept.md b/change_notes/2023-08-04-a15-5-1-noexcept.md new file mode 100644 index 0000000000..3f8c43c64d --- /dev/null +++ b/change_notes/2023-08-04-a15-5-1-noexcept.md @@ -0,0 +1,3 @@ + - `A15-5-1` + - Rephrase alert message for `noalert(false)` special functions to clarify that this permits exceptions. + - Additional results for implicit `noexcept(true)` special functions highlighting that the specification should be made explicit. diff --git a/cpp/autosar/src/rules/A15-5-1/SpecialFunctionMissingNoExceptSpecification.ql b/cpp/autosar/src/rules/A15-5-1/SpecialFunctionMissingNoExceptSpecification.ql index ae61049b6f..77fdd88670 100644 --- a/cpp/autosar/src/rules/A15-5-1/SpecialFunctionMissingNoExceptSpecification.ql +++ b/cpp/autosar/src/rules/A15-5-1/SpecialFunctionMissingNoExceptSpecification.ql @@ -22,15 +22,25 @@ import codingstandards.cpp.exceptions.ExceptionSpecifications from SpecialFunction f, string message where not isExcluded(f, Exceptions2Package::specialFunctionMissingNoExceptSpecificationQuery()) and - not isNoExceptTrue(f) and + not isFDENoExceptTrue(f.getDefinition()) and not f.isCompilerGenerated() and not f.isDeleted() and not f.isDefaulted() and ( isNoExceptExplicitlyFalse(f) and - message = f.getQualifiedName() + " should not be noexcept(false)." + message = + "Special function " + f.getQualifiedName() + + " has a noexcept(false) specification that permits exceptions." or + isNoExceptTrue(f) and + message = + f.getQualifiedName() + + " has an implicit noexcept(true) specification but should make that explicit." + or + not isNoExceptTrue(f) and not isNoExceptExplicitlyFalse(f) and - message = f.getQualifiedName() + " is implicitly noexcept(false) and might throw." + message = + "Special function " + f.getQualifiedName() + + " has an implicit noexcept(false) specification that permits exceptions." ) select f, message diff --git a/cpp/autosar/test/rules/A15-5-1/SpecialFunctionMissingNoExceptSpecification.expected b/cpp/autosar/test/rules/A15-5-1/SpecialFunctionMissingNoExceptSpecification.expected index 9e698e41ae..4c6a3ae4f7 100644 --- a/cpp/autosar/test/rules/A15-5-1/SpecialFunctionMissingNoExceptSpecification.expected +++ b/cpp/autosar/test/rules/A15-5-1/SpecialFunctionMissingNoExceptSpecification.expected @@ -1,11 +1,11 @@ -| test.cpp:5:3:5:9 | ~ClassA | ClassA::~ClassA should not be noexcept(false). | -| test.cpp:9:3:9:9 | ~ClassB | ClassB::~ClassB should not be noexcept(false). | -| test.cpp:38:6:38:20 | operator delete | operator delete is implicitly noexcept(false) and might throw. | -| test.cpp:43:6:43:20 | operator delete | operator delete is implicitly noexcept(false) and might throw. | -| test.cpp:53:11:53:19 | operator= | ClassF::operator= should not be noexcept(false). | -| test.cpp:63:3:63:8 | ClassH | ClassH::ClassH should not be noexcept(false). | -| test.cpp:68:6:68:9 | swap | swap is implicitly noexcept(false) and might throw. | -| test.cpp:72:6:72:9 | swap | swap should not be noexcept(false). | -| test.cpp:77:8:77:11 | swap | ClassI::swap is implicitly noexcept(false) and might throw. | -| test.cpp:82:8:82:11 | swap | ClassJ::swap is implicitly noexcept(false) and might throw. | -| test.cpp:88:6:88:6 | swap | swap is implicitly noexcept(false) and might throw. | +| test.cpp:5:3:5:9 | ~ClassA | Special function ClassA::~ClassA has a noexcept(false) specification that permits exceptions. | +| test.cpp:9:3:9:9 | ~ClassB | Special function ClassB::~ClassB has a noexcept(false) specification that permits exceptions. | +| test.cpp:38:6:38:20 | operator delete | operator delete has an implicit noexcept(true) specification but should make that explicit. | +| test.cpp:43:6:43:20 | operator delete | operator delete has an implicit noexcept(true) specification but should make that explicit. | +| test.cpp:53:11:53:19 | operator= | Special function ClassF::operator= has a noexcept(false) specification that permits exceptions. | +| test.cpp:63:3:63:8 | ClassH | Special function ClassH::ClassH has a noexcept(false) specification that permits exceptions. | +| test.cpp:68:6:68:9 | swap | Special function swap has an implicit noexcept(false) specification that permits exceptions. | +| test.cpp:72:6:72:9 | swap | Special function swap has a noexcept(false) specification that permits exceptions. | +| test.cpp:77:8:77:11 | swap | Special function ClassI::swap has an implicit noexcept(false) specification that permits exceptions. | +| test.cpp:82:8:82:11 | swap | Special function ClassJ::swap has an implicit noexcept(false) specification that permits exceptions. | +| test.cpp:88:6:88:6 | swap | Special function swap has an implicit noexcept(false) specification that permits exceptions. | diff --git a/cpp/autosar/test/rules/A15-5-1/test.cpp b/cpp/autosar/test/rules/A15-5-1/test.cpp index adc45dd36c..353f4f62d7 100644 --- a/cpp/autosar/test/rules/A15-5-1/test.cpp +++ b/cpp/autosar/test/rules/A15-5-1/test.cpp @@ -1,6 +1,6 @@ #include "stddef.h" +#include #include - class ClassA { ~ClassA() noexcept(false) { throw std::exception(); } // NON_COMPLIANT }; @@ -36,12 +36,12 @@ class ClassD { }; void operator delete(void *ptr) { // NON_COMPLIANT - // NOTE: cannot be declared noexcept(false) + // NOTE: defaults to noexcept(true) throw std::exception(); } void operator delete(void *ptr, size_t size) { // NON_COMPLIANT - // NOTE: cannot be declared noexcept(false) + // NOTE: defaults to noexcept(true) throw std::exception(); } From e70089f964988a59fc672dcc802941a3a471a475 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 4 Aug 2023 01:21:42 +0100 Subject: [PATCH 11/16] A18-5-5/A18-5-6: Make test case valid for gcc --- cpp/autosar/test/rules/A18-5-5/test.cpp | 2 +- cpp/autosar/test/rules/A18-5-6/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/autosar/test/rules/A18-5-5/test.cpp b/cpp/autosar/test/rules/A18-5-5/test.cpp index 73244c15a6..b125f2201a 100644 --- a/cpp/autosar/test/rules/A18-5-5/test.cpp +++ b/cpp/autosar/test/rules/A18-5-5/test.cpp @@ -11,7 +11,7 @@ void *malloc1(int b) { // NON_COMPLIANT - recursion return malloc1(b - 1); } -void *malloc2(int b) __attribute__((no_caller_saved_registers, __malloc__)); +void *malloc2(int b) __attribute__((__malloc__)); void *malloc2(int b) { // NON_COMPLIANT - execution doesn't depend on b for (int i = 0; i < 10; i++) { diff --git a/cpp/autosar/test/rules/A18-5-6/test.cpp b/cpp/autosar/test/rules/A18-5-6/test.cpp index 576dbc02fa..a9434ed1b5 100644 --- a/cpp/autosar/test/rules/A18-5-6/test.cpp +++ b/cpp/autosar/test/rules/A18-5-6/test.cpp @@ -4,7 +4,7 @@ void *malloc1(int b) __attribute__((malloc)); void *malloc1(int b) { return nullptr; } // NON_COMPLIANT -void *malloc3(int b) __attribute__((no_caller_saved_registers, __malloc__)); +void *malloc3(int b) __attribute__((__malloc__)); void *malloc3(int b) { return nullptr; } // NON_COMPLIANT void h1() {} // NON_COMPLIANT From eb9541983ac6eace2ead9388646ead2840b6f167 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 4 Aug 2023 18:13:56 +0100 Subject: [PATCH 12/16] CON50-CPP: Mutexes do not have destructors in most real libraries Mark ~mutex() as deleted, as that is what we see in real libraries. Also modify lock_guard. This didn't have any affect on the test, but retained to ensure we better reflect real compilers. --- cpp/common/test/includes/standard-library/mutex.h | 10 +++++++--- .../DoNotDestroyAMutexWhileItIsLocked.expected | 3 --- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cpp/common/test/includes/standard-library/mutex.h b/cpp/common/test/includes/standard-library/mutex.h index 4f16824861..4c49819ddd 100644 --- a/cpp/common/test/includes/standard-library/mutex.h +++ b/cpp/common/test/includes/standard-library/mutex.h @@ -23,7 +23,7 @@ constexpr try_to_lock_t try_to_lock{}; class mutex { public: constexpr mutex() noexcept; - ~mutex(); + ~mutex() = default; mutex(const mutex &) = delete; mutex &operator=(const mutex &) = delete; void lock(); @@ -62,15 +62,19 @@ template void swap(unique_lock &x, unique_lock &y) noexcept; template -void lock(_Lock0 &_Lk0, _Lock1 &_Lk1, _LockN &..._LkN) { } +void lock(_Lock0 &_Lk0, _Lock1 &_Lk1, _LockN &..._LkN) {} template class lock_guard { public: typedef Mutex mutex_type; - explicit lock_guard(mutex_type &__m); + explicit lock_guard(mutex_type &__m) : _m(__m) { _m.lock(); } lock_guard(const lock_guard &) = delete; lock_guard &operator=(const lock_guard &) = delete; + ~lock_guard() { _m.unlock(); } + +private: + mutex_type &_m; }; } // namespace std diff --git a/cpp/common/test/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.expected b/cpp/common/test/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.expected index 0ae4aafa66..71ccc11ba7 100644 --- a/cpp/common/test/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.expected +++ b/cpp/common/test/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.expected @@ -1,6 +1,3 @@ -| test.cpp:4:18:4:33 | call to mutex | Mutex used by thread potentially $@ while in use. | test.cpp:11:18:11:26 | call to ~mutex | destroyed | | test.cpp:4:18:4:33 | call to mutex | Mutex used by thread potentially $@ while in use. | test.cpp:11:18:11:26 | delete | destroyed | -| test.cpp:16:14:16:15 | call to mutex | Mutex used by thread potentially $@ while in use. | test.cpp:21:1:21:1 | call to ~mutex | destroyed | | test.cpp:16:14:16:15 | call to mutex | Mutex used by thread potentially $@ while in use. | test.cpp:21:1:21:1 | return ... | destroyed | -| test.cpp:94:8:94:23 | call to mutex | Mutex used by thread potentially $@ while in use. | test.cpp:10:34:10:42 | call to ~mutex | destroyed | | test.cpp:94:8:94:23 | call to mutex | Mutex used by thread potentially $@ while in use. | test.cpp:10:34:10:42 | delete | destroyed | From 6aaf0ee2a5c6c35440b142637eae855e1e5abf9c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 4 Aug 2023 21:43:14 +0100 Subject: [PATCH 13/16] A15-2-2: Address compiler compatibility issue This query included some spurious edges for results that are outside the source location. We now exclude constructors outside the source archive to avoid these spurious edges, and make the result more stable. --- .../ConstructorErrorLeavesObjectInInvalidState.ql | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql b/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql index 5fbd09d522..47a4e86c19 100644 --- a/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql +++ b/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql @@ -78,11 +78,18 @@ class DeleteWrapperFunction extends Function { class ExceptionThrownInConstructor extends ExceptionThrowingExpr { Constructor c; - ExceptionThrownInConstructor() { exists(getAFunctionThrownType(c, this)) } + ExceptionThrownInConstructor() { + exists(getAFunctionThrownType(c, this)) and + // The constructor is within the users source code + exists(c.getFile().getRelativePath()) + } Constructor getConstructor() { result = c } } +/** + * Add the `nodes` predicate to ensure results with an empty path are still reported. + */ query predicate nodes(ExceptionFlowNode node) { any() } from From 14e4193c997fd88148f43444fa5c3288511a755f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 6 Aug 2023 23:35:13 +0100 Subject: [PATCH 14/16] A16-2-2: Library includes are not useless on real compilers Our useless include query is looking for includes where nothing from the included file is used by the including file. In this case, the declaration of v transitively uses std::size_t, and `#include ` transitively includes the file that defines std::size_t. To detect such cases we would need to report redundant includes e.g. includes for which useful symbols are provided, but which are made unnecessary by other imports in the file. For now we just exclude these expected results, as modifying the query is tricky. Furthermore, the intention of the rule is actually that we check standard library includes against the list of symbols as per the standard library, but again this is challenging. --- .../test/rules/A16-2-2/UnusedIncludeDirectives.expected.clang | 1 + .../test/rules/A16-2-2/UnusedIncludeDirectives.expected.gcc | 1 + .../test/rules/A16-2-2/UnusedIncludeDirectives.expected.qcc | 1 + cpp/autosar/test/rules/A16-2-2/test.cpp | 4 ++-- 4 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.clang create mode 100644 cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.gcc create mode 100644 cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.qcc diff --git a/cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.clang b/cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.clang new file mode 100644 index 0000000000..153bf8fa0f --- /dev/null +++ b/cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.clang @@ -0,0 +1 @@ +| test.cpp:1:1:1:19 | #include "test.hpp" | Nothing in this file uses anything from "test.hpp" | diff --git a/cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.gcc b/cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.gcc new file mode 100644 index 0000000000..153bf8fa0f --- /dev/null +++ b/cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.gcc @@ -0,0 +1 @@ +| test.cpp:1:1:1:19 | #include "test.hpp" | Nothing in this file uses anything from "test.hpp" | diff --git a/cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.qcc b/cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.qcc new file mode 100644 index 0000000000..153bf8fa0f --- /dev/null +++ b/cpp/autosar/test/rules/A16-2-2/UnusedIncludeDirectives.expected.qcc @@ -0,0 +1 @@ +| test.cpp:1:1:1:19 | #include "test.hpp" | Nothing in this file uses anything from "test.hpp" | diff --git a/cpp/autosar/test/rules/A16-2-2/test.cpp b/cpp/autosar/test/rules/A16-2-2/test.cpp index 50c66461b4..571675ab18 100644 --- a/cpp/autosar/test/rules/A16-2-2/test.cpp +++ b/cpp/autosar/test/rules/A16-2-2/test.cpp @@ -1,5 +1,5 @@ -#include "test.hpp" //NON_COMPLIANT -#include //NON_COMPLIANT +#include "test.hpp" //NON_COMPLIANT +#include //NON_COMPLIANT - redundant but not useless on real compilers #include //COMPLIANT std::vector v; \ No newline at end of file From f283a3839a397df460712d7986311934f9f845be Mon Sep 17 00:00:00 2001 From: "John L. Singleton" Date: Tue, 8 Aug 2023 15:26:41 -0400 Subject: [PATCH 15/16] fixes --- .../src/codingstandards/cpp/Concurrency.qll | 17 ++++++++++++++++- ...reventDeadlockByLockingInPredefinedOrder.qll | 6 +++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index 7c92d93752..609cfafc4b 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -114,7 +114,10 @@ class CPPMutexFunctionCall extends MutexFunctionCall { /** * Holds if this `CPPMutexFunctionCall` is a lock. */ - override predicate isLock() { getTarget().getName() = "lock" } + override predicate isLock() { + not isLockingOperationWithinLockingOperation(this) and + getTarget().getName() = "lock" + } /** * Holds if this `CPPMutexFunctionCall` is a speculative lock, defined as calling @@ -172,6 +175,7 @@ class CMutexFunctionCall extends MutexFunctionCall { * Holds if this `CMutexFunctionCall` is a lock. */ override predicate isLock() { + not isLockingOperationWithinLockingOperation(this) and getTarget().getName() = ["mtx_lock", "mtx_timedlock", "mtx_trylock"] } @@ -296,6 +300,16 @@ abstract class LockingOperation extends FunctionCall { * Holds if this is an unlock operation */ abstract predicate isUnlock(); + + /** + * Holds if this locking operation is really a locking operation within a + * designated locking operation. This library assumes the underlying locking + * operations are implemented correctly in that calling a `LockingOperation` + * results in the creation of a singular lock. + */ + predicate isLockingOperationWithinLockingOperation(LockingOperation inner) { + exists(LockingOperation outer | outer.getTarget() = inner.getEnclosingFunction()) + } } /** @@ -317,6 +331,7 @@ class RAIIStyleLock extends LockingOperation { * Holds if this is a lock operation */ override predicate isLock() { + not isLockingOperationWithinLockingOperation(this) and this instanceof ConstructorCall and lock = getArgument(0).getAChild*() and // defer_locks don't cause a lock diff --git a/cpp/common/src/codingstandards/cpp/rules/preventdeadlockbylockinginpredefinedorder/PreventDeadlockByLockingInPredefinedOrder.qll b/cpp/common/src/codingstandards/cpp/rules/preventdeadlockbylockinginpredefinedorder/PreventDeadlockByLockingInPredefinedOrder.qll index 3767f023a0..db755293c6 100644 --- a/cpp/common/src/codingstandards/cpp/rules/preventdeadlockbylockinginpredefinedorder/PreventDeadlockByLockingInPredefinedOrder.qll +++ b/cpp/common/src/codingstandards/cpp/rules/preventdeadlockbylockinginpredefinedorder/PreventDeadlockByLockingInPredefinedOrder.qll @@ -24,7 +24,11 @@ predicate getAnOrderedLockPair( lock1 = node.coveredByLock() and lock2 = node.coveredByLock() and not lock1 = lock2 and - lock1.getEnclosingFunction() = lock2.getEnclosingFunction() and + exists(Function f | + lock1.getEnclosingFunction() = f and + lock2.getEnclosingFunction() = f and + node.getBasicBlock().getEnclosingFunction() = f + ) and exists(Location l1Loc, Location l2Loc | l1Loc = lock1.getLocation() and l2Loc = lock2.getLocation() From f6a9d301293976428bd0dbbe17be23a6d11a7a06 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 14 Aug 2023 00:23:37 +0100 Subject: [PATCH 16/16] A18-1-4: Address compiler compatibility issue libc++ defines release inline in the header, which causes extraneous paths to be reported by CodeQL. Adjust to summarize and exclude. --- ...oAnElementOfAnArrayPassedToASmartPointer.ql | 18 ++++++++++++++++++ .../src/codingstandards/cpp/SmartPointers.qll | 5 +++++ .../test/includes/standard-library/memory.h | 9 ++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql index 5996448a38..639de937f7 100644 --- a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql +++ b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql @@ -50,6 +50,24 @@ class SingleObjectSmartPointerArrayConstructionConfig extends TaintTracking::Con ) ) } + + override predicate isAdditionalTaintStep(DataFlow::Node source, DataFlow::Node sink) { + exists(AutosarUniquePointer sp, FunctionCall fc | + fc = sp.getAReleaseCall() and + source.asExpr() = fc.getQualifier() and + sink.asExpr() = fc + ) + } + + override predicate isSanitizerIn(DataFlow::Node node) { + // Exclude flow into header files outside the source archive which are summarized by the + // additional taint steps above. + exists(AutosarUniquePointer sp | + sp.getAReleaseCall().getTarget() = node.asExpr().(ThisExpr).getEnclosingFunction() + | + not exists(node.getLocation().getFile().getRelativePath()) + ) + } } from diff --git a/cpp/common/src/codingstandards/cpp/SmartPointers.qll b/cpp/common/src/codingstandards/cpp/SmartPointers.qll index 46d5626a87..0f01d886be 100644 --- a/cpp/common/src/codingstandards/cpp/SmartPointers.qll +++ b/cpp/common/src/codingstandards/cpp/SmartPointers.qll @@ -70,6 +70,11 @@ abstract class AutosarSmartPointer extends Class { class AutosarUniquePointer extends AutosarSmartPointer { AutosarUniquePointer() { this.hasQualifiedName("std", "unique_ptr") } + + FunctionCall getAReleaseCall() { + result.getTarget().hasName("release") and + result.getQualifier().getType().stripType() = this + } } class AutosarSharedPointer extends AutosarSmartPointer { diff --git a/cpp/common/test/includes/standard-library/memory.h b/cpp/common/test/includes/standard-library/memory.h index ba361a4dc6..985ee41602 100644 --- a/cpp/common/test/includes/standard-library/memory.h +++ b/cpp/common/test/includes/standard-library/memory.h @@ -57,13 +57,20 @@ template class unique_ptr { pointer get() const noexcept; explicit operator bool() const noexcept; - pointer release() noexcept; + pointer release() noexcept { + pointer __p = get(); + _M_p = pointer(); + return __p; + } void reset(pointer p = pointer()) noexcept; void reset(nullptr_t) noexcept; template void reset(U) = delete; void swap(unique_ptr &u) noexcept; unique_ptr(const unique_ptr &) = delete; unique_ptr &operator=(const unique_ptr &) = delete; + +private: + pointer _M_p; }; template unique_ptr make_unique(Args &&...args);