Skip to content

Commit ffed467

Browse files
committed
Rule 21.10.1: NoVariadicFunctionMacros.ql
A query for reporting the use of variadic functions. [a]
1 parent 58e43ad commit ffed467

File tree

4 files changed

+143
-0
lines changed

4 files changed

+143
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @id cpp/misra/no-variadic-function-macros
3+
* @name RULE-21-10-1: The features of <cstdarg> shall not be used
4+
* @description Using <cstdarg> features like va_list, va_arg, va_start, va_end and va_copy bypasses
5+
* compiler type checking and leads to undefined behavior when used incorrectly.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-21-10-1
10+
* scope/single-translation-unit
11+
* external/misra/enforcement/decidable
12+
* external/misra/obligation/required
13+
*/
14+
15+
import cpp
16+
import codingstandards.cpp.misra
17+
18+
class VaListType extends Type {
19+
VaListType() {
20+
this.getName() = "va_list" or
21+
this.getName() = "__va_list_tag" or
22+
this.(SpecifiedType).getBaseType() instanceof VaListType or
23+
this.(TypedefType).getBaseType() instanceof VaListType
24+
}
25+
}
26+
27+
from Element element, string message
28+
where
29+
not isExcluded(element, BannedAPIsPackage::noVariadicFunctionMacrosQuery()) and
30+
(
31+
element.(Variable).getType() instanceof VaListType and
32+
message = "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'."
33+
or
34+
element.(Parameter).getType() instanceof VaListType and
35+
message = "Declaration of parameter '" + element.(Parameter).getName() + "' of type 'va_list'."
36+
or
37+
element instanceof BuiltInVarArgsStart and
38+
message = "Call to 'va_start'."
39+
or
40+
element instanceof BuiltInVarArgsEnd and
41+
message = "Call to 'va_end'."
42+
or
43+
element instanceof BuiltInVarArg and
44+
message = "Call to 'va_arg'."
45+
or
46+
element instanceof BuiltInVarArgCopy and
47+
message = "Call to 'va_copy'."
48+
or
49+
element.(TypedefType).getBaseType() instanceof VaListType and
50+
message =
51+
"Declaration of typedef '" + element.(TypedefType).getName() + "' aliasing 'va_list' type."
52+
)
53+
select element, message
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
| test.cpp:5:11:5:12 | l1 | Declaration of variable 'l1' of type 'va_list'. |
2+
| test.cpp:9:11:9:12 | l2 | Declaration of variable 'l2' of type 'va_list'. |
3+
| test.cpp:10:3:10:18 | __builtin_va_start | Call to 'va_start'. |
4+
| test.cpp:11:3:11:12 | __builtin_va_end | Call to 'va_end'. |
5+
| test.cpp:15:11:15:12 | l2 | Declaration of variable 'l2' of type 'va_list'. |
6+
| test.cpp:16:3:16:18 | __builtin_va_start | Call to 'va_start'. |
7+
| test.cpp:17:21:17:44 | __builtin_va_arg | Call to 'va_arg'. |
8+
| test.cpp:18:3:18:12 | __builtin_va_end | Call to 'va_end'. |
9+
| test.cpp:22:11:22:12 | l2 | Declaration of variable 'l2' of type 'va_list'. |
10+
| test.cpp:23:3:23:18 | __builtin_va_start | Call to 'va_start'. |
11+
| test.cpp:24:3:24:12 | __builtin_va_end | Call to 'va_end'. |
12+
| test.cpp:28:11:28:12 | l2 | Declaration of variable 'l2' of type 'va_list'. |
13+
| test.cpp:28:15:28:16 | l3 | Declaration of variable 'l3' of type 'va_list'. |
14+
| test.cpp:29:3:29:18 | __builtin_va_start | Call to 'va_start'. |
15+
| test.cpp:30:3:30:17 | __builtin_va_copy | Call to 'va_copy'. |
16+
| test.cpp:31:3:31:12 | __builtin_va_end | Call to 'va_end'. |
17+
| test.cpp:32:3:32:12 | __builtin_va_end | Call to 'va_end'. |
18+
| test.cpp:35:37:35:38 | l1 | Declaration of parameter 'l1' of type 'va_list'. |
19+
| test.cpp:35:37:35:38 | l1 | Declaration of variable 'l1' of type 'va_list'. |
20+
| test.cpp:36:15:36:32 | __builtin_va_arg | Call to 'va_arg'. |
21+
| test.cpp:40:11:40:12 | l2 | Declaration of variable 'l2' of type 'va_list'. |
22+
| test.cpp:41:3:41:18 | __builtin_va_start | Call to 'va_start'. |
23+
| test.cpp:42:21:42:44 | __builtin_va_arg | Call to 'va_arg'. |
24+
| test.cpp:43:15:43:32 | __builtin_va_arg | Call to 'va_arg'. |
25+
| test.cpp:44:3:44:12 | __builtin_va_end | Call to 'va_end'. |
26+
| test.cpp:55:17:55:29 | va_list_alias | Declaration of typedef 'va_list_alias' aliasing 'va_list' type. |
27+
| test.cpp:56:17:56:25 | SOME_TYPE | Declaration of typedef 'SOME_TYPE' aliasing 'va_list' type. |
28+
| test.cpp:58:17:58:18 | l1 | Declaration of variable 'l1' of type 'va_list'. |
29+
| test.cpp:59:13:59:14 | l2 | Declaration of variable 'l2' of type 'va_list'. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-21-10-1/NoVariadicFunctionMacros.ql
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include <cstdarg>
2+
#include <cstdint>
3+
4+
void test_va_list_declaration() {
5+
va_list l1; // NON_COMPLIANT
6+
}
7+
8+
void test_va_start_usage(std::int32_t l1, ...) {
9+
va_list l2; // NON_COMPLIANT
10+
va_start(l2, l1); // NON_COMPLIANT
11+
va_end(l2); // NON_COMPLIANT
12+
}
13+
14+
void test_va_arg_usage(std::int32_t l1, ...) {
15+
va_list l2; // NON_COMPLIANT
16+
va_start(l2, l1); // NON_COMPLIANT
17+
std::int32_t l3 = va_arg(l2, std::int32_t); // NON_COMPLIANT
18+
va_end(l2); // NON_COMPLIANT
19+
}
20+
21+
void test_va_end_usage(std::int32_t l1, ...) {
22+
va_list l2; // NON_COMPLIANT
23+
va_start(l2, l1); // NON_COMPLIANT
24+
va_end(l2); // NON_COMPLIANT
25+
}
26+
27+
void test_va_copy_usage(std::int32_t l1, ...) {
28+
va_list l2, l3; // NON_COMPLIANT
29+
va_start(l2, l1); // NON_COMPLIANT
30+
va_copy(l3, l2); // NON_COMPLIANT
31+
va_end(l3); // NON_COMPLIANT
32+
va_end(l2); // NON_COMPLIANT
33+
}
34+
35+
void test_va_list_parameter(va_list l1) { // NON_COMPLIANT
36+
double l2 = va_arg(l1, double); // NON_COMPLIANT
37+
}
38+
39+
void test_multiple_va_arg_calls(std::int32_t l1, ...) {
40+
va_list l2; // NON_COMPLIANT
41+
va_start(l2, l1); // NON_COMPLIANT
42+
std::int32_t l3 = va_arg(l2, std::int32_t); // NON_COMPLIANT
43+
double l4 = va_arg(l2, double); // NON_COMPLIANT
44+
va_end(l2); // NON_COMPLIANT
45+
}
46+
47+
void test_variadic_function_declaration(std::int16_t l1, ...) {
48+
// Function declaration with ellipsis is compliant
49+
}
50+
51+
void test_variadic_function_call() {
52+
test_variadic_function_declaration(1, 2.0, 3.0); // COMPLIANT
53+
}
54+
55+
typedef va_list va_list_alias; // NON_COMPLIANT
56+
typedef va_list SOME_TYPE; // NON_COMPLIANT
57+
void test_va_list_alias() {
58+
va_list_alias l1; // NON_COMPLIANT
59+
SOME_TYPE l2; // NON_COMPLIANT
60+
}

0 commit comments

Comments
 (0)