Skip to content

Commit 40ed471

Browse files
Initial implementation of rule 4-1-1, must be standard C++17
1 parent fd9c1d7 commit 40ed471

File tree

9 files changed

+413
-1
lines changed

9 files changed

+413
-1
lines changed

cpp/common/src/codingstandards/cpp/Extensions.qll

Lines changed: 213 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,216 @@ abstract class CompilerExtension extends Locatable { }
88
/**
99
* Common base class for modeling compiler extensions in CPP.
1010
*/
11-
abstract class CPPCompilerExtension extends CompilerExtension { }
11+
abstract class CPPCompilerExtension extends CompilerExtension {
12+
abstract string getMessage();
13+
}
14+
15+
/**
16+
* An `Attribute` that may be a `GnuAttribute` or `Declspec`, or `MicrosoftAttribute`, etc.
17+
*
18+
* There are language extensions such as GNU `__attribute__`, Microsoft `__declspec` or
19+
* `[attribute]` syntax.
20+
*/
21+
class CPPAttributeExtension extends CPPCompilerExtension, Attribute {
22+
CPPAttributeExtension() { not this instanceof StdAttribute and not this instanceof AlignAs }
23+
24+
override string getMessage() {
25+
result =
26+
"Use of attribute '" + getName() +
27+
"' is a compiler extension and is not portable to other compilers."
28+
}
29+
}
30+
31+
/**
32+
* An `Attribute` within a compiler specific namespace such as `[[gnu::weak]]`.
33+
*/
34+
class CppNamespacedStdAttributeExtension extends CPPCompilerExtension, StdAttribute {
35+
CppNamespacedStdAttributeExtension() { exists(this.getNamespace()) and not getNamespace() = "" }
36+
37+
override string getMessage() {
38+
result =
39+
"Use of attribute '" + getName() + "' in namespace '" + getNamespace() +
40+
"' is a compiler extension and is not portable to other compilers."
41+
}
42+
}
43+
44+
class CppUnrecognizedAttributeExtension extends CPPCompilerExtension, StdAttribute {
45+
CppUnrecognizedAttributeExtension() {
46+
not this instanceof CppNamespacedStdAttributeExtension and
47+
not getName() in [
48+
"maybe_unused", "nodiscard", "noreturn", "deprecated", "carries_dependency", "fallthrough"
49+
]
50+
}
51+
52+
override string getMessage() {
53+
result = "Use of unrecognized or non-C++17 attribute '" + getName() + "'."
54+
}
55+
}
56+
57+
/**
58+
* Compiler-specific builtin functions.
59+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
60+
*/
61+
class CPPBuiltinFunctionExtension extends CPPCompilerExtension, FunctionCall {
62+
CPPBuiltinFunctionExtension() {
63+
getTarget().getName().indexOf("__builtin_") = 0 or
64+
getTarget().getName().indexOf("__sync_") = 0 or
65+
getTarget().getName().indexOf("__atomic_") = 0
66+
}
67+
68+
override string getMessage() {
69+
result =
70+
"Call to builtin function '" + getTarget().getName() +
71+
"' is a compiler extension and is not portable to other compilers."
72+
}
73+
}
74+
75+
/**
76+
* Statement expressions: ({ ... }) syntax.
77+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
78+
*/
79+
class CPPStmtExprExtension extends CPPCompilerExtension, StmtExpr {
80+
override string getMessage() {
81+
result =
82+
"Statement expressions are a compiler extension and are not portable to other compilers."
83+
}
84+
}
85+
86+
/**
87+
* Ternary expressions with omitted middle operand: x ?: y
88+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html
89+
*/
90+
class CPPTerseTernaryExtension extends CPPCompilerExtension, ConditionalExpr {
91+
CPPTerseTernaryExtension() { getCondition() = getElse() or getCondition() = getThen() }
92+
93+
override string getMessage() {
94+
result =
95+
"Ternaries with omitted middle operands are a compiler extension and are not portable to other compilers."
96+
}
97+
}
98+
99+
/**
100+
* Extended integer types: __int128, etc.
101+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/__int128.html
102+
*/
103+
class CPPExtendedIntegerTypeExtension extends CPPCompilerExtension, DeclarationEntry {
104+
CPPExtendedIntegerTypeExtension() { getType() instanceof Int128Type }
105+
106+
override string getMessage() {
107+
result = "128-bit integers are a compiler extension and are not portable to other compilers."
108+
}
109+
}
110+
111+
/**
112+
* Extended floating-point types: __float128, _Decimal32, etc.
113+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Decimal-Float.html
114+
*/
115+
class CPPExtendedFloatTypeExtension extends CPPCompilerExtension, DeclarationEntry {
116+
CPPExtendedFloatTypeExtension() {
117+
getType() instanceof Decimal128Type or
118+
getType() instanceof Decimal32Type or
119+
getType() instanceof Decimal64Type or
120+
getType() instanceof Float128Type
121+
}
122+
123+
override string getMessage() {
124+
result =
125+
"Extended floating-point types are a compiler extension and are not portable to other compilers."
126+
}
127+
}
128+
129+
/**
130+
* Zero-length arrays (flexible array members must be last).
131+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
132+
*/
133+
class CPPZeroLengthArraysExtension extends CPPCompilerExtension, DeclarationEntry {
134+
CPPZeroLengthArraysExtension() { getType().(ArrayType).getArraySize() = 0 }
135+
136+
override string getMessage() {
137+
result = "Zero length arrays are a compiler extension and are not portable to other compilers."
138+
}
139+
}
140+
141+
/**
142+
* Variable-length arrays in struct members (not C++17 compliant).
143+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
144+
*/
145+
class CPPVariableLengthArraysExtension extends CPPCompilerExtension, Field {
146+
CPPVariableLengthArraysExtension() {
147+
getType() instanceof ArrayType and
148+
not getType().(ArrayType).hasArraySize() and
149+
// Not the final member of the struct, which is allowed in some contexts
150+
not exists(int lastIndex, Class declaringStruct |
151+
declaringStruct = getDeclaringType() and
152+
lastIndex = count(declaringStruct.getACanonicalMember()) - 1 and
153+
this = declaringStruct.getCanonicalMember(lastIndex)
154+
)
155+
}
156+
157+
override string getMessage() {
158+
result =
159+
"Variable length arrays are a compiler extension and are not portable to other compilers."
160+
}
161+
}
162+
163+
/**
164+
* __alignof__ operator (use alignof from C++11 instead).
165+
*/
166+
class CPPAlignofExtension extends CPPCompilerExtension, AlignofExprOperator {
167+
CPPAlignofExtension() { exists(getValueText().indexOf("__alignof__")) }
168+
169+
override string getMessage() {
170+
result = "'__alignof__' is a compiler extension and is not portable to other compilers."
171+
}
172+
}
173+
174+
/**
175+
* Preprocessor extensions for feature detection.
176+
* Reference: https://clang.llvm.org/docs/LanguageExtensions.html
177+
*/
178+
class CPPConditionalDefineExtension extends CPPCompilerExtension, PreprocessorIfdef {
179+
string feature;
180+
181+
CPPConditionalDefineExtension() {
182+
feature =
183+
[
184+
"__has_builtin", "__has_constexpr_builtin", "__has_feature", "__has_extension",
185+
"__has_attribute", "__has_declspec_attribute", "__is_identifier", "__has_include",
186+
"__has_include_next", "__has_warning", "__has_cpp_attribute"
187+
] and
188+
exists(toString().indexOf(feature))
189+
}
190+
191+
override string getMessage() {
192+
result =
193+
"Call to builtin preprocessor feature '" + feature +
194+
"' is a compiler extension and is not portable to other compilers."
195+
}
196+
}
197+
198+
class CPPPreprocessorDirectiveExtension extends CPPCompilerExtension, PreprocessorDirective {
199+
string kind;
200+
201+
CPPPreprocessorDirectiveExtension() {
202+
this instanceof PreprocessorPragma and kind = "#pragma " + getHead()
203+
or
204+
this instanceof PreprocessorError and kind = "#error"
205+
or
206+
this instanceof PreprocessorWarning and kind = "#warning"
207+
}
208+
209+
override string getMessage() {
210+
result = "Use of non-standard preprocessor directive '" + kind + "' is a compiler extension."
211+
}
212+
}
213+
214+
/**
215+
* Built-in type traits and operations such as `__is_abstract`, `__is_same`, etc.
216+
*
217+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
218+
*/
219+
class CPPBuiltinOperationExtension extends CPPCompilerExtension, BuiltInOperation {
220+
override string getMessage() {
221+
result = "Use of built-in operation '" + toString() + "' is a compiler extension."
222+
}
223+
}

cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ import Statements
9292
import Strings
9393
import Templates
9494
import Toolchain
95+
import Toolchain2
9596
import Toolchain3
9697
import Trigraph
9798
import TrustBoundaries
@@ -191,6 +192,7 @@ newtype TCPPQuery =
191192
TStringsPackageQuery(StringsQuery q) or
192193
TTemplatesPackageQuery(TemplatesQuery q) or
193194
TToolchainPackageQuery(ToolchainQuery q) or
195+
TToolchain2PackageQuery(Toolchain2Query q) or
194196
TToolchain3PackageQuery(Toolchain3Query q) or
195197
TTrigraphPackageQuery(TrigraphQuery q) or
196198
TTrustBoundariesPackageQuery(TrustBoundariesQuery q) or
@@ -290,6 +292,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
290292
isStringsQueryMetadata(query, queryId, ruleId, category) or
291293
isTemplatesQueryMetadata(query, queryId, ruleId, category) or
292294
isToolchainQueryMetadata(query, queryId, ruleId, category) or
295+
isToolchain2QueryMetadata(query, queryId, ruleId, category) or
293296
isToolchain3QueryMetadata(query, queryId, ruleId, category) or
294297
isTrigraphQueryMetadata(query, queryId, ruleId, category) or
295298
isTrustBoundariesQueryMetadata(query, queryId, ruleId, category) or
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype Toolchain2Query = TCompilerLanguageExtensionsUsedQuery()
7+
8+
predicate isToolchain2QueryMetadata(Query query, string queryId, string ruleId, string category) {
9+
query =
10+
// `Query` instance for the `compilerLanguageExtensionsUsed` query
11+
Toolchain2Package::compilerLanguageExtensionsUsedQuery() and
12+
queryId =
13+
// `@id` for the `compilerLanguageExtensionsUsed` query
14+
"cpp/misra/compiler-language-extensions-used" and
15+
ruleId = "RULE-4-1-1" and
16+
category = "required"
17+
}
18+
19+
module Toolchain2Package {
20+
Query compilerLanguageExtensionsUsedQuery() {
21+
//autogenerate `Query` type
22+
result =
23+
// `Query` type for `compilerLanguageExtensionsUsed` query
24+
TQueryCPP(TToolchain2PackageQuery(TCompilerLanguageExtensionsUsedQuery()))
25+
}
26+
}

