Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 213 additions & 1 deletion cpp/common/src/codingstandards/cpp/Extensions.qll
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,216 @@ abstract class CompilerExtension extends Locatable { }
/**
* Common base class for modeling compiler extensions in CPP.
*/
abstract class CPPCompilerExtension extends CompilerExtension { }
abstract class CPPCompilerExtension extends CompilerExtension {
abstract string getMessage();
}

/**
* An `Attribute` that may be a `GnuAttribute` or `Declspec`, or `MicrosoftAttribute`, etc.
*
* There are language extensions such as GNU `__attribute__`, Microsoft `__declspec` or
* `[attribute]` syntax.
*/
class CPPAttributeExtension extends CPPCompilerExtension, Attribute {
CPPAttributeExtension() { not this instanceof StdAttribute and not this instanceof AlignAs }

override string getMessage() {
result =
"Use of attribute '" + getName() +
"' is a compiler extension and is not portable to other compilers."
}
}

/**
* An `Attribute` within a compiler specific namespace such as `[[gnu::weak]]`.
*/
class CppNamespacedStdAttributeExtension extends CPPCompilerExtension, StdAttribute {
CppNamespacedStdAttributeExtension() { exists(this.getNamespace()) and not getNamespace() = "" }

override string getMessage() {
result =
"Use of attribute '" + getName() + "' in namespace '" + getNamespace() +
"' is a compiler extension and is not portable to other compilers."
}
}

class CppUnrecognizedAttributeExtension extends CPPCompilerExtension, StdAttribute {
CppUnrecognizedAttributeExtension() {
Comment thread
MichaelRFairhurst marked this conversation as resolved.
Outdated
not this instanceof CppNamespacedStdAttributeExtension and
not getName() in [
"maybe_unused", "nodiscard", "noreturn", "deprecated", "carries_dependency", "fallthrough"
]
}
Comment thread
MichaelRFairhurst marked this conversation as resolved.
Outdated

override string getMessage() {
result = "Use of unrecognized or non-C++17 attribute '" + getName() + "'."
}
}

/**
* Compiler-specific builtin functions.
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
*/
class CPPBuiltinFunctionExtension extends CPPCompilerExtension, FunctionCall {
CPPBuiltinFunctionExtension() {
getTarget().getName().indexOf("__builtin_") = 0 or
getTarget().getName().indexOf("__sync_") = 0 or
getTarget().getName().indexOf("__atomic_") = 0
}

override string getMessage() {
result =
"Call to builtin function '" + getTarget().getName() +
"' is a compiler extension and is not portable to other compilers."
}
}

/**
* Statement expressions: ({ ... }) syntax.
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
*/
class CPPStmtExprExtension extends CPPCompilerExtension, StmtExpr {
override string getMessage() {
result =
"Statement expressions are a compiler extension and are not portable to other compilers."
}
}

/**
* Ternary expressions with omitted middle operand: x ?: y
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html
*/
class CPPTerseTernaryExtension extends CPPCompilerExtension, ConditionalExpr {
CPPTerseTernaryExtension() { getCondition() = getElse() or getCondition() = getThen() }

override string getMessage() {
result =
"Ternaries with omitted middle operands are a compiler extension and are not portable to other compilers."
}
Comment thread
mbaluda marked this conversation as resolved.
}

/**
* Extended integer types: __int128, etc.
* Reference: https://gcc.gnu.org/onlinedocs/gcc/__int128.html
*/
class CPPExtendedIntegerTypeExtension extends CPPCompilerExtension, DeclarationEntry {
CPPExtendedIntegerTypeExtension() { getType() instanceof Int128Type }

override string getMessage() {
result = "128-bit integers are a compiler extension and are not portable to other compilers."
}
}

/**
* Extended floating-point types: __float128, _Decimal32, etc.
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Decimal-Float.html
*/
class CPPExtendedFloatTypeExtension extends CPPCompilerExtension, DeclarationEntry {
CPPExtendedFloatTypeExtension() {
getType() instanceof Decimal128Type or
getType() instanceof Decimal32Type or
getType() instanceof Decimal64Type or
getType() instanceof Float128Type
}

override string getMessage() {
result =
"Extended floating-point types are a compiler extension and are not portable to other compilers."
}
}

/**
* Zero-length arrays (flexible array members must be last).
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
*/
class CPPZeroLengthArraysExtension extends CPPCompilerExtension, DeclarationEntry {
CPPZeroLengthArraysExtension() { getType().(ArrayType).getArraySize() = 0 }

override string getMessage() {
result = "Zero length arrays are a compiler extension and are not portable to other compilers."
}
}

