From f64743e91d849f7aea15a5dd0b98d36fc21e2ae6 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 4 Jul 2024 16:19:32 +0100
Subject: [PATCH 01/12] C++: Fix mistake in example for
cpp/incorrect-allocation-error-handling.
---
.../Security/CWE/CWE-570/IncorrectAllocationErrorHandling.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cpp/ql/src/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.cpp b/cpp/ql/src/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.cpp
index 055aadcedb6..446cb14befa 100644
--- a/cpp/ql/src/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.cpp
+++ b/cpp/ql/src/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.cpp
@@ -34,7 +34,7 @@ void good1(std::size_t length) noexcept {
// GOOD: the allocation failure is handled appropriately.
void good2(std::size_t length) noexcept {
- int* dest = new int[length];
+ int* dest = new(std::nothrow) int[length];
if(!dest) {
return;
}
From 4de43e1bfa0e8b044cdddd771f9ba0f2c85c7e50 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 4 Jul 2024 17:07:10 +0100
Subject: [PATCH 02/12] C++: Add the examples to the test.
---
.../IncorrectAllocationErrorHandling.expected | 1 +
.../query-tests/Security/CWE/CWE-570/test.cpp | 51 +++++++++++++++++++
2 files changed, 52 insertions(+)
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.expected
index 67f1bee2f54..1d48edd7cea 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.expected
@@ -16,3 +16,4 @@
| test.cpp:151:9:151:24 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:152:15:152:18 | { ... } | This catch block |
| test.cpp:199:15:199:35 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:201:16:201:19 | { ... } | This catch block |
| test.cpp:212:14:212:34 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:213:34:213:36 | { ... } | This catch block |
+| test.cpp:246:17:246:31 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:247:8:247:12 | ! ... | This check |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-570/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-570/test.cpp
index 046acab20d4..cedef98a5d8 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-570/test.cpp
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-570/test.cpp
@@ -233,3 +233,54 @@ void test_operator_new_without_exception_spec() {
int* p = new(42, std::nothrow) int; // GOOD
if(p == nullptr) {}
}
+
+namespace std {
+ void *memset(void *s, int c, size_t n);
+}
+
+// from the qhelp:
+namespace qhelp {
+ // BAD: the allocation will throw an unhandled exception
+ // instead of returning a null pointer.
+ void bad1(std::size_t length) noexcept {
+ int* dest = new int[length];
+ if(!dest) {
+ return;
+ }
+ std::memset(dest, 0, length);
+ // ...
+ }
+
+ // BAD: the allocation won't throw an exception, but
+ // instead return a null pointer. [NOT DETECTED]
+ void bad2(std::size_t length) noexcept {
+ try {
+ int* dest = new(std::nothrow) int[length];
+ std::memset(dest, 0, length);
+ // ...
+ } catch(std::bad_alloc&) {
+ // ...
+ }
+ }
+
+ // GOOD: the allocation failure is handled appropriately.
+ void good1(std::size_t length) noexcept {
+ try {
+ int* dest = new int[length];
+ std::memset(dest, 0, length);
+ // ...
+ } catch(std::bad_alloc&) {
+ // ...
+ }
+ }
+
+ // GOOD: the allocation failure is handled appropriately.
+ void good2(std::size_t length) noexcept {
+ int* dest = new(std::nothrow) int[length];
+ if(!dest) {
+ return;
+ }
+ std::memset(dest, 0, length);
+ // ...
+ }
+}
From 7abece46c741cfcb6b2f85e9fa82d9bfa793def2 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 4 Jul 2024 16:33:38 +0100
Subject: [PATCH 03/12] C++: Add a 'good' example for
cpp/unsigned-difference-expression-compared-zero.
---
.../CWE-191/UnsignedDifferenceExpressionComparedZero.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c
index d2f2b76fddc..c19afc017c3 100644
--- a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c
+++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c
@@ -1,5 +1,10 @@
unsigned limit = get_limit();
unsigned total = 0;
-while (limit - total > 0) { // wrong: if `total` is greater than `limit` this will underflow and continue executing the loop.
+
+while (limit - total > 0) { // BAD: if `total` is greater than `limit` this will underflow and continue executing the loop.
total += get_data();
-}
\ No newline at end of file
+}
+
+while (total < limit) { // GOOD: never underflows.
+ total += get_data();
+}
From 1343e4c9aad2554f0db6d03b86047d5fe5c73947 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 4 Jul 2024 16:43:09 +0100
Subject: [PATCH 04/12] C++: Add another 'good' example for
cpp/unsigned-difference-expression-compared-zero.
---
.../CWE-191/UnsignedDifferenceExpressionComparedZero.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c
index c19afc017c3..38ecc79ef2d 100644
--- a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c
+++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c
@@ -1,10 +1,14 @@
-unsigned limit = get_limit();
-unsigned total = 0;
+uint32_t limit = get_limit();
+uint32_t total = 0;
while (limit - total > 0) { // BAD: if `total` is greater than `limit` this will underflow and continue executing the loop.
total += get_data();
}
-while (total < limit) { // GOOD: never underflows.
+while (total < limit) { // GOOD: never underflows here because there is no arithmetic.
+ total += get_data();
+}
+
+while ((int64_t)limit - total > 0) { // GOOD: never underflows here because the result always fits in an `int64_t`.
total += get_data();
}
From 5d898727c069a4d634be12dde8de6f3b8eac5fa4 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 4 Jul 2024 17:00:25 +0100
Subject: [PATCH 05/12] C++: Add the examples to the test.
---
...dDifferenceExpressionComparedZero.expected | 1 +
.../test.cpp | 25 ++++++++++++++++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected
index 85938f15499..64631c12679 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected
@@ -13,3 +13,4 @@
| test.cpp:266:10:266:24 | ... > ... | Unsigned subtraction can never be negative. |
| test.cpp:276:11:276:19 | ... > ... | Unsigned subtraction can never be negative. |
| test.cpp:288:10:288:18 | ... > ... | Unsigned subtraction can never be negative. |
+| test.cpp:312:9:312:25 | ... > ... | Unsigned subtraction can never be negative. |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp
index 1a6aaa618e5..430160165e6 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp
@@ -43,7 +43,7 @@ void test(unsigned x, unsigned y, bool unknown) {
while(cond()) {
if(unknown) { y--; }
}
-
+
if(x - y > 0) { } // GOOD
x = y;
@@ -298,3 +298,26 @@ int test18() {
return (a - b > 0); // GOOD (as b = 0)
}
+
+typedef unsigned int uint32_t;
+typedef long long int64_t;
+uint32_t get_limit();
+uint32_t get_data();
+
+void test19() {
+ // from the doc:
+ uint32_t limit = get_limit();
+ uint32_t total = 0;
+
+ while (limit - total > 0) { // BAD: if `total` is greater than `limit` this will underflow and continue executing the loop.
+ total += get_data();
+ }
+
+ while (total < limit) { // GOOD: never underflows here because there is no arithmetic.
+ total += get_data();
+ }
+
+ while ((int64_t)limit - total > 0) { // GOOD: never underflows here because the result always fits in an `int64_t`.
+ total += get_data();
+ }
+}
From 0288499801ae4864ab9a1561e882c0c6e5298697 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 4 Jul 2024 17:28:29 +0100
Subject: [PATCH 06/12] C++: Rephrase the alert message for
cpp/wrong-type-format-argument to be less prescriptive.
---
.../Format/WrongTypeFormatArguments.ql | 3 +-
.../WrongTypeFormatArguments.expected | 24 ++--
.../WrongTypeFormatArguments.expected | 8 +-
.../WrongTypeFormatArguments.expected | 124 +++++++++---------
.../WrongTypeFormatArguments.expected | 4 +-
.../WrongTypeFormatArguments.expected | 40 +++---
.../WrongTypeFormatArguments.expected | 74 +++++------
.../WrongTypeFormatArguments.expected | 70 +++++-----
8 files changed, 173 insertions(+), 174 deletions(-)
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
index 492315ad8b7..96ee311637b 100644
--- a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
@@ -172,5 +172,4 @@ where
not arg.isFromUninstantiatedTemplate(_) and
not actual.getUnspecifiedType() instanceof ErroneousType
select arg,
- "This argument should be of type '" + expected.getName() + "' but is of type '" +
- actual.getUnspecifiedType().getName() + "'."
+ "This format specifier for type '" + expected.getName() + "' does not match the argument type '" + actual.getUnspecifiedType().getName() + "'."
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/WrongTypeFormatArguments.expected
index 8dfd55c4174..99810e0e55d 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_byte_wprintf/WrongTypeFormatArguments.expected
@@ -1,12 +1,12 @@
-| tests.cpp:18:15:18:22 | Hello | This argument should be of type 'char *' but is of type 'char16_t *'. |
-| tests.cpp:19:15:19:22 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *'. |
-| tests.cpp:21:15:21:21 | Hello | This argument should be of type 'char16_t *' but is of type 'char *'. |
-| tests.cpp:21:15:21:21 | Hello | This argument should be of type 'wchar_t *' but is of type 'char *'. |
-| tests.cpp:26:17:26:24 | Hello | This argument should be of type 'char *' but is of type 'char16_t *'. |
-| tests.cpp:30:17:30:24 | Hello | This argument should be of type 'wchar_t *' but is of type 'char16_t *'. |
-| tests.cpp:35:36:35:43 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *'. |
-| tests.cpp:39:36:39:43 | Hello | This argument should be of type 'char16_t *' but is of type 'wchar_t *'. |
-| tests.cpp:42:37:42:44 | Hello | This argument should be of type 'char *' but is of type 'char16_t *'. |
-| tests.cpp:43:37:43:44 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *'. |
-| tests.cpp:45:37:45:43 | Hello | This argument should be of type 'char16_t *' but is of type 'char *'. |
-| tests.cpp:47:37:47:44 | Hello | This argument should be of type 'char16_t *' but is of type 'wchar_t *'. |
+| tests.cpp:18:15:18:22 | Hello | This format specifier for type 'char *' does not match the argument type 'char16_t *'. |
+| tests.cpp:19:15:19:22 | Hello | This format specifier for type 'char *' does not match the argument type 'wchar_t *'. |
+| tests.cpp:21:15:21:21 | Hello | This format specifier for type 'char16_t *' does not match the argument type 'char *'. |
+| tests.cpp:21:15:21:21 | Hello | This format specifier for type 'wchar_t *' does not match the argument type 'char *'. |
+| tests.cpp:26:17:26:24 | Hello | This format specifier for type 'char *' does not match the argument type 'char16_t *'. |
+| tests.cpp:30:17:30:24 | Hello | This format specifier for type 'wchar_t *' does not match the argument type 'char16_t *'. |
+| tests.cpp:35:36:35:43 | Hello | This format specifier for type 'char *' does not match the argument type 'wchar_t *'. |
+| tests.cpp:39:36:39:43 | Hello | This format specifier for type 'char16_t *' does not match the argument type 'wchar_t *'. |
+| tests.cpp:42:37:42:44 | Hello | This format specifier for type 'char *' does not match the argument type 'char16_t *'. |
+| tests.cpp:43:37:43:44 | Hello | This format specifier for type 'char *' does not match the argument type 'wchar_t *'. |
+| tests.cpp:45:37:45:43 | Hello | This format specifier for type 'char16_t *' does not match the argument type 'char *'. |
+| tests.cpp:47:37:47:44 | Hello | This format specifier for type 'char16_t *' does not match the argument type 'wchar_t *'. |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_word_size/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_word_size/WrongTypeFormatArguments.expected
index 096e9c9cbae..907b0c1385b 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_word_size/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_mixed_word_size/WrongTypeFormatArguments.expected
@@ -1,4 +1,4 @@
-| tests_32.cpp:14:16:14:23 | void_ptr | This argument should be of type 'long' but is of type 'void *'. |
-| tests_32.cpp:15:15:15:15 | l | This argument should be of type 'void *' but is of type 'long'. |
-| tests_64.cpp:14:16:14:23 | void_ptr | This argument should be of type 'long' but is of type 'void *'. |
-| tests_64.cpp:15:15:15:15 | l | This argument should be of type 'void *' but is of type 'long'. |
+| tests_32.cpp:14:16:14:23 | void_ptr | This format specifier for type 'long' does not match the argument type 'void *'. |
+| tests_32.cpp:15:15:15:15 | l | This format specifier for type 'void *' does not match the argument type 'long'. |
+| tests_64.cpp:14:16:14:23 | void_ptr | This format specifier for type 'long' does not match the argument type 'void *'. |
+| tests_64.cpp:15:15:15:15 | l | This format specifier for type 'void *' does not match the argument type 'long'. |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected
index 8556ab875a4..f3963eff2b0 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected
@@ -1,62 +1,62 @@
-| format.h:16:59:16:61 | str | This argument should be of type 'int' but is of type 'char *'. |
-| format.h:16:64:16:64 | i | This argument should be of type 'double' but is of type 'int'. |
-| format.h:16:67:16:67 | d | This argument should be of type 'char *' but is of type 'double'. |
-| linux.cpp:15:24:15:41 | call to get_template_value | This argument should be of type 'int' but is of type 'long'. |
-| linux_c.c:11:15:11:18 | str3 | This argument should be of type 'char *' but is of type 'short *'. |
-| pri_macros.h:15:35:15:40 | my_u64 | This argument should be of type 'unsigned int' but is of type 'unsigned long long'. |
-| printf1.h:12:27:12:27 | i | This argument should be of type 'double' but is of type 'int'. |
-| printf1.h:18:18:18:18 | i | This argument should be of type 'void *' but is of type 'int'. |
-| printf1.h:25:22:25:22 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:27:19:27:20 | cs | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:38:18:38:30 | MYONETHOUSAND | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:44:18:44:20 | ull | This argument should be of type 'int' but is of type 'unsigned long long'. |
-| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long'. |
-| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long'. |
-| printf1.h:113:17:113:17 | d | This argument should be of type 'long double' but is of type 'double'. |
-| printf1.h:114:18:114:18 | d | This argument should be of type 'long double' but is of type 'double'. |
-| printf1.h:147:19:147:19 | i | This argument should be of type 'long long' but is of type 'int'. |
-| printf1.h:148:19:148:20 | ui | This argument should be of type 'unsigned long long' but is of type 'unsigned int'. |
-| printf1.h:160:18:160:18 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:161:21:161:21 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:167:17:167:17 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:168:18:168:18 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:169:19:169:19 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:174:17:174:17 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:175:18:175:18 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:176:19:176:19 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:180:17:180:17 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:181:20:181:20 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:183:18:183:18 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:184:21:184:21 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:186:19:186:19 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:187:22:187:22 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:189:19:189:19 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:190:22:190:22 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:192:19:192:19 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:193:22:193:22 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:194:25:194:25 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:198:24:198:24 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:199:21:199:21 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:202:26:202:26 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:203:23:203:23 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:206:25:206:25 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:207:22:207:22 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:210:26:210:26 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:211:23:211:23 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:214:28:214:28 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:215:28:215:28 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:216:25:216:25 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:221:18:221:18 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:222:20:222:20 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:225:23:225:23 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:228:24:228:24 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:231:25:231:25 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:234:25:234:25 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:235:22:235:22 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:276:32:276:32 | s | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:278:17:278:17 | s | This argument should be of type 'int' but is of type 'char *'. |
-| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *'. |
-| real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *'. |
-| real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *'. |
-| real_world.h:64:22:64:24 | & ... | This argument should be of type 'short *' but is of type 'signed int *'. |
-| wide_string.h:25:18:25:20 | c | This argument should be of type 'char' but is of type 'char *'. |
+| format.h:16:59:16:61 | str | This format specifier for type 'int' does not match the argument type 'char *'. |
+| format.h:16:64:16:64 | i | This format specifier for type 'double' does not match the argument type 'int'. |
+| format.h:16:67:16:67 | d | This format specifier for type 'char *' does not match the argument type 'double'. |
+| linux.cpp:15:24:15:41 | call to get_template_value | This format specifier for type 'int' does not match the argument type 'long'. |
+| linux_c.c:11:15:11:18 | str3 | This format specifier for type 'char *' does not match the argument type 'short *'. |
+| pri_macros.h:15:35:15:40 | my_u64 | This format specifier for type 'unsigned int' does not match the argument type 'unsigned long long'. |
+| printf1.h:12:27:12:27 | i | This format specifier for type 'double' does not match the argument type 'int'. |
+| printf1.h:18:18:18:18 | i | This format specifier for type 'void *' does not match the argument type 'int'. |
+| printf1.h:25:22:25:22 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:27:19:27:20 | cs | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:38:18:38:30 | MYONETHOUSAND | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:44:18:44:20 | ull | This format specifier for type 'int' does not match the argument type 'unsigned long long'. |
+| printf1.h:45:18:45:20 | ull | This format specifier for type 'unsigned int' does not match the argument type 'unsigned long long'. |
+| printf1.h:46:18:46:20 | ull | This format specifier for type 'unsigned int' does not match the argument type 'unsigned long long'. |
+| printf1.h:113:17:113:17 | d | This format specifier for type 'long double' does not match the argument type 'double'. |
+| printf1.h:114:18:114:18 | d | This format specifier for type 'long double' does not match the argument type 'double'. |
+| printf1.h:147:19:147:19 | i | This format specifier for type 'long long' does not match the argument type 'int'. |
+| printf1.h:148:19:148:20 | ui | This format specifier for type 'unsigned long long' does not match the argument type 'unsigned int'. |
+| printf1.h:160:18:160:18 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:161:21:161:21 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:167:17:167:17 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:168:18:168:18 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:169:19:169:19 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:174:17:174:17 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:175:18:175:18 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:176:19:176:19 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:180:17:180:17 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:181:20:181:20 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:183:18:183:18 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:184:21:184:21 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:186:19:186:19 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:187:22:187:22 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:189:19:189:19 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:190:22:190:22 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:192:19:192:19 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:193:22:193:22 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:194:25:194:25 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:198:24:198:24 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:199:21:199:21 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:202:26:202:26 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:203:23:203:23 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:206:25:206:25 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:207:22:207:22 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:210:26:210:26 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:211:23:211:23 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:214:28:214:28 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:215:28:215:28 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:216:25:216:25 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:221:18:221:18 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:222:20:222:20 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:225:23:225:23 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:228:24:228:24 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:231:25:231:25 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:234:25:234:25 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:235:22:235:22 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:276:32:276:32 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:278:17:278:17 | s | This format specifier for type 'int' does not match the argument type 'char *'. |
+| real_world.h:61:21:61:22 | & ... | This format specifier for type 'int *' does not match the argument type 'short *'. |
+| real_world.h:62:22:62:23 | & ... | This format specifier for type 'short *' does not match the argument type 'int *'. |
+| real_world.h:63:22:63:24 | & ... | This format specifier for type 'short *' does not match the argument type 'unsigned int *'. |
+| real_world.h:64:22:64:24 | & ... | This format specifier for type 'short *' does not match the argument type 'signed int *'. |
+| wide_string.h:25:18:25:20 | c | This format specifier for type 'char' does not match the argument type 'char *'. |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/WrongTypeFormatArguments.expected
index 1a1ff20bd27..0e62df1dd7f 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_two_byte_wprintf/WrongTypeFormatArguments.expected
@@ -1,2 +1,2 @@
-| printf.cpp:43:29:43:35 | test | This argument should be of type 'char *' but is of type 'char16_t *'. |
-| printf.cpp:50:29:50:35 | test | This argument should be of type 'char16_t *' but is of type 'wchar_t *'. |
+| printf.cpp:43:29:43:35 | test | This format specifier for type 'char *' does not match the argument type 'char16_t *'. |
+| printf.cpp:50:29:50:35 | test | This format specifier for type 'char16_t *' does not match the argument type 'wchar_t *'. |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected
index de24649beb8..45bf793082e 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected
@@ -1,20 +1,20 @@
-| format.h:16:59:16:61 | str | This argument should be of type 'int' but is of type 'char *'. |
-| format.h:16:64:16:64 | i | This argument should be of type 'double' but is of type 'int'. |
-| format.h:16:67:16:67 | d | This argument should be of type 'char *' but is of type 'double'. |
-| pri_macros.h:15:35:15:40 | my_u64 | This argument should be of type 'unsigned int' but is of type 'unsigned long long'. |
-| printf1.h:12:27:12:27 | i | This argument should be of type 'double' but is of type 'int'. |
-| printf1.h:18:18:18:18 | i | This argument should be of type 'void *' but is of type 'int'. |
-| printf1.h:25:22:25:22 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:27:19:27:20 | cs | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:38:18:38:30 | MYONETHOUSAND | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:44:18:44:20 | ull | This argument should be of type 'int' but is of type 'unsigned long long'. |
-| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long'. |
-| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long'. |
-| printf1.h:130:18:130:18 | 0 | This argument should be of type 'void *' but is of type 'int'. |
-| printf1.h:168:19:168:19 | i | This argument should be of type 'long long' but is of type 'int'. |
-| printf1.h:169:19:169:20 | ui | This argument should be of type 'unsigned long long' but is of type 'unsigned int'. |
-| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *'. |
-| real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *'. |
-| real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *'. |
-| real_world.h:64:22:64:24 | & ... | This argument should be of type 'short *' but is of type 'signed int *'. |
-| wide_string.h:25:18:25:20 | c | This argument should be of type 'char' but is of type 'char *'. |
+| format.h:16:59:16:61 | str | This format specifier for type 'int' does not match the argument type 'char *'. |
+| format.h:16:64:16:64 | i | This format specifier for type 'double' does not match the argument type 'int'. |
+| format.h:16:67:16:67 | d | This format specifier for type 'char *' does not match the argument type 'double'. |
+| pri_macros.h:15:35:15:40 | my_u64 | This format specifier for type 'unsigned int' does not match the argument type 'unsigned long long'. |
+| printf1.h:12:27:12:27 | i | This format specifier for type 'double' does not match the argument type 'int'. |
+| printf1.h:18:18:18:18 | i | This format specifier for type 'void *' does not match the argument type 'int'. |
+| printf1.h:25:22:25:22 | i | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:27:19:27:20 | cs | This format specifier for type 'int' does not match the argument type 'char *'. |
+| printf1.h:38:18:38:30 | MYONETHOUSAND | This format specifier for type 'char *' does not match the argument type 'int'. |
+| printf1.h:44:18:44:20 | ull | This format specifier for type 'int' does not match the argument type 'unsigned long long'. |
+| printf1.h:45:18:45:20 | ull | This format specifier for type 'unsigned int' does not match the argument type 'unsigned long long'. |
+| printf1.h:46:18:46:20 | ull | This format specifier for type 'unsigned int' does not match the argument type 'unsigned long long'. |
+| printf1.h:130:18:130:18 | 0 | This format specifier for type 'void *' does not match the argument type 'int'. |
+| printf1.h:168:19:168:19 | i | This format specifier for type 'long long' does not match the argument type 'int'. |
+| printf1.h:169:19:169:20 | ui | This format specifier for type 'unsigned long long' does not match the argument type 'unsigned int'. |
+| real_world.h:61:21:61:22 | & ... | This format specifier for type 'int *' does not match the argument type 'short *'. |
+| real_world.h:62:22:62:23 | & ... | This format specifier for type 'short *' does not match the argument type 'int *'. |
+| real_world.h:63:22:63:24 | & ... | This format specifier for type 'short *' does not match the argument type 'unsigned int *'. |
+| real_world.h:64:22:64:24 | & ... | This format specifier for type 'short *' does not match the argument type 'signed int *'. |
+| wide_string.h:25:18:25:20 | c | This format specifier for type 'char' does not match the argument type 'char *'. |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected
index 8e2cdb7845a..8a05434fde6 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected
@@ -1,37 +1,37 @@
-| format.h:16:59:16:61 | str | This argument should be of type 'int' but is of type 'char *'. |
-| format.h:16:64:16:64 | i | This argument should be of type 'double' but is of type 'int'. |
-| format.h:16:67:16:67 | d | This argument should be of type 'char *' but is of type 'double'. |
-| pri_macros.h:15:35:15:40 | my_u64 | This argument should be of type 'unsigned int' but is of type 'unsigned long long'. |
-| printf1.h:12:27:12:27 | i | This argument should be of type 'double' but is of type 'int'. |
-| printf1.h:18:18:18:18 | i | This argument should be of type 'void *' but is of type 'int'. |
-| printf1.h:25:22:25:22 | i | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:27:19:27:20 | cs | This argument should be of type 'int' but is of type 'char *'. |
-| printf1.h:38:18:38:30 | MYONETHOUSAND | This argument should be of type 'char *' but is of type 'int'. |
-| printf1.h:44:18:44:20 | ull | This argument should be of type 'int' but is of type 'unsigned long long'. |
-| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long'. |
-| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long'. |
-| printf1.h:71:19:71:20 | st | This argument should be of type 'ssize_t' but is of type 'unsigned long long'. |
-| printf1.h:72:19:72:20 | ST | This argument should be of type 'ssize_t' but is of type 'unsigned long long'. |
-| printf1.h:73:19:73:22 | c_st | This argument should be of type 'ssize_t' but is of type 'unsigned long long'. |
-| printf1.h:74:19:74:22 | C_ST | This argument should be of type 'ssize_t' but is of type 'unsigned long long'. |
-| printf1.h:75:19:75:28 | sizeof( This rule finds return statements that return pointers to an object allocated on the stack.
-The lifetime of a stack allocated memory location only lasts until the function returns, and
-the contents of that memory become undefined after that. Clearly, using a pointer to stack
+ This rule finds return statements that return pointers to an object allocated on the stack.
+The lifetime of a stack allocated memory location only lasts until the function returns, and
+the contents of that memory become undefined after that. Clearly, using a pointer to stack
memory after the function has already returned will have undefined results. Use the functions of the malloc family to dynamically allocate memory on the heap for data that is used across function calls. Use the functions of the malloc family, or new, to dynamically allocate memory on the heap for data that is used across function calls. The following example allocates an object on the stack and returns a pointer to it. This is incorrect because the object is deallocated
+when the function returns, and the pointer becomes invalid. To fix this, allocate the object on the heap using new and return a pointer to the heap-allocated object.
-The first example creates the default configuration file with the usual "default" Unix permissions, 0666. This makes the
+The first example creates the default configuration file with the usual "default" Unix permissions, 0666. This makes the
file world-writable, so that an attacker could write in their own configuration that would be read by the program. The second example uses
more restrictive permissions: a combination of the standard Unix constants S_IWUSR and S_IRUSR which means that
-only the current user will have read and write access to the file.
+only the current user will have read and write access to the file. The third example shows another way to create a file with more restrictive
+permissions if a FILE * stream pointer is required rather than a file descriptor.