cpp/common/test/includes/standard-library/type_traits.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ template <typename T, unsigned int N> struct remove_extent<T[N]> {
6262
typedef T type;
6363
};
6464

65+
template <typename T> struct is_abstract {
66+
const static bool value = false;
67+
constexpr operator bool() { return value; }
68+
};
69+
70+
template <typename T> bool is_abstract_v = is_abstract<T>::value;
71+
72+
template <typename T, typename U> struct is_same {
73+
const static bool value = false;
74+
constexpr operator bool() { return value; }
75+
};
76+
77+
template <typename T, typename U> bool is_same_v = is_same<T, U>::value;
78+
6579
template <class T> struct is_trivially_copy_constructible {
6680
const static bool value = true;
6781
constexpr operator bool() { return value; }
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @id cpp/misra/compiler-language-extensions-used
3+
* @name RULE-4-1-1: A program shall conform to ISO/IEC 14882:2017 (C++17)
4+
* @description Language extensions are compiler-specific features that are not part of the C++17
5+
* standard. Using these extensions reduces portability and may lead to unpredictable
6+
* behavior when code is compiled with different compilers or compiler versions.
7+
* @kind problem
8+
* @precision high
9+
* @problem.severity error
10+
* @tags external/misra/id/rule-4-1-1
11+
* scope/system
12+
* maintainability
13+
* portability
14+
* external/misra/enforcement/undecidable
15+
* external/misra/obligation/required
16+
*/
17+
18+
import cpp
19+
import codingstandards.cpp.misra
20+
import codingstandards.cpp.Extensions
21+
import codingstandards.cpp.AlertReporting
22+
23+
from CPPCompilerExtension e
24+
where not isExcluded(e, Toolchain2Package::compilerLanguageExtensionsUsedQuery())
25+
select MacroUnwrapper<CPPCompilerExtension>::unwrapElement(e), e.getMessage()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
| file:///Users/michaelrfairhurst/projects/codeql-coding-standards/cpp/common/test/includes/standard-library/stdarg.h:5:1:5:47 | #define va_start(v,l) __builtin_va_start(v, l) | Use of built-in operation '__builtin_va_start' is a compiler extension. |
2+
| test.cpp:11:3:11:19 | maybe_unused | Use of attribute 'maybe_unused' in namespace 'gnu' is a compiler extension and is not portable to other compilers. |
3+
| test.cpp:12:16:12:22 | aligned | Use of attribute 'aligned' is a compiler extension and is not portable to other compilers. |
4+
| test.cpp:13:16:13:21 | unused | Use of attribute 'unused' is a compiler extension and is not portable to other compilers. |
5+
| test.cpp:14:21:14:28 | noreturn | Use of attribute 'noreturn' is a compiler extension and is not portable to other compilers. |
6+
| test.cpp:15:3:15:17 | deprecated | Use of attribute 'deprecated' in namespace 'gnu' is a compiler extension and is not portable to other compilers. |
7+
| test.cpp:16:3:16:23 | nonstandard_attribute | Use of unrecognized or non-C++17 attribute 'nonstandard_attribute'. |
8+
| test.cpp:19:3:19:20 | call to __builtin_popcount | Call to builtin function '__builtin_popcount' is a compiler extension and is not portable to other compilers. |
9+
| test.cpp:20:3:20:18 | call to __builtin_expect | Call to builtin function '__builtin_expect' is a compiler extension and is not portable to other compilers. |
10+
| test.cpp:21:3:21:22 | call to __sync_fetch_and_add_4 | Call to builtin function '__sync_fetch_and_add_4' is a compiler extension and is not portable to other compilers. |
11+
| test.cpp:23:3:23:20 | __is_abstract | Use of built-in operation '__is_abstract' is a compiler extension. |
12+
| test.cpp:24:3:24:22 | __is_same | Use of built-in operation '__is_same' is a compiler extension. |
13+
| test.cpp:30:3:33:4 | (statement expression) | Statement expressions are a compiler extension and are not portable to other compilers. |
14+
| test.cpp:34:3:34:12 | ... ? ... : ... | Ternaries with omitted middle operands are a compiler extension and are not portable to other compilers. |
15+
| test.cpp:36:12:36:13 | definition of l0 | 128-bit integers are a compiler extension and are not portable to other compilers. |
16+
| test.cpp:45:20:45:30 | fallthrough | Use of attribute 'fallthrough' is a compiler extension and is not portable to other compilers. |
17+
| test.cpp:47:7:47:22 | fallthrough | Use of attribute 'fallthrough' in namespace 'gnu' is a compiler extension and is not portable to other compilers. |
18+
| test.cpp:55:3:55:29 | __builtin_va_start | Use of built-in operation '__builtin_va_start' is a compiler extension. |
19+
| test.cpp:60:7:60:8 | definition of m1 | Zero length arrays are a compiler extension and are not portable to other compilers. |
20+
| test.cpp:64:31:64:41 | vector_size | Use of attribute 'vector_size' is a compiler extension and is not portable to other compilers. |
21+
| test.cpp:66:1:66:20 | #ifdef __has_builtin | Call to builtin preprocessor feature '__has_builtin' is a compiler extension and is not portable to other compilers. |
22+
| test.cpp:72:1:72:12 | #pragma once | Use of non-standard preprocessor directive '#pragma once' is a compiler extension. |
23+
| test.cpp:73:1:73:27 | #pragma GCC diagnostic push | Use of non-standard preprocessor directive '#pragma GCC diagnostic push' is a compiler extension. |
24+
| test.cpp:74:1:74:28 | #warning "This is a warning" | Use of non-standard preprocessor directive '#warning' is a compiler extension. |
25+
| test.cpp:76:1:76:41 | #warning "preceeding spaces is common" | Use of non-standard preprocessor directive '#warning' is a compiler extension. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-4-1-1/CompilerLanguageExtensionsUsed.ql

0 commit comments

Comments
 (0)