/**
* Variable-length arrays in struct members (not C++17 compliant).
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
*/
class CPPVariableLengthArraysExtension extends CPPCompilerExtension, Field {
CPPVariableLengthArraysExtension() {
getType() instanceof ArrayType and
not getType().(ArrayType).hasArraySize() and
// Not the final member of the struct, which is allowed in some contexts
not exists(int lastIndex, Class declaringStruct |
declaringStruct = getDeclaringType() and
lastIndex = count(declaringStruct.getACanonicalMember()) - 1 and
this = declaringStruct.getCanonicalMember(lastIndex)
)
}

override string getMessage() {
result =
"Variable length arrays are a compiler extension and are not portable to other compilers."
}
}

/**
* __alignof__ operator (use alignof from C++11 instead).
*/
class CPPAlignofExtension extends CPPCompilerExtension, AlignofExprOperator {
CPPAlignofExtension() { exists(getValueText().indexOf("__alignof__")) }

override string getMessage() {
result = "'__alignof__' is a compiler extension and is not portable to other compilers."
}
}

/**
* Preprocessor extensions for feature detection.
* Reference: https://clang.llvm.org/docs/LanguageExtensions.html
*/
class CPPConditionalDefineExtension extends CPPCompilerExtension, PreprocessorIfdef {
string feature;

CPPConditionalDefineExtension() {
feature =
[
"__has_builtin", "__has_constexpr_builtin", "__has_feature", "__has_extension",
"__has_attribute", "__has_declspec_attribute", "__is_identifier", "__has_include",
"__has_include_next", "__has_warning", "__has_cpp_attribute"
] and
exists(toString().indexOf(feature))
}

override string getMessage() {
result =
"Call to builtin preprocessor feature '" + feature +
"' is a compiler extension and is not portable to other compilers."
}
}

class CPPPreprocessorDirectiveExtension extends CPPCompilerExtension, PreprocessorDirective {
string kind;

CPPPreprocessorDirectiveExtension() {
this instanceof PreprocessorPragma and kind = "#pragma " + getHead()
or
this instanceof PreprocessorError and kind = "#error"
or
this instanceof PreprocessorWarning and kind = "#warning"
}

override string getMessage() {
result = "Use of non-standard preprocessor directive '" + kind + "' is a compiler extension."
}
}

/**
* Built-in type traits and operations such as `__is_abstract`, `__is_same`, etc.
*
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
*/
class CPPBuiltinOperationExtension extends CPPCompilerExtension, BuiltInOperation {
override string getMessage() {
result = "Use of built-in operation '" + toString() + "' is a compiler extension."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ import Statements
import Strings
import Templates
import Toolchain
import Toolchain2
import Toolchain3
import Trigraph
import TrustBoundaries
Expand Down Expand Up @@ -191,6 +192,7 @@ newtype TCPPQuery =
TStringsPackageQuery(StringsQuery q) or
TTemplatesPackageQuery(TemplatesQuery q) or
TToolchainPackageQuery(ToolchainQuery q) or
TToolchain2PackageQuery(Toolchain2Query q) or
TToolchain3PackageQuery(Toolchain3Query q) or
TTrigraphPackageQuery(TrigraphQuery q) or
TTrustBoundariesPackageQuery(TrustBoundariesQuery q) or
Expand Down Expand Up @@ -290,6 +292,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
isStringsQueryMetadata(query, queryId, ruleId, category) or
isTemplatesQueryMetadata(query, queryId, ruleId, category) or
isToolchainQueryMetadata(query, queryId, ruleId, category) or
isToolchain2QueryMetadata(query, queryId, ruleId, category) or
isToolchain3QueryMetadata(query, queryId, ruleId, category) or
isTrigraphQueryMetadata(query, queryId, ruleId, category) or
isTrustBoundariesQueryMetadata(query, queryId, ruleId, category) or
Expand Down
26 changes: 26 additions & 0 deletions cpp/common/src/codingstandards/cpp/exclusions/cpp/Toolchain2.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
import cpp
import RuleMetadata
import codingstandards.cpp.exclusions.RuleMetadata

newtype Toolchain2Query = TCompilerLanguageExtensionsUsedQuery()

predicate isToolchain2QueryMetadata(Query query, string queryId, string ruleId, string category) {
query =
// `Query` instance for the `compilerLanguageExtensionsUsed` query
Toolchain2Package::compilerLanguageExtensionsUsedQuery() and
queryId =
// `@id` for the `compilerLanguageExtensionsUsed` query
"cpp/misra/compiler-language-extensions-used" and
ruleId = "RULE-4-1-1" and
category = "required"
}

module Toolchain2Package {
Query compilerLanguageExtensionsUsedQuery() {
//autogenerate `Query` type
result =
// `Query` type for `compilerLanguageExtensionsUsed` query
TQueryCPP(TToolchain2PackageQuery(TCompilerLanguageExtensionsUsedQuery()))
}
}
14 changes: 14 additions & 0 deletions cpp/common/test/includes/standard-library/type_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ template <typename T, unsigned int N> struct remove_extent<T[N]> {
typedef T type;
};

template <typename T> struct is_abstract {
const static bool value = false;
constexpr operator bool() { return value; }
};

template <typename T> bool is_abstract_v = is_abstract<T>::value;

template <typename T, typename U> struct is_same {
const static bool value = false;
constexpr operator bool() { return value; }
};

template <typename T, typename U> bool is_same_v = is_same<T, U>::value;
Comment thread
MichaelRFairhurst marked this conversation as resolved.

template <class T> struct is_trivially_copy_constructible {
const static bool value = true;
constexpr operator bool() { return value; }
Expand Down
25 changes: 25 additions & 0 deletions cpp/misra/src/rules/RULE-4-1-1/CompilerLanguageExtensionsUsed.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @id cpp/misra/compiler-language-extensions-used
* @name RULE-4-1-1: A program shall conform to ISO/IEC 14882:2017 (C++17)
* @description Language extensions are compiler-specific features that are not part of the C++17
* standard. Using these extensions reduces portability and may lead to unpredictable
* behavior when code is compiled with different compilers or compiler versions.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/misra/id/rule-4-1-1
* scope/system
* maintainability
* portability
* external/misra/enforcement/undecidable
* external/misra/obligation/required
*/

import cpp
import codingstandards.cpp.misra
import codingstandards.cpp.Extensions
import codingstandards.cpp.AlertReporting

from CPPCompilerExtension e
where not isExcluded(e, Toolchain2Package::compilerLanguageExtensionsUsedQuery())
select MacroUnwrapper<CPPCompilerExtension>::unwrapElement(e), e.getMessage()
Comment thread
MichaelRFairhurst marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
| 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. |
Comment thread
MichaelRFairhurst marked this conversation as resolved.
Outdated
| 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. |
| test.cpp:12:16:12:22 | aligned | Use of attribute 'aligned' is a compiler extension and is not portable to other compilers. |
| test.cpp:13:16:13:21 | unused | Use of attribute 'unused' is a compiler extension and is not portable to other compilers. |
| test.cpp:14:21:14:28 | noreturn | Use of attribute 'noreturn' is a compiler extension and is not portable to other compilers. |
| 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. |
| test.cpp:16:3:16:23 | nonstandard_attribute | Use of unrecognized or non-C++17 attribute 'nonstandard_attribute'. |
| 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. |
| 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. |
| 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. |
| test.cpp:23:3:23:20 | __is_abstract | Use of built-in operation '__is_abstract' is a compiler extension. |
| test.cpp:24:3:24:22 | __is_same | Use of built-in operation '__is_same' is a compiler extension. |
| test.cpp:30:3:33:4 | (statement expression) | Statement expressions are a compiler extension and are not portable to other compilers. |
| test.cpp:34:3:34:12 | ... ? ... : ... | Ternaries with omitted middle operands are a compiler extension and are not portable to other compilers. |
| test.cpp:36:12:36:13 | definition of l0 | 128-bit integers are a compiler extension and are not portable to other compilers. |
| test.cpp:45:20:45:30 | fallthrough | Use of attribute 'fallthrough' is a compiler extension and is not portable to other compilers. |
| 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. |
| test.cpp:55:3:55:29 | __builtin_va_start | Use of built-in operation '__builtin_va_start' is a compiler extension. |
| test.cpp:60:7:60:8 | definition of m1 | Zero length arrays are a compiler extension and are not portable to other compilers. |
| test.cpp:64:31:64:41 | vector_size | Use of attribute 'vector_size' is a compiler extension and is not portable to other compilers. |
| 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. |
| test.cpp:72:1:72:12 | #pragma once | Use of non-standard preprocessor directive '#pragma once' is a compiler extension. |
| test.cpp:73:1:73:27 | #pragma GCC diagnostic push | Use of non-standard preprocessor directive '#pragma GCC diagnostic push' is a compiler extension. |
| test.cpp:74:1:74:28 | #warning "This is a warning" | Use of non-standard preprocessor directive '#warning' is a compiler extension. |
| test.cpp:76:1:76:41 | #warning "preceeding spaces is common" | Use of non-standard preprocessor directive '#warning' is a compiler extension. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-4-1-1/CompilerLanguageExtensionsUsed.ql
Loading
Loading