From 18443397f5a4713f426384167c968c50e4f4bfde Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 15:50:45 +0100 Subject: [PATCH 01/36] Add BannedAPIs package details --- .../cpp/exclusions/cpp/BannedAPIs.qll | 163 ++++++++++++++++ .../cpp/exclusions/cpp/RuleMetadata.qll | 3 + rule_packages/cpp/BannedAPIs.json | 184 ++++++++++++++++++ 3 files changed, 350 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll create mode 100644 rule_packages/cpp/BannedAPIs.json diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll new file mode 100644 index 000000000..571a48a62 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll @@ -0,0 +1,163 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype BannedAPIsQuery = + TAvoidProgramTerminatingFunctionsQuery() or + TNoVariadicFunctionMacrosQuery() or + TNoCsetjmpHeaderQuery() or + TUnsafeStringHandlingFunctionsQuery() or + TBannedSystemFunctionQuery() or + TUseSmartPtrFactoryFunctionsQuery() or + TCharacterHandlingFunctionRestrictionsQuery() or + TNoMemoryFunctionsFromCStringQuery() or + TLocaleGlobalFunctionNotAllowedQuery() + +predicate isBannedAPIsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `avoidProgramTerminatingFunctions` query + BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery() and + queryId = + // `@id` for the `avoidProgramTerminatingFunctions` query + "cpp/misra/avoid-program-terminating-functions" and + ruleId = "RULE-18-5-2" and + category = "advisory" + or + query = + // `Query` instance for the `noVariadicFunctionMacros` query + BannedAPIsPackage::noVariadicFunctionMacrosQuery() and + queryId = + // `@id` for the `noVariadicFunctionMacros` query + "cpp/misra/no-variadic-function-macros" and + ruleId = "RULE-21-10-1" and + category = "required" + or + query = + // `Query` instance for the `noCsetjmpHeader` query + BannedAPIsPackage::noCsetjmpHeaderQuery() and + queryId = + // `@id` for the `noCsetjmpHeader` query + "cpp/misra/no-csetjmp-header" and + ruleId = "RULE-21-10-2" and + category = "required" + or + query = + // `Query` instance for the `unsafeStringHandlingFunctions` query + BannedAPIsPackage::unsafeStringHandlingFunctionsQuery() and + queryId = + // `@id` for the `unsafeStringHandlingFunctions` query + "cpp/misra/unsafe-string-handling-functions" and + ruleId = "RULE-21-2-2" and + category = "required" + or + query = + // `Query` instance for the `bannedSystemFunction` query + BannedAPIsPackage::bannedSystemFunctionQuery() and + queryId = + // `@id` for the `bannedSystemFunction` query + "cpp/misra/banned-system-function" and + ruleId = "RULE-21-2-3" and + category = "required" + or + query = + // `Query` instance for the `useSmartPtrFactoryFunctions` query + BannedAPIsPackage::useSmartPtrFactoryFunctionsQuery() and + queryId = + // `@id` for the `useSmartPtrFactoryFunctions` query + "cpp/misra/use-smart-ptr-factory-functions" and + ruleId = "RULE-23-11-1" and + category = "advisory" + or + query = + // `Query` instance for the `characterHandlingFunctionRestrictions` query + BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery() and + queryId = + // `@id` for the `characterHandlingFunctionRestrictions` query + "cpp/misra/character-handling-function-restrictions" and + ruleId = "RULE-24-5-1" and + category = "required" + or + query = + // `Query` instance for the `noMemoryFunctionsFromCString` query + BannedAPIsPackage::noMemoryFunctionsFromCStringQuery() and + queryId = + // `@id` for the `noMemoryFunctionsFromCString` query + "cpp/misra/no-memory-functions-from-c-string" and + ruleId = "RULE-24-5-2" and + category = "required" + or + query = + // `Query` instance for the `localeGlobalFunctionNotAllowed` query + BannedAPIsPackage::localeGlobalFunctionNotAllowedQuery() and + queryId = + // `@id` for the `localeGlobalFunctionNotAllowed` query + "cpp/misra/locale-global-function-not-allowed" and + ruleId = "RULE-25-5-1" and + category = "required" +} + +module BannedAPIsPackage { + Query avoidProgramTerminatingFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `avoidProgramTerminatingFunctions` query + TQueryCPP(TBannedAPIsPackageQuery(TAvoidProgramTerminatingFunctionsQuery())) + } + + Query noVariadicFunctionMacrosQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noVariadicFunctionMacros` query + TQueryCPP(TBannedAPIsPackageQuery(TNoVariadicFunctionMacrosQuery())) + } + + Query noCsetjmpHeaderQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noCsetjmpHeader` query + TQueryCPP(TBannedAPIsPackageQuery(TNoCsetjmpHeaderQuery())) + } + + Query unsafeStringHandlingFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unsafeStringHandlingFunctions` query + TQueryCPP(TBannedAPIsPackageQuery(TUnsafeStringHandlingFunctionsQuery())) + } + + Query bannedSystemFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `bannedSystemFunction` query + TQueryCPP(TBannedAPIsPackageQuery(TBannedSystemFunctionQuery())) + } + + Query useSmartPtrFactoryFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useSmartPtrFactoryFunctions` query + TQueryCPP(TBannedAPIsPackageQuery(TUseSmartPtrFactoryFunctionsQuery())) + } + + Query characterHandlingFunctionRestrictionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `characterHandlingFunctionRestrictions` query + TQueryCPP(TBannedAPIsPackageQuery(TCharacterHandlingFunctionRestrictionsQuery())) + } + + Query noMemoryFunctionsFromCStringQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noMemoryFunctionsFromCString` query + TQueryCPP(TBannedAPIsPackageQuery(TNoMemoryFunctionsFromCStringQuery())) + } + + Query localeGlobalFunctionNotAllowedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `localeGlobalFunctionNotAllowed` query + TQueryCPP(TBannedAPIsPackageQuery(TLocaleGlobalFunctionNotAllowedQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index abd6aeff9..92e1bba57 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -3,6 +3,7 @@ import cpp import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ import Allocations +import BannedAPIs import BannedFunctions import BannedLibraries import BannedSyntax @@ -58,6 +59,7 @@ import VirtualFunctions /** The TQuery type representing this language * */ newtype TCPPQuery = TAllocationsPackageQuery(AllocationsQuery q) or + TBannedAPIsPackageQuery(BannedAPIsQuery q) or TBannedFunctionsPackageQuery(BannedFunctionsQuery q) or TBannedLibrariesPackageQuery(BannedLibrariesQuery q) or TBannedSyntaxPackageQuery(BannedSyntaxQuery q) or @@ -113,6 +115,7 @@ newtype TCPPQuery = /** The metadata predicate * */ predicate isQueryMetadata(Query query, string queryId, string ruleId, string category) { isAllocationsQueryMetadata(query, queryId, ruleId, category) or + isBannedAPIsQueryMetadata(query, queryId, ruleId, category) or isBannedFunctionsQueryMetadata(query, queryId, ruleId, category) or isBannedLibrariesQueryMetadata(query, queryId, ruleId, category) or isBannedSyntaxQueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/cpp/BannedAPIs.json b/rule_packages/cpp/BannedAPIs.json new file mode 100644 index 000000000..591f50b5e --- /dev/null +++ b/rule_packages/cpp/BannedAPIs.json @@ -0,0 +1,184 @@ +{ + "MISRA-C++-2023": { + "RULE-18-5-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using program-terminating functions like abort, exit, _Exit, quick_exit or terminate causes the stack to not be unwound and object destructors to not be called, potentially leaving the environment in an undesirable state.", + "kind": "problem", + "name": "Program-terminating functions should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "AvoidProgramTerminatingFunctions", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Program-terminating functions should not be used" + }, + "RULE-21-10-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using features like va_list, va_arg, va_start, va_end and va_copy bypasses compiler type checking and leads to undefined behavior when used incorrectly.", + "kind": "problem", + "name": "The features of shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoVariadicFunctionMacros", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The features of shall not be used" + }, + "RULE-21-10-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using facilities from the header causes undefined behavior by bypassing normal function return mechanisms and may result in non-trivial object destruction being omitted.", + "kind": "problem", + "name": "The standard header file shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoCsetjmpHeader", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The standard header file shall not be used" + }, + "RULE-21-2-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using string handling functions from , , and headers may result in buffer overflows or unreliable error detection through errno.", + "kind": "problem", + "name": "The string handling functions from , , and shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "UnsafeStringHandlingFunctions", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The string handling functions from , , and shall not be used" + }, + "RULE-21-2-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using the system() function from cstdlib or stdlib.h causes undefined behavior and potential security vulnerabilities.", + "kind": "problem", + "name": "The library function system from shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "BannedSystemFunction", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The library function system from shall not be used" + }, + "RULE-23-11-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using raw pointer constructors of std::shared_ptr and std::unique_ptr instead of make_shared/make_unique can lead to memory leaks if exceptions occur during construction.", + "kind": "problem", + "name": "The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "UseSmartPtrFactoryFunctions", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used" + }, + "RULE-24-5-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using character classification and case mapping functions from and causes undefined behavior when arguments are not representable as unsigned char or not equal to EOF.", + "kind": "problem", + "name": "The character handling functions from and shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "CharacterHandlingFunctionRestrictions", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The character handling functions from and shall not be used" + }, + "RULE-24-5-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using memcpy, memmove or memcmp from can result in undefined behavior due to overlapping memory, non-trivially copyable objects, or unequal comparison of logically equal objects.", + "kind": "problem", + "name": "The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoMemoryFunctionsFromCString", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used" + }, + "RULE-25-5-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Calling setlocale or std::locale::global functions can introduce data races with functions that use the locale, leading to undefined behavior.", + "kind": "problem", + "name": "The setlocale and std::locale::global functions shall not be called", + "precision": "very-high", + "severity": "error", + "short_name": "LocaleGlobalFunctionNotAllowed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The setlocale and std::locale::global functions shall not be called" + } + } +} \ No newline at end of file From 102703a3a25ee130af03de7b2c41245d3ee409c6 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 16:08:50 +0100 Subject: [PATCH 02/36] Rule 18.5.2: AvoidProgramTerminatingFunctions.ql Add a query to identify uses of terminating program functions. [a] --- .../test/includes/standard-library/cstdlib.h | 13 ++-- .../test/includes/standard-library/stdlib.h | 8 ++- .../AvoidProgramTerminatingFunctions.ql | 53 +++++++++++++++ .../AvoidProgramTerminatingFunctions.expected | 27 ++++++++ .../AvoidProgramTerminatingFunctions.qlref | 1 + cpp/misra/test/rules/RULE-18-5-2/test.cpp | 65 +++++++++++++++++++ 6 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql create mode 100644 cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected create mode 100644 cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref create mode 100644 cpp/misra/test/rules/RULE-18-5-2/test.cpp diff --git a/cpp/common/test/includes/standard-library/cstdlib.h b/cpp/common/test/includes/standard-library/cstdlib.h index 4a2d0cd9e..50c17d4ec 100644 --- a/cpp/common/test/includes/standard-library/cstdlib.h +++ b/cpp/common/test/includes/standard-library/cstdlib.h @@ -2,15 +2,18 @@ #define _GHLIBCPP_CSTDLIB #include "stdlib.h" namespace std { -[[noreturn]] void _Exit(int status) noexcept; -[[noreturn]] void abort(void) noexcept; -[[noreturn]] void quick_exit(int status) noexcept; -extern "C++" int atexit(void (*f)(void)) noexcept; -extern "C++" int at_quick_exit(void (*f)(void)) noexcept; +using ::_Exit; +using ::abort; +using ::at_quick_exit; +using ::atexit; using ::atof; using ::atoi; using ::atol; using ::atoll; +using ::exit; +using ::free; +using ::malloc; +using ::quick_exit; using ::rand; } // namespace std #endif // _GHLIBCPP_CSTDLIB \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdlib.h b/cpp/common/test/includes/standard-library/stdlib.h index 67f1abd69..7bfb3dc99 100644 --- a/cpp/common/test/includes/standard-library/stdlib.h +++ b/cpp/common/test/includes/standard-library/stdlib.h @@ -8,14 +8,18 @@ void free(void *ptr); void *malloc(size_t size); void *realloc(void *ptr, size_t size); -void abort(); +[[noreturn]] void _Exit(int status) noexcept; +[[noreturn]] void abort(void) noexcept; +[[noreturn]] void quick_exit(int status) noexcept; +extern "C++" int atexit(void (*f)(void)) noexcept; +extern "C++" int at_quick_exit(void (*f)(void)) noexcept; void exit(int code); int system(const char *command); char *getenv(const char *name); -int setenv (const char *, const char *, int); +int setenv(const char *, const char *, int); int atoi(const char *str); long int atol(const char *str); diff --git a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql new file mode 100644 index 000000000..e15c4f2b0 --- /dev/null +++ b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql @@ -0,0 +1,53 @@ +/** + * @id cpp/misra/avoid-program-terminating-functions + * @name RULE-18-5-2: Program-terminating functions should not be used + * @description Using program-terminating functions like abort, exit, _Exit, quick_exit or terminate + * causes the stack to not be unwound and object destructors to not be called, + * potentially leaving the environment in an undesirable state. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-5-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +predicate isTerminatingFunction(Function f, string functionName) { + functionName = f.getName() and + ( + functionName in ["abort", "exit", "_Exit", "quick_exit"] and + (f.hasQualifiedName("", functionName) or f.hasQualifiedName("std", functionName)) + or + // std::terminate does not occur in the global namespace. + functionName = "terminate" and f.hasQualifiedName("std", functionName) + ) +} + +predicate isAssertMacroCall(FunctionCall call) { + exists(MacroInvocation mi | + mi.getMacroName() = "assert" and + mi.getAnExpandedElement() = call + ) +} + +from Expr e, Function f, string functionName, string action +where + not isExcluded(e, BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery()) and + isTerminatingFunction(f, functionName) and + ( + // Direct function calls (excluding assert macro calls) + e instanceof FunctionCall and + f = e.(FunctionCall).getTarget() and + not isAssertMacroCall(e) and + action = "Call to" + or + // Function access + e instanceof FunctionAccess and + f = e.(FunctionAccess).getTarget() and + action = "Address taken for" + ) +select e, action + " program-terminating function '" + functionName + "'." diff --git a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected new file mode 100644 index 000000000..e9419d5cb --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected @@ -0,0 +1,27 @@ +| test.cpp:7:3:7:7 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:8:3:8:6 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:9:3:9:7 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:10:3:10:12 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:15:3:15:12 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:16:3:16:11 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:17:3:17:12 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:18:3:18:17 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:19:3:19:16 | call to terminate | Call to program-terminating function 'terminate'. | +| test.cpp:24:14:24:18 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:25:14:25:17 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:26:14:26:18 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:27:14:27:23 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:28:14:28:23 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:29:14:29:22 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:30:14:30:23 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:31:14:31:28 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:32:14:32:27 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:37:18:37:22 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:38:21:38:24 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:39:21:39:25 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:40:21:40:30 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:41:18:41:27 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:42:21:42:29 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:43:21:43:30 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:44:21:44:35 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:45:18:45:31 | terminate | Address taken for program-terminating function 'terminate'. | diff --git a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref new file mode 100644 index 000000000..afb81410c --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref @@ -0,0 +1 @@ +rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-18-5-2/test.cpp b/cpp/misra/test/rules/RULE-18-5-2/test.cpp new file mode 100644 index 000000000..ae7354adb --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-2/test.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +void test_direct_calls_to_terminating_functions() { + // Direct calls to program-terminating functions + abort(); // NON_COMPLIANT + exit(0); // NON_COMPLIANT + _Exit(1); // NON_COMPLIANT + quick_exit(2); // NON_COMPLIANT +} + +void test_std_namespace_calls() { + // Calls to functions in std namespace + std::abort(); // NON_COMPLIANT + std::exit(0); // NON_COMPLIANT + std::_Exit(1); // NON_COMPLIANT + std::quick_exit(2); // NON_COMPLIANT + std::terminate(); // NON_COMPLIANT +} + +void test_taking_addresses_of_terminating_functions() { + // Taking addresses of program-terminating functions + auto l1 = &abort; // NON_COMPLIANT + auto l2 = &exit; // NON_COMPLIANT + auto l3 = &_Exit; // NON_COMPLIANT + auto l4 = &quick_exit; // NON_COMPLIANT + auto l5 = &std::abort; // NON_COMPLIANT + auto l6 = &std::exit; // NON_COMPLIANT + auto l7 = &std::_Exit; // NON_COMPLIANT + auto l8 = &std::quick_exit; // NON_COMPLIANT + auto l9 = &std::terminate; // NON_COMPLIANT +} + +void test_function_pointers_to_terminating_functions() { + // Function pointers to program-terminating functions + void (*l1)() = abort; // NON_COMPLIANT + void (*l2)(int) = exit; // NON_COMPLIANT + void (*l3)(int) = _Exit; // NON_COMPLIANT + void (*l4)(int) = quick_exit; // NON_COMPLIANT + void (*l5)() = std::abort; // NON_COMPLIANT + void (*l6)(int) = std::exit; // NON_COMPLIANT + void (*l7)(int) = std::_Exit; // NON_COMPLIANT + void (*l8)(int) = std::quick_exit; // NON_COMPLIANT + void (*l9)() = std::terminate; // NON_COMPLIANT +} + +void test_assert_macro_exception() { + // The call to abort via assert macro is compliant by exception + assert(true); // COMPLIANT + assert(1 == 1); // COMPLIANT +} + +void f1() { + // Valid alternative: normal function return + return; // COMPLIANT +} + +void test_compliant_alternatives() { + // Using normal control flow instead of terminating functions + f1(); // COMPLIANT + + // Using exceptions for error handling + throw std::runtime_error("error"); // COMPLIANT +} \ No newline at end of file From 31039e343133feea7974c1d9a66a89c9eda84f31 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 16:42:23 +0100 Subject: [PATCH 03/36] RULE-18-5-2: Improve macro defined results Make the results easier to understand by reporting calls in macro expansions in the macros themselves, if they are defined by the developers of this project. --- .../includes/custom-library/custom_abort.h | 3 + .../AvoidProgramTerminatingFunctions.ql | 56 ++++++++++++------ .../AvoidProgramTerminatingFunctions.expected | 58 ++++++++++--------- cpp/misra/test/rules/RULE-18-5-2/test.cpp | 14 +++++ 4 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 cpp/common/test/includes/custom-library/custom_abort.h diff --git a/cpp/common/test/includes/custom-library/custom_abort.h b/cpp/common/test/includes/custom-library/custom_abort.h new file mode 100644 index 000000000..bab19a8e8 --- /dev/null +++ b/cpp/common/test/includes/custom-library/custom_abort.h @@ -0,0 +1,3 @@ +// Used for RULE-18-5-2 for library aborts +#include +#define LIBRARY_ABORT() std::abort() \ No newline at end of file diff --git a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql index e15c4f2b0..c262030c9 100644 --- a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql +++ b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql @@ -15,6 +15,7 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.AlertReporting predicate isTerminatingFunction(Function f, string functionName) { functionName = f.getName() and @@ -27,27 +28,46 @@ predicate isTerminatingFunction(Function f, string functionName) { ) } -predicate isAssertMacroCall(FunctionCall call) { +class TerminatingFunctionUse extends Expr { + string action; + string functionName; + + TerminatingFunctionUse() { + exists(Function f | isTerminatingFunction(f, functionName) | + this.(FunctionCall).getTarget() = f and + action = "Call to" + or + this.(FunctionAccess).getTarget() = f and + action = "Address taken for" + ) + } + + string getFunctionName() { result = functionName } + + string getAction() { result = action } + + Element getPrimaryElement() { + // If this is defined in a macro in the users source location, then report the macro + // expansion, otherwise report the element itself. This ensures that we always report + // the use of the terminating function, but combine usages when the macro is defined + // by the user. + exists(Element e | e = MacroUnwrapper::unwrapElement(this) | + if exists(e.getFile().getRelativePath()) then result = e else result = this + ) + } +} + +predicate isInAssertMacroInvocation(TerminatingFunctionUse use) { exists(MacroInvocation mi | mi.getMacroName() = "assert" and - mi.getAnExpandedElement() = call + mi.getAnExpandedElement() = use ) } -from Expr e, Function f, string functionName, string action +from TerminatingFunctionUse use where - not isExcluded(e, BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery()) and - isTerminatingFunction(f, functionName) and - ( - // Direct function calls (excluding assert macro calls) - e instanceof FunctionCall and - f = e.(FunctionCall).getTarget() and - not isAssertMacroCall(e) and - action = "Call to" - or - // Function access - e instanceof FunctionAccess and - f = e.(FunctionAccess).getTarget() and - action = "Address taken for" - ) -select e, action + " program-terminating function '" + functionName + "'." + not isExcluded(use, BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery()) and + // Exclude the uses in the assert macro + not isInAssertMacroInvocation(use) +select use.getPrimaryElement(), + use.getAction() + " program-terminating function '" + use.getFunctionName() + "'." diff --git a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected index e9419d5cb..4f0a79dcb 100644 --- a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected +++ b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected @@ -1,27 +1,31 @@ -| test.cpp:7:3:7:7 | call to abort | Call to program-terminating function 'abort'. | -| test.cpp:8:3:8:6 | call to exit | Call to program-terminating function 'exit'. | -| test.cpp:9:3:9:7 | call to _Exit | Call to program-terminating function '_Exit'. | -| test.cpp:10:3:10:12 | call to quick_exit | Call to program-terminating function 'quick_exit'. | -| test.cpp:15:3:15:12 | call to abort | Call to program-terminating function 'abort'. | -| test.cpp:16:3:16:11 | call to exit | Call to program-terminating function 'exit'. | -| test.cpp:17:3:17:12 | call to _Exit | Call to program-terminating function '_Exit'. | -| test.cpp:18:3:18:17 | call to quick_exit | Call to program-terminating function 'quick_exit'. | -| test.cpp:19:3:19:16 | call to terminate | Call to program-terminating function 'terminate'. | -| test.cpp:24:14:24:18 | abort | Address taken for program-terminating function 'abort'. | -| test.cpp:25:14:25:17 | exit | Address taken for program-terminating function 'exit'. | -| test.cpp:26:14:26:18 | _Exit | Address taken for program-terminating function '_Exit'. | -| test.cpp:27:14:27:23 | quick_exit | Address taken for program-terminating function 'quick_exit'. | -| test.cpp:28:14:28:23 | abort | Address taken for program-terminating function 'abort'. | -| test.cpp:29:14:29:22 | exit | Address taken for program-terminating function 'exit'. | -| test.cpp:30:14:30:23 | _Exit | Address taken for program-terminating function '_Exit'. | -| test.cpp:31:14:31:28 | quick_exit | Address taken for program-terminating function 'quick_exit'. | -| test.cpp:32:14:32:27 | terminate | Address taken for program-terminating function 'terminate'. | -| test.cpp:37:18:37:22 | abort | Address taken for program-terminating function 'abort'. | -| test.cpp:38:21:38:24 | exit | Address taken for program-terminating function 'exit'. | -| test.cpp:39:21:39:25 | _Exit | Address taken for program-terminating function '_Exit'. | -| test.cpp:40:21:40:30 | quick_exit | Address taken for program-terminating function 'quick_exit'. | -| test.cpp:41:18:41:27 | abort | Address taken for program-terminating function 'abort'. | -| test.cpp:42:21:42:29 | exit | Address taken for program-terminating function 'exit'. | -| test.cpp:43:21:43:30 | _Exit | Address taken for program-terminating function '_Exit'. | -| test.cpp:44:21:44:35 | quick_exit | Address taken for program-terminating function 'quick_exit'. | -| test.cpp:45:18:45:31 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:8:3:8:7 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:9:3:9:6 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:10:3:10:7 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:11:3:11:12 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:16:3:16:12 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:17:3:17:11 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:18:3:18:12 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:19:3:19:17 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:20:3:20:16 | call to terminate | Call to program-terminating function 'terminate'. | +| test.cpp:25:14:25:18 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:26:14:26:17 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:27:14:27:18 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:28:14:28:23 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:29:14:29:23 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:30:14:30:22 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:31:14:31:23 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:32:14:32:28 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:33:14:33:27 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:38:18:38:22 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:39:21:39:24 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:40:21:40:25 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:41:21:41:30 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:42:18:42:27 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:43:21:43:29 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:44:21:44:30 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:45:21:45:35 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:46:18:46:31 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:68:1:68:33 | #define CALL_ABORT() std::abort() | Call to program-terminating function 'abort'. | +| test.cpp:69:1:69:33 | #define CALL_EXIT(x) std::exit(x) | Call to program-terminating function 'exit'. | +| test.cpp:70:1:70:41 | #define CALL_TERMINATE() std::terminate() | Call to program-terminating function 'terminate'. | +| test.cpp:77:3:77:17 | call to abort | Call to program-terminating function 'abort'. | diff --git a/cpp/misra/test/rules/RULE-18-5-2/test.cpp b/cpp/misra/test/rules/RULE-18-5-2/test.cpp index ae7354adb..d2e2cca38 100644 --- a/cpp/misra/test/rules/RULE-18-5-2/test.cpp +++ b/cpp/misra/test/rules/RULE-18-5-2/test.cpp @@ -1,3 +1,4 @@ +#include "custom_abort.h" #include #include #include @@ -62,4 +63,17 @@ void test_compliant_alternatives() { // Using exceptions for error handling throw std::runtime_error("error"); // COMPLIANT +} + +#define CALL_ABORT() std::abort() // NON_COMPLIANT +#define CALL_EXIT(x) std::exit(x) // NON_COMPLIANT +#define CALL_TERMINATE() std::terminate() // NON_COMPLIANT + +void test_macro_expansion_with_terminating_functions() { + // Macro expansions containing terminating functions + CALL_ABORT(); // reported at the definition site + CALL_EXIT(1); // reported at the definition site + CALL_TERMINATE(); // reported at the definition site + LIBRARY_ABORT(); // NON_COMPLIANT - macro not defined by user, so flagged at + // the call site } \ No newline at end of file From e9c0fe4bbfa8258819b7cef57dd44b248e544cd2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 16:49:39 +0100 Subject: [PATCH 04/36] Remove cstdlib.h This header shouldn't exist. --- .../test/includes/standard-library/cstdlib | 20 ++++++++++++++++++- .../test/includes/standard-library/cstdlib.h | 19 ------------------ 2 files changed, 19 insertions(+), 20 deletions(-) delete mode 100644 cpp/common/test/includes/standard-library/cstdlib.h diff --git a/cpp/common/test/includes/standard-library/cstdlib b/cpp/common/test/includes/standard-library/cstdlib index 23eab7eac..50c17d4ec 100644 --- a/cpp/common/test/includes/standard-library/cstdlib +++ b/cpp/common/test/includes/standard-library/cstdlib @@ -1 +1,19 @@ -#include "cstdlib.h" \ No newline at end of file +#ifndef _GHLIBCPP_CSTDLIB +#define _GHLIBCPP_CSTDLIB +#include "stdlib.h" +namespace std { +using ::_Exit; +using ::abort; +using ::at_quick_exit; +using ::atexit; +using ::atof; +using ::atoi; +using ::atol; +using ::atoll; +using ::exit; +using ::free; +using ::malloc; +using ::quick_exit; +using ::rand; +} // namespace std +#endif // _GHLIBCPP_CSTDLIB \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstdlib.h b/cpp/common/test/includes/standard-library/cstdlib.h deleted file mode 100644 index 50c17d4ec..000000000 --- a/cpp/common/test/includes/standard-library/cstdlib.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _GHLIBCPP_CSTDLIB -#define _GHLIBCPP_CSTDLIB -#include "stdlib.h" -namespace std { -using ::_Exit; -using ::abort; -using ::at_quick_exit; -using ::atexit; -using ::atof; -using ::atoi; -using ::atol; -using ::atoll; -using ::exit; -using ::free; -using ::malloc; -using ::quick_exit; -using ::rand; -} // namespace std -#endif // _GHLIBCPP_CSTDLIB \ No newline at end of file From 58e43adbd7a84e174e029f4d61c8d1145c114e5f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 22:31:58 +0100 Subject: [PATCH 05/36] Improve C++ stub headers for cstdarg --- cpp/common/test/includes/standard-library/cstdarg | 10 +++++----- cpp/common/test/includes/standard-library/stdarg.h | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cstdarg b/cpp/common/test/includes/standard-library/cstdarg index f2b84242a..6dd883b68 100644 --- a/cpp/common/test/includes/standard-library/cstdarg +++ b/cpp/common/test/includes/standard-library/cstdarg @@ -1,9 +1,9 @@ #pragma once +#ifndef _GHLIBCPP_CSTDARG +#define _GHLIBCPP_CSTDARG +#include "stdarg.h" namespace std { - typedef __builtin_va_list va_list; +using ::va_list; } // namespace std - -#define va_arg(v, p) __builtin_va_arg(v, p) -#define va_end(v) __builtin_va_end(v) -#define va_start(v,l) __builtin_va_start(v,l) \ No newline at end of file +#endif // _GHLIBCPP_CSTDARG \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdarg.h b/cpp/common/test/includes/standard-library/stdarg.h index e69de29bb..cab940168 100644 --- a/cpp/common/test/includes/standard-library/stdarg.h +++ b/cpp/common/test/includes/standard-library/stdarg.h @@ -0,0 +1,6 @@ + +typedef __builtin_va_list va_list; +#define va_arg(v, p) __builtin_va_arg(v, p) +#define va_end(v) __builtin_va_end(v) +#define va_start(v, l) __builtin_va_start(v, l) +#define va_copy(d, s) __builtin_va_copy(d, s) \ No newline at end of file From ffed4673ca327f950798f57c3cd56e9e84fd2130 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 22:37:16 +0100 Subject: [PATCH 06/36] Rule 21.10.1: NoVariadicFunctionMacros.ql A query for reporting the use of variadic functions. [a] --- .../RULE-21-10-1/NoVariadicFunctionMacros.ql | 53 ++++++++++++++++ .../NoVariadicFunctionMacros.expected | 29 +++++++++ .../NoVariadicFunctionMacros.qlref | 1 + cpp/misra/test/rules/RULE-21-10-1/test.cpp | 60 +++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql create mode 100644 cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected create mode 100644 cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref create mode 100644 cpp/misra/test/rules/RULE-21-10-1/test.cpp diff --git a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql new file mode 100644 index 000000000..7e96f7022 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql @@ -0,0 +1,53 @@ +/** + * @id cpp/misra/no-variadic-function-macros + * @name RULE-21-10-1: The features of shall not be used + * @description Using features like va_list, va_arg, va_start, va_end and va_copy bypasses + * compiler type checking and leads to undefined behavior when used incorrectly. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-10-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +class VaListType extends Type { + VaListType() { + this.getName() = "va_list" or + this.getName() = "__va_list_tag" or + this.(SpecifiedType).getBaseType() instanceof VaListType or + this.(TypedefType).getBaseType() instanceof VaListType + } +} + +from Element element, string message +where + not isExcluded(element, BannedAPIsPackage::noVariadicFunctionMacrosQuery()) and + ( + element.(Variable).getType() instanceof VaListType and + message = "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'." + or + element.(Parameter).getType() instanceof VaListType and + message = "Declaration of parameter '" + element.(Parameter).getName() + "' of type 'va_list'." + or + element instanceof BuiltInVarArgsStart and + message = "Call to 'va_start'." + or + element instanceof BuiltInVarArgsEnd and + message = "Call to 'va_end'." + or + element instanceof BuiltInVarArg and + message = "Call to 'va_arg'." + or + element instanceof BuiltInVarArgCopy and + message = "Call to 'va_copy'." + or + element.(TypedefType).getBaseType() instanceof VaListType and + message = + "Declaration of typedef '" + element.(TypedefType).getName() + "' aliasing 'va_list' type." + ) +select element, message \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected new file mode 100644 index 000000000..3c47cc4aa --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected @@ -0,0 +1,29 @@ +| test.cpp:5:11:5:12 | l1 | Declaration of variable 'l1' of type 'va_list'. | +| test.cpp:9:11:9:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:10:3:10:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:11:3:11:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:15:11:15:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:16:3:16:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:17:21:17:44 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:18:3:18:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:22:11:22:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:23:3:23:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:24:3:24:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:28:11:28:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:28:15:28:16 | l3 | Declaration of variable 'l3' of type 'va_list'. | +| test.cpp:29:3:29:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:30:3:30:17 | __builtin_va_copy | Call to 'va_copy'. | +| test.cpp:31:3:31:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:32:3:32:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:35:37:35:38 | l1 | Declaration of parameter 'l1' of type 'va_list'. | +| test.cpp:35:37:35:38 | l1 | Declaration of variable 'l1' of type 'va_list'. | +| test.cpp:36:15:36:32 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:40:11:40:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:41:3:41:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:42:21:42:44 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:43:15:43:32 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:44:3:44:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:55:17:55:29 | va_list_alias | Declaration of typedef 'va_list_alias' aliasing 'va_list' type. | +| test.cpp:56:17:56:25 | SOME_TYPE | Declaration of typedef 'SOME_TYPE' aliasing 'va_list' type. | +| test.cpp:58:17:58:18 | l1 | Declaration of variable 'l1' of type 'va_list'. | +| test.cpp:59:13:59:14 | l2 | Declaration of variable 'l2' of type 'va_list'. | diff --git a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref new file mode 100644 index 000000000..7106c2aa2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref @@ -0,0 +1 @@ +rules/RULE-21-10-1/NoVariadicFunctionMacros.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-1/test.cpp b/cpp/misra/test/rules/RULE-21-10-1/test.cpp new file mode 100644 index 000000000..1ff0793e0 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-1/test.cpp @@ -0,0 +1,60 @@ +#include +#include + +void test_va_list_declaration() { + va_list l1; // NON_COMPLIANT +} + +void test_va_start_usage(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_arg_usage(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + std::int32_t l3 = va_arg(l2, std::int32_t); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_end_usage(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_copy_usage(std::int32_t l1, ...) { + va_list l2, l3; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + va_copy(l3, l2); // NON_COMPLIANT + va_end(l3); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_list_parameter(va_list l1) { // NON_COMPLIANT + double l2 = va_arg(l1, double); // NON_COMPLIANT +} + +void test_multiple_va_arg_calls(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + std::int32_t l3 = va_arg(l2, std::int32_t); // NON_COMPLIANT + double l4 = va_arg(l2, double); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_variadic_function_declaration(std::int16_t l1, ...) { + // Function declaration with ellipsis is compliant +} + +void test_variadic_function_call() { + test_variadic_function_declaration(1, 2.0, 3.0); // COMPLIANT +} + +typedef va_list va_list_alias; // NON_COMPLIANT +typedef va_list SOME_TYPE; // NON_COMPLIANT +void test_va_list_alias() { + va_list_alias l1; // NON_COMPLIANT + SOME_TYPE l2; // NON_COMPLIANT +} \ No newline at end of file From d3ec7b09b2aaa9f0c59155c70519abf318856b72 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 10:53:09 +0100 Subject: [PATCH 07/36] Remove redundant header stub file --- .../test/includes/standard-library/cstring | 30 ++++++++++++++++++- .../test/includes/standard-library/cstring.h | 29 ------------------ 2 files changed, 29 insertions(+), 30 deletions(-) delete mode 100644 cpp/common/test/includes/standard-library/cstring.h diff --git a/cpp/common/test/includes/standard-library/cstring b/cpp/common/test/includes/standard-library/cstring index 105e3e469..2034c3963 100644 --- a/cpp/common/test/includes/standard-library/cstring +++ b/cpp/common/test/includes/standard-library/cstring @@ -1 +1,29 @@ -#include "cstring.h" \ No newline at end of file +#ifndef _GHLIBCPP_CSTRING +#define _GHLIBCPP_CSTRING + +#include + +namespace std { +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 \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstring.h b/cpp/common/test/includes/standard-library/cstring.h deleted file mode 100644 index 2f3ffd393..000000000 --- a/cpp/common/test/includes/standard-library/cstring.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _GHLIBCPP_CSTRING -#define _GHLIBCPP_CSTRING - -#include - -namespace std { -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 From aae01d00b2b224b95bb1bfb38ddc2c128d4d3dc4 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:32:19 +0100 Subject: [PATCH 08/36] Add csetjmp header --- cpp/common/test/includes/standard-library/csetjmp | 12 ++++++++++++ cpp/common/test/includes/standard-library/setjmp.h | 12 +++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/cpp/common/test/includes/standard-library/csetjmp b/cpp/common/test/includes/standard-library/csetjmp index e69de29bb..c1f7ceed3 100644 --- a/cpp/common/test/includes/standard-library/csetjmp +++ b/cpp/common/test/includes/standard-library/csetjmp @@ -0,0 +1,12 @@ +#ifndef _GHLIBCPP_CSETJMP +#define _GHLIBCPP_CSETJMP + +#include "setjmp.h" + +// C++ std namespace declarations +namespace std { +using ::jmp_buf; +using ::longjmp; +} // namespace std + +#endif // _GHLIBCPP_CSETJMP \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/setjmp.h b/cpp/common/test/includes/standard-library/setjmp.h index bb7e4fdc2..3d9ac27eb 100644 --- a/cpp/common/test/includes/standard-library/setjmp.h +++ b/cpp/common/test/includes/standard-library/setjmp.h @@ -1,14 +1,12 @@ #ifndef _GHLIBCPP_SETJMP #define _GHLIBCPP_SETJMP - -struct __jmp_buf_tag - { - int x; - }; +struct __jmp_buf_tag { + int x; +}; typedef struct __jmp_buf_tag jmp_buf[1]; -void longjmp (struct __jmp_buf_tag __env[1], int __val); -#define setjmp(env) 0 +[[noreturn]] void longjmp(struct __jmp_buf_tag __env[1], int __val); +#define setjmp(env) 0 #endif From 786f747318bce4d540393b9340db201e4fb4fc37 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:33:18 +0100 Subject: [PATCH 09/36] Add str* functions to cstdlib/stdlib.h headers --- cpp/common/test/includes/standard-library/cstdlib | 7 +++++++ cpp/common/test/includes/standard-library/stdlib.h | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/cpp/common/test/includes/standard-library/cstdlib b/cpp/common/test/includes/standard-library/cstdlib index 50c17d4ec..1b7df173a 100644 --- a/cpp/common/test/includes/standard-library/cstdlib +++ b/cpp/common/test/includes/standard-library/cstdlib @@ -15,5 +15,12 @@ using ::free; using ::malloc; using ::quick_exit; using ::rand; +using ::strtod; +using ::strtof; +using ::strtol; +using ::strtold; +using ::strtoll; +using ::strtoul; +using ::strtoull; } // namespace std #endif // _GHLIBCPP_CSTDLIB \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdlib.h b/cpp/common/test/includes/standard-library/stdlib.h index 7bfb3dc99..eb73db062 100644 --- a/cpp/common/test/includes/standard-library/stdlib.h +++ b/cpp/common/test/includes/standard-library/stdlib.h @@ -26,6 +26,14 @@ long int atol(const char *str); long long int atoll(const char *str); double atof(const char *str); +long int strtol(const char *str, char **endptr, int base); +long long int strtoll(const char *str, char **endptr, int base); +unsigned long int strtoul(const char *str, char **endptr, int base); +unsigned long long int strtoull(const char *str, char **endptr, int base); +double strtod(const char *str, char **endptr); +float strtof(const char *str, char **endptr); +long double strtold(const char *str, char **endptr); + int rand(void); #endif // _GHLIBCPP_STDLIB \ No newline at end of file From 4ae6e326ba14eff4f681bc69637618be25521fcf Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:33:53 +0100 Subject: [PATCH 10/36] Add strerror to cstring/string.h And remove duplicate definitions --- cpp/common/test/includes/standard-library/cstring | 1 + cpp/common/test/includes/standard-library/string.h | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cstring b/cpp/common/test/includes/standard-library/cstring index 2034c3963..1df227607 100644 --- a/cpp/common/test/includes/standard-library/cstring +++ b/cpp/common/test/includes/standard-library/cstring @@ -15,6 +15,7 @@ using ::strcmp; using ::strcoll; using ::strcpy; using ::strcspn; +using ::strerror; using ::strlen; using ::strncat; using ::strncmp; diff --git a/cpp/common/test/includes/standard-library/string.h b/cpp/common/test/includes/standard-library/string.h index d94a186f0..b4b4d9b12 100644 --- a/cpp/common/test/includes/standard-library/string.h +++ b/cpp/common/test/includes/standard-library/string.h @@ -35,14 +35,13 @@ const char *strstr(const char *str1, const char *str2); char *strstr(char *str1, const char *str2); char *strtok(char *str, const char *delimiters); +char *strerror(int errnum); -char *strdup (const char *); +char *strdup(const char *); void *memcpy(void *dest, const void *src, size_t count); 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); -size_t strlen(const char *str); - #endif // _GHLIBCPP_STRINGH \ No newline at end of file From 1415a723fadc3c2b4bbb0697ea5feb3c3dd051b2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:37:07 +0100 Subject: [PATCH 11/36] Add cwchar/wchar.h as stubs --- .../test/includes/standard-library/cwchar | 18 ++++++++++++++++++ .../test/includes/standard-library/wchar.h | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/cpp/common/test/includes/standard-library/cwchar b/cpp/common/test/includes/standard-library/cwchar index e69de29bb..a3e70b8d2 100644 --- a/cpp/common/test/includes/standard-library/cwchar +++ b/cpp/common/test/includes/standard-library/cwchar @@ -0,0 +1,18 @@ +#pragma once +#ifndef _GHLIBCPP_CWCHAR +#define _GHLIBCPP_CWCHAR +#include "wchar.h" + +namespace std { +using ::fgetwc; +using ::fputwc; +using ::wcstod; +using ::wcstof; +using ::wcstol; +using ::wcstold; +using ::wcstoll; +using ::wcstoul; +using ::wcstoull; +} // namespace std + +#endif // _GHLIBCPP_CWCHAR \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/wchar.h b/cpp/common/test/includes/standard-library/wchar.h index e69de29bb..e2f294245 100644 --- a/cpp/common/test/includes/standard-library/wchar.h +++ b/cpp/common/test/includes/standard-library/wchar.h @@ -0,0 +1,19 @@ +#ifndef _GHLIBCPP_WCHAR +#define _GHLIBCPP_WCHAR + +#include "stddef.h" + +// Wide character I/O functions +wchar_t fgetwc(void *stream); +wchar_t fputwc(wchar_t wc, void *stream); + +// Wide character string conversion functions +long wcstol(const wchar_t *str, wchar_t **endptr, int base); +long long wcstoll(const wchar_t *str, wchar_t **endptr, int base); +unsigned long wcstoul(const wchar_t *str, wchar_t **endptr, int base); +unsigned long long wcstoull(const wchar_t *str, wchar_t **endptr, int base); +double wcstod(const wchar_t *str, wchar_t **endptr); +float wcstof(const wchar_t *str, wchar_t **endptr); +long double wcstold(const wchar_t *str, wchar_t **endptr); + +#endif // _GHLIBCPP_WCHAR \ No newline at end of file From c15b516d8f6a7f4ef223112f2fff158a6ebb91a0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:38:29 +0100 Subject: [PATCH 12/36] Add `stdint.h` as a header, and move cstdint definitions --- .../test/includes/standard-library/cstdint.h | 29 ++++++++++--------- .../test/includes/standard-library/stdint.h | 20 +++++++++++++ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cstdint.h b/cpp/common/test/includes/standard-library/cstdint.h index 6a691637f..f84fe3e4b 100644 --- a/cpp/common/test/includes/standard-library/cstdint.h +++ b/cpp/common/test/includes/standard-library/cstdint.h @@ -1,19 +1,20 @@ #ifndef _GHLIBCPP_CSTDINT #define _GHLIBCPP_CSTDINT +#include "stdint.h" namespace std { -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef signed short int int16_t; -typedef unsigned short int uint16_t; -typedef signed int int32_t; -typedef unsigned int uint32_t; -typedef signed long int int64_t; -typedef unsigned long int uint64_t; -typedef int intmax_t; - -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; +using ::int16_t; +using ::int32_t; +using ::int64_t; +using ::int8_t; +using ::intmax_t; +using ::uint16_t; +using ::uint32_t; +using ::uint64_t; +using ::uint8_t; +using ::uint_fast16_t; +using ::uint_fast32_t; +using ::uint_fast64_t; +using ::uint_fast8_t; +using ::uintmax_t; } // namespace std #endif // _GHLIBCPP_CSTDINT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdint.h b/cpp/common/test/includes/standard-library/stdint.h index e69de29bb..ab5746164 100644 --- a/cpp/common/test/includes/standard-library/stdint.h +++ b/cpp/common/test/includes/standard-library/stdint.h @@ -0,0 +1,20 @@ +#ifndef _GHLIBCPP_STDINT +#define _GHLIBCPP_STDINT + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int int16_t; +typedef unsigned short int uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef signed long int int64_t; +typedef unsigned long int uint64_t; +typedef int intmax_t; +typedef unsigned int uintmax_t; + +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +#endif // _GHLIBCPP_STDINT \ No newline at end of file From ce58affab081b50e13326efde5da90af3308c312 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:39:55 +0100 Subject: [PATCH 13/36] Remove cstdint.h This is not a "real" header - definitions should be in stdint.h and cstdint. --- .../src/codingstandards/cpp/CommonTypes.qll | 2 +- .../test/includes/standard-library/cstdint | 26 ++++++++++++++----- .../test/includes/standard-library/cstdint.h | 20 -------------- .../test/includes/standard-library/random.h | 2 +- 4 files changed, 22 insertions(+), 28 deletions(-) delete mode 100644 cpp/common/test/includes/standard-library/cstdint.h diff --git a/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll b/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll index aafbe8543..3c8ea46b0 100644 --- a/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll +++ b/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll @@ -1,7 +1,7 @@ import cpp as default /* - * Implementations of the C/C++ Fixed Width Types from cstdint.h. + * Implementations of the C/C++ Fixed Width Types from cstdint. * * TODO: Deprecate once this is available in the CodeQL standard library. */ diff --git a/cpp/common/test/includes/standard-library/cstdint b/cpp/common/test/includes/standard-library/cstdint index fedf405dd..f84fe3e4b 100644 --- a/cpp/common/test/includes/standard-library/cstdint +++ b/cpp/common/test/includes/standard-library/cstdint @@ -1,6 +1,20 @@ -#ifndef _CPP_CSTDINT -#define _CPP_CSTDINT - -#define MAX_INT -#include -#endif \ No newline at end of file +#ifndef _GHLIBCPP_CSTDINT +#define _GHLIBCPP_CSTDINT +#include "stdint.h" +namespace std { +using ::int16_t; +using ::int32_t; +using ::int64_t; +using ::int8_t; +using ::intmax_t; +using ::uint16_t; +using ::uint32_t; +using ::uint64_t; +using ::uint8_t; +using ::uint_fast16_t; +using ::uint_fast32_t; +using ::uint_fast64_t; +using ::uint_fast8_t; +using ::uintmax_t; +} // namespace std +#endif // _GHLIBCPP_CSTDINT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstdint.h b/cpp/common/test/includes/standard-library/cstdint.h deleted file mode 100644 index f84fe3e4b..000000000 --- a/cpp/common/test/includes/standard-library/cstdint.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _GHLIBCPP_CSTDINT -#define _GHLIBCPP_CSTDINT -#include "stdint.h" -namespace std { -using ::int16_t; -using ::int32_t; -using ::int64_t; -using ::int8_t; -using ::intmax_t; -using ::uint16_t; -using ::uint32_t; -using ::uint64_t; -using ::uint8_t; -using ::uint_fast16_t; -using ::uint_fast32_t; -using ::uint_fast64_t; -using ::uint_fast8_t; -using ::uintmax_t; -} // namespace std -#endif // _GHLIBCPP_CSTDINT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/random.h b/cpp/common/test/includes/standard-library/random.h index 1a2b34122..141b806b6 100644 --- a/cpp/common/test/includes/standard-library/random.h +++ b/cpp/common/test/includes/standard-library/random.h @@ -1,7 +1,7 @@ #ifndef _GHLIBCPP_RANDOM #define _GHLIBCPP_RANDOM -#include "cstdint.h" #include "stddef.h" +#include #include namespace std { From 99fa73b45e2850399338eae173c03a5a365756ea Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:47:48 +0100 Subject: [PATCH 14/36] Update cinttypes/inttypes.h - Replace int aliases with include of stdint.h - Add str/wcs function stubs - Add header guards --- .../test/includes/standard-library/cinttypes | 13 ++++++++++++- .../test/includes/standard-library/inttypes.h | 19 ++++++++++--------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cinttypes b/cpp/common/test/includes/standard-library/cinttypes index 8adb84dd2..e9f7d4514 100644 --- a/cpp/common/test/includes/standard-library/cinttypes +++ b/cpp/common/test/includes/standard-library/cinttypes @@ -1 +1,12 @@ -#include \ No newline at end of file +#ifndef _GHLIBCPP_CINTTYPES +#define _GHLIBCPP_CINTTYPES +#include "inttypes.h" + +namespace std { +using ::strtoimax; +using ::strtoumax; +using ::wcstoimax; +using ::wcstoumax; +} // namespace std + +#endif // _GHLIBCPP_CINTTYPES \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/inttypes.h b/cpp/common/test/includes/standard-library/inttypes.h index d613ea4dc..2f32726a0 100644 --- a/cpp/common/test/includes/standard-library/inttypes.h +++ b/cpp/common/test/includes/standard-library/inttypes.h @@ -1,11 +1,12 @@ -#pragma once +#ifndef _GHLIBCPP_INTTYPES +#define _GHLIBCPP_INTTYPES +#include -typedef signed char int8_t; -typedef signed short int int16_t; -typedef signed long int int32_t; -typedef signed long long int int64_t; +// String conversion functions +intmax_t strtoimax(const char *str, char **endptr, int base); +uintmax_t strtoumax(const char *str, char **endptr, int base); -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned long int uint32_t; -typedef unsigned long long int uint64_t; \ No newline at end of file +// Wide character versions +intmax_t wcstoimax(const wchar_t *str, wchar_t **endptr, int base); +uintmax_t wcstoumax(const wchar_t *str, wchar_t **endptr, int base); +#endif // _GHLIBCPP_INTTYPES \ No newline at end of file From 84697e6605d7b8efad19c024510b5216a77b2a7f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 12:49:19 +0100 Subject: [PATCH 15/36] Populate wint_t from wctype.h, and use it in wchar.h. --- cpp/common/test/includes/standard-library/cwctype | 8 ++++++++ cpp/common/test/includes/standard-library/wchar.h | 5 +++-- cpp/common/test/includes/standard-library/wctype.h | 6 ++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cwctype b/cpp/common/test/includes/standard-library/cwctype index e69de29bb..490ed4edf 100644 --- a/cpp/common/test/includes/standard-library/cwctype +++ b/cpp/common/test/includes/standard-library/cwctype @@ -0,0 +1,8 @@ +#ifndef _GHLIBCPP_CWCTYPE +#define _GHLIBCPP_CWCTYPE + +namespace std { +using ::wint_t; +} // namespace std + +#endif // _GHLIBCPP_CWCTYPE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/wchar.h b/cpp/common/test/includes/standard-library/wchar.h index e2f294245..6c79fb0de 100644 --- a/cpp/common/test/includes/standard-library/wchar.h +++ b/cpp/common/test/includes/standard-library/wchar.h @@ -2,10 +2,11 @@ #define _GHLIBCPP_WCHAR #include "stddef.h" +#include "wctype.h" // Wide character I/O functions -wchar_t fgetwc(void *stream); -wchar_t fputwc(wchar_t wc, void *stream); +wint_t fgetwc(void *stream); +wint_t fputwc(wchar_t wc, void *stream); // Wide character string conversion functions long wcstol(const wchar_t *str, wchar_t **endptr, int base); diff --git a/cpp/common/test/includes/standard-library/wctype.h b/cpp/common/test/includes/standard-library/wctype.h index e69de29bb..b82c7a13f 100644 --- a/cpp/common/test/includes/standard-library/wctype.h +++ b/cpp/common/test/includes/standard-library/wctype.h @@ -0,0 +1,6 @@ +#ifndef _GHLIBCPP_WCTYPE +#define _GHLIBCPP_WCTYPE + +typedef long wint_t; + +#endif // _GHLIBCPP_WCTYPE \ No newline at end of file From 555fdecf8c3b4cab2ce9ce9ea13e9827a7e5667c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 12:51:02 +0100 Subject: [PATCH 16/36] Rule 21.2.2 - UnsafeStringHandlingFunctions.ql Add a query to detect uses of a number of common unsafe string handling functions. [a] --- .../UnsafeStringHandlingFunctions.ql | 45 +++ .../UnsafeStringHandlingFunctions.expected | 222 +++++++++++ .../UnsafeStringHandlingFunctions.qlref | 1 + cpp/misra/test/rules/RULE-21-2-2/test.cpp | 367 ++++++++++++++++++ 4 files changed, 635 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql create mode 100644 cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected create mode 100644 cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref create mode 100644 cpp/misra/test/rules/RULE-21-2-2/test.cpp diff --git a/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql new file mode 100644 index 000000000..6a2638d21 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql @@ -0,0 +1,45 @@ +/** + * @id cpp/misra/unsafe-string-handling-functions + * @name RULE-21-2-2: The string handling functions from , , and shall not be used + * @description Using string handling functions from , , and + * headers may result in buffer overflows or unreliable error detection through errno. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-2-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +predicate isBannedStringFunction(Function f) { + f.hasGlobalName([ + "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn", + "strerror", "strlen", "strncat", "strncmp", "strncpy", "strpbrk", + "strrchr", "strspn", "strstr", "strtok", "strxfrm", + "strtol", "strtoll", "strtoul", "strtoull", "strtod", "strtof", "strtold", + "fgetwc", "fputwc", "wcstol", "wcstoll", "wcstoul", "wcstoull", + "wcstod", "wcstof", "wcstold", + "strtoumax", "strtoimax", "wcstoumax", "wcstoimax" + ]) +} + +from Expr e, Function f, string msg +where + not isExcluded(e, BannedAPIsPackage::unsafeStringHandlingFunctionsQuery()) and + ( + (e.(FunctionCall).getTarget() = f and isBannedStringFunction(f) and + msg = "Call to banned string handling function '" + f.getName() + "'.") + or + (e.(AddressOfExpr).getOperand().(FunctionAccess).getTarget() = f and isBannedStringFunction(f) and + msg = "Address taken of banned string handling function '" + f.getName() + "'.") + or + (e.(FunctionAccess).getTarget() = f and isBannedStringFunction(f) and + not e.getParent() instanceof FunctionCall and + not e.getParent() instanceof AddressOfExpr and + msg = "Reference to banned string handling function '" + f.getName() + "'.") + ) +select e, msg \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected new file mode 100644 index 000000000..29e347add --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected @@ -0,0 +1,222 @@ +| test.cpp:16:3:16:8 | call to strcat | Call to banned string handling function 'strcat'. | +| test.cpp:17:3:17:8 | call to strchr | Call to banned string handling function 'strchr'. | +| test.cpp:18:3:18:8 | call to strcmp | Call to banned string handling function 'strcmp'. | +| test.cpp:19:3:19:9 | call to strcoll | Call to banned string handling function 'strcoll'. | +| test.cpp:20:3:20:8 | call to strcpy | Call to banned string handling function 'strcpy'. | +| test.cpp:21:3:21:9 | call to strcspn | Call to banned string handling function 'strcspn'. | +| test.cpp:22:3:22:10 | call to strerror | Call to banned string handling function 'strerror'. | +| test.cpp:23:3:23:8 | call to strlen | Call to banned string handling function 'strlen'. | +| test.cpp:24:3:24:9 | call to strncat | Call to banned string handling function 'strncat'. | +| test.cpp:25:3:25:9 | call to strncmp | Call to banned string handling function 'strncmp'. | +| test.cpp:26:3:26:9 | call to strncpy | Call to banned string handling function 'strncpy'. | +| test.cpp:27:3:27:9 | call to strpbrk | Call to banned string handling function 'strpbrk'. | +| test.cpp:28:3:28:9 | call to strrchr | Call to banned string handling function 'strrchr'. | +| test.cpp:29:3:29:8 | call to strspn | Call to banned string handling function 'strspn'. | +| test.cpp:30:3:30:8 | call to strstr | Call to banned string handling function 'strstr'. | +| test.cpp:31:3:31:8 | call to strtok | Call to banned string handling function 'strtok'. | +| test.cpp:32:3:32:9 | call to strxfrm | Call to banned string handling function 'strxfrm'. | +| test.cpp:39:3:39:8 | call to strtol | Call to banned string handling function 'strtol'. | +| test.cpp:40:3:40:9 | call to strtoll | Call to banned string handling function 'strtoll'. | +| test.cpp:41:3:41:9 | call to strtoul | Call to banned string handling function 'strtoul'. | +| test.cpp:42:3:42:10 | call to strtoull | Call to banned string handling function 'strtoull'. | +| test.cpp:43:3:43:8 | call to strtod | Call to banned string handling function 'strtod'. | +| test.cpp:44:3:44:8 | call to strtof | Call to banned string handling function 'strtof'. | +| test.cpp:45:3:45:9 | call to strtold | Call to banned string handling function 'strtold'. | +| test.cpp:54:3:54:8 | call to fgetwc | Call to banned string handling function 'fgetwc'. | +| test.cpp:55:3:55:8 | call to fputwc | Call to banned string handling function 'fputwc'. | +| test.cpp:56:3:56:8 | call to wcstol | Call to banned string handling function 'wcstol'. | +| test.cpp:57:3:57:9 | call to wcstoll | Call to banned string handling function 'wcstoll'. | +| test.cpp:58:3:58:9 | call to wcstoul | Call to banned string handling function 'wcstoul'. | +| test.cpp:59:3:59:10 | call to wcstoull | Call to banned string handling function 'wcstoull'. | +| test.cpp:60:3:60:8 | call to wcstod | Call to banned string handling function 'wcstod'. | +| test.cpp:61:3:61:8 | call to wcstof | Call to banned string handling function 'wcstof'. | +| test.cpp:62:3:62:9 | call to wcstold | Call to banned string handling function 'wcstold'. | +| test.cpp:71:3:71:11 | call to strtoumax | Call to banned string handling function 'strtoumax'. | +| test.cpp:72:3:72:11 | call to strtoimax | Call to banned string handling function 'strtoimax'. | +| test.cpp:73:3:73:11 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | +| test.cpp:74:3:74:11 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | +| test.cpp:78:39:78:45 | & ... | Address taken of banned string handling function 'strcat'. | +| test.cpp:79:39:79:44 | strcat | Reference to banned string handling function 'strcat'. | +| test.cpp:80:42:80:48 | & ... | Address taken of banned string handling function 'strchr'. | +| test.cpp:81:42:81:47 | strchr | Reference to banned string handling function 'strchr'. | +| test.cpp:82:43:82:49 | & ... | Address taken of banned string handling function 'strcmp'. | +| test.cpp:83:43:83:48 | strcmp | Reference to banned string handling function 'strcmp'. | +| test.cpp:84:43:84:50 | & ... | Address taken of banned string handling function 'strcoll'. | +| test.cpp:85:43:85:49 | strcoll | Reference to banned string handling function 'strcoll'. | +| test.cpp:86:39:86:45 | & ... | Address taken of banned string handling function 'strcpy'. | +| test.cpp:87:40:87:45 | strcpy | Reference to banned string handling function 'strcpy'. | +| test.cpp:88:47:88:54 | & ... | Address taken of banned string handling function 'strcspn'. | +| test.cpp:89:47:89:53 | strcspn | Reference to banned string handling function 'strcspn'. | +| test.cpp:90:23:90:31 | & ... | Address taken of banned string handling function 'strerror'. | +| test.cpp:91:23:91:30 | strerror | Reference to banned string handling function 'strerror'. | +| test.cpp:92:33:92:39 | & ... | Address taken of banned string handling function 'strlen'. | +| test.cpp:93:33:93:38 | strlen | Reference to banned string handling function 'strlen'. | +| test.cpp:94:48:94:55 | & ... | Address taken of banned string handling function 'strncat'. | +| test.cpp:95:48:95:54 | strncat | Reference to banned string handling function 'strncat'. | +| test.cpp:96:52:96:59 | & ... | Address taken of banned string handling function 'strncmp'. | +| test.cpp:97:52:97:58 | strncmp | Reference to banned string handling function 'strncmp'. | +| test.cpp:98:48:98:55 | & ... | Address taken of banned string handling function 'strncpy'. | +| test.cpp:99:48:99:54 | strncpy | Reference to banned string handling function 'strncpy'. | +| test.cpp:100:52:100:59 | & ... | Address taken of banned string handling function 'strpbrk'. | +| test.cpp:101:52:101:58 | strpbrk | Reference to banned string handling function 'strpbrk'. | +| test.cpp:102:43:102:50 | & ... | Address taken of banned string handling function 'strrchr'. | +| test.cpp:103:43:103:49 | strrchr | Reference to banned string handling function 'strrchr'. | +| test.cpp:104:47:104:53 | & ... | Address taken of banned string handling function 'strspn'. | +| test.cpp:105:47:105:52 | strspn | Reference to banned string handling function 'strspn'. | +| test.cpp:106:52:106:58 | & ... | Address taken of banned string handling function 'strstr'. | +| test.cpp:107:52:107:57 | strstr | Reference to banned string handling function 'strstr'. | +| test.cpp:108:40:108:46 | & ... | Address taken of banned string handling function 'strtok'. | +| test.cpp:109:40:109:45 | strtok | Reference to banned string handling function 'strtok'. | +| test.cpp:110:49:110:56 | & ... | Address taken of banned string handling function 'strxfrm'. | +| test.cpp:111:49:111:55 | strxfrm | Reference to banned string handling function 'strxfrm'. | +| test.cpp:115:44:115:50 | & ... | Address taken of banned string handling function 'strtol'. | +| test.cpp:116:44:116:49 | strtol | Reference to banned string handling function 'strtol'. | +| test.cpp:117:49:117:56 | & ... | Address taken of banned string handling function 'strtoll'. | +| test.cpp:118:49:118:55 | strtoll | Reference to banned string handling function 'strtoll'. | +| test.cpp:119:53:119:60 | & ... | Address taken of banned string handling function 'strtoul'. | +| test.cpp:120:53:120:59 | strtoul | Reference to banned string handling function 'strtoul'. | +| test.cpp:122:7:122:15 | & ... | Address taken of banned string handling function 'strtoull'. | +| test.cpp:124:7:124:14 | strtoull | Reference to banned string handling function 'strtoull'. | +| test.cpp:125:41:125:47 | & ... | Address taken of banned string handling function 'strtod'. | +| test.cpp:126:42:126:47 | strtod | Reference to banned string handling function 'strtod'. | +| test.cpp:127:41:127:47 | & ... | Address taken of banned string handling function 'strtof'. | +| test.cpp:128:41:128:46 | strtof | Reference to banned string handling function 'strtof'. | +| test.cpp:129:47:129:54 | & ... | Address taken of banned string handling function 'strtold'. | +| test.cpp:130:47:130:53 | strtold | Reference to banned string handling function 'strtold'. | +| test.cpp:134:26:134:32 | & ... | Address taken of banned string handling function 'fgetwc'. | +| test.cpp:135:26:135:31 | fgetwc | Reference to banned string handling function 'fgetwc'. | +| test.cpp:136:35:136:41 | & ... | Address taken of banned string handling function 'fputwc'. | +| test.cpp:137:35:137:40 | fputwc | Reference to banned string handling function 'fputwc'. | +| test.cpp:138:50:138:56 | & ... | Address taken of banned string handling function 'wcstol'. | +| test.cpp:139:50:139:55 | wcstol | Reference to banned string handling function 'wcstol'. | +| test.cpp:140:55:140:62 | & ... | Address taken of banned string handling function 'wcstoll'. | +| test.cpp:141:55:141:61 | wcstoll | Reference to banned string handling function 'wcstoll'. | +| test.cpp:143:7:143:14 | & ... | Address taken of banned string handling function 'wcstoul'. | +| test.cpp:145:7:145:13 | wcstoul | Reference to banned string handling function 'wcstoul'. | +| test.cpp:147:7:147:15 | & ... | Address taken of banned string handling function 'wcstoull'. | +| test.cpp:149:7:149:14 | wcstoull | Reference to banned string handling function 'wcstoull'. | +| test.cpp:150:48:150:54 | & ... | Address taken of banned string handling function 'wcstod'. | +| test.cpp:151:48:151:53 | wcstod | Reference to banned string handling function 'wcstod'. | +| test.cpp:152:47:152:53 | & ... | Address taken of banned string handling function 'wcstof'. | +| test.cpp:153:47:153:52 | wcstof | Reference to banned string handling function 'wcstof'. | +| test.cpp:154:53:154:60 | & ... | Address taken of banned string handling function 'wcstold'. | +| test.cpp:155:53:155:59 | wcstold | Reference to banned string handling function 'wcstold'. | +| test.cpp:159:49:159:58 | & ... | Address taken of banned string handling function 'strtoumax'. | +| test.cpp:160:49:160:57 | strtoumax | Reference to banned string handling function 'strtoumax'. | +| test.cpp:161:48:161:57 | & ... | Address taken of banned string handling function 'strtoimax'. | +| test.cpp:162:48:162:56 | strtoimax | Reference to banned string handling function 'strtoimax'. | +| test.cpp:164:7:164:16 | & ... | Address taken of banned string handling function 'wcstoumax'. | +| test.cpp:166:7:166:15 | wcstoumax | Reference to banned string handling function 'wcstoumax'. | +| test.cpp:168:7:168:16 | & ... | Address taken of banned string handling function 'wcstoimax'. | +| test.cpp:169:54:169:62 | wcstoimax | Reference to banned string handling function 'wcstoimax'. | +| test.cpp:177:3:177:13 | call to strcat | Call to banned string handling function 'strcat'. | +| test.cpp:178:3:178:13 | call to strchr | Call to banned string handling function 'strchr'. | +| test.cpp:179:3:179:13 | call to strcmp | Call to banned string handling function 'strcmp'. | +| test.cpp:180:3:180:14 | call to strcoll | Call to banned string handling function 'strcoll'. | +| test.cpp:181:3:181:13 | call to strcpy | Call to banned string handling function 'strcpy'. | +| test.cpp:182:3:182:14 | call to strcspn | Call to banned string handling function 'strcspn'. | +| test.cpp:183:3:183:15 | call to strerror | Call to banned string handling function 'strerror'. | +| test.cpp:184:3:184:13 | call to strlen | Call to banned string handling function 'strlen'. | +| test.cpp:185:3:185:14 | call to strncat | Call to banned string handling function 'strncat'. | +| test.cpp:186:3:186:14 | call to strncmp | Call to banned string handling function 'strncmp'. | +| test.cpp:187:3:187:14 | call to strncpy | Call to banned string handling function 'strncpy'. | +| test.cpp:188:3:188:14 | call to strpbrk | Call to banned string handling function 'strpbrk'. | +| test.cpp:189:3:189:14 | call to strrchr | Call to banned string handling function 'strrchr'. | +| test.cpp:190:3:190:13 | call to strspn | Call to banned string handling function 'strspn'. | +| test.cpp:191:3:191:13 | call to strstr | Call to banned string handling function 'strstr'. | +| test.cpp:192:3:192:13 | call to strtok | Call to banned string handling function 'strtok'. | +| test.cpp:193:3:193:14 | call to strxfrm | Call to banned string handling function 'strxfrm'. | +| test.cpp:200:3:200:13 | call to strtol | Call to banned string handling function 'strtol'. | +| test.cpp:201:3:201:14 | call to strtoll | Call to banned string handling function 'strtoll'. | +| test.cpp:202:3:202:14 | call to strtoul | Call to banned string handling function 'strtoul'. | +| test.cpp:203:3:203:15 | call to strtoull | Call to banned string handling function 'strtoull'. | +| test.cpp:204:3:204:13 | call to strtod | Call to banned string handling function 'strtod'. | +| test.cpp:205:3:205:13 | call to strtof | Call to banned string handling function 'strtof'. | +| test.cpp:206:3:206:14 | call to strtold | Call to banned string handling function 'strtold'. | +| test.cpp:215:3:215:13 | call to fgetwc | Call to banned string handling function 'fgetwc'. | +| test.cpp:216:3:216:13 | call to fputwc | Call to banned string handling function 'fputwc'. | +| test.cpp:217:3:217:13 | call to wcstol | Call to banned string handling function 'wcstol'. | +| test.cpp:218:3:218:14 | call to wcstoll | Call to banned string handling function 'wcstoll'. | +| test.cpp:219:3:219:14 | call to wcstoul | Call to banned string handling function 'wcstoul'. | +| test.cpp:220:3:220:15 | call to wcstoull | Call to banned string handling function 'wcstoull'. | +| test.cpp:221:3:221:13 | call to wcstod | Call to banned string handling function 'wcstod'. | +| test.cpp:222:3:222:13 | call to wcstof | Call to banned string handling function 'wcstof'. | +| test.cpp:223:3:223:14 | call to wcstold | Call to banned string handling function 'wcstold'. | +| test.cpp:232:3:232:16 | call to strtoumax | Call to banned string handling function 'strtoumax'. | +| test.cpp:233:3:233:16 | call to strtoimax | Call to banned string handling function 'strtoimax'. | +| test.cpp:234:3:234:16 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | +| test.cpp:235:3:235:16 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | +| test.cpp:239:39:239:50 | & ... | Address taken of banned string handling function 'strcat'. | +| test.cpp:240:39:240:49 | strcat | Reference to banned string handling function 'strcat'. | +| test.cpp:241:42:241:53 | & ... | Address taken of banned string handling function 'strchr'. | +| test.cpp:242:42:242:52 | strchr | Reference to banned string handling function 'strchr'. | +| test.cpp:243:43:243:54 | & ... | Address taken of banned string handling function 'strcmp'. | +| test.cpp:244:43:244:53 | strcmp | Reference to banned string handling function 'strcmp'. | +| test.cpp:245:43:245:55 | & ... | Address taken of banned string handling function 'strcoll'. | +| test.cpp:246:43:246:54 | strcoll | Reference to banned string handling function 'strcoll'. | +| test.cpp:247:39:247:50 | & ... | Address taken of banned string handling function 'strcpy'. | +| test.cpp:248:40:248:50 | strcpy | Reference to banned string handling function 'strcpy'. | +| test.cpp:249:47:249:59 | & ... | Address taken of banned string handling function 'strcspn'. | +| test.cpp:250:47:250:58 | strcspn | Reference to banned string handling function 'strcspn'. | +| test.cpp:251:23:251:36 | & ... | Address taken of banned string handling function 'strerror'. | +| test.cpp:252:23:252:35 | strerror | Reference to banned string handling function 'strerror'. | +| test.cpp:253:33:253:44 | & ... | Address taken of banned string handling function 'strlen'. | +| test.cpp:254:33:254:43 | strlen | Reference to banned string handling function 'strlen'. | +| test.cpp:255:48:255:60 | & ... | Address taken of banned string handling function 'strncat'. | +| test.cpp:256:48:256:59 | strncat | Reference to banned string handling function 'strncat'. | +| test.cpp:258:7:258:19 | & ... | Address taken of banned string handling function 'strncmp'. | +| test.cpp:260:7:260:18 | strncmp | Reference to banned string handling function 'strncmp'. | +| test.cpp:261:48:261:60 | & ... | Address taken of banned string handling function 'strncpy'. | +| test.cpp:262:48:262:59 | strncpy | Reference to banned string handling function 'strncpy'. | +| test.cpp:264:7:264:19 | & ... | Address taken of banned string handling function 'strpbrk'. | +| test.cpp:266:7:266:18 | strpbrk | Reference to banned string handling function 'strpbrk'. | +| test.cpp:267:43:267:55 | & ... | Address taken of banned string handling function 'strrchr'. | +| test.cpp:268:43:268:54 | strrchr | Reference to banned string handling function 'strrchr'. | +| test.cpp:269:47:269:58 | & ... | Address taken of banned string handling function 'strspn'. | +| test.cpp:270:47:270:57 | strspn | Reference to banned string handling function 'strspn'. | +| test.cpp:272:7:272:18 | & ... | Address taken of banned string handling function 'strstr'. | +| test.cpp:273:52:273:62 | strstr | Reference to banned string handling function 'strstr'. | +| test.cpp:274:40:274:51 | & ... | Address taken of banned string handling function 'strtok'. | +| test.cpp:275:40:275:50 | strtok | Reference to banned string handling function 'strtok'. | +| test.cpp:276:49:276:61 | & ... | Address taken of banned string handling function 'strxfrm'. | +| test.cpp:277:49:277:60 | strxfrm | Reference to banned string handling function 'strxfrm'. | +| test.cpp:281:44:281:55 | & ... | Address taken of banned string handling function 'strtol'. | +| test.cpp:282:44:282:54 | strtol | Reference to banned string handling function 'strtol'. | +| test.cpp:283:49:283:61 | & ... | Address taken of banned string handling function 'strtoll'. | +| test.cpp:284:49:284:60 | strtoll | Reference to banned string handling function 'strtoll'. | +| test.cpp:286:7:286:19 | & ... | Address taken of banned string handling function 'strtoul'. | +| test.cpp:288:7:288:18 | strtoul | Reference to banned string handling function 'strtoul'. | +| test.cpp:290:7:290:20 | & ... | Address taken of banned string handling function 'strtoull'. | +| test.cpp:292:7:292:19 | strtoull | Reference to banned string handling function 'strtoull'. | +| test.cpp:293:41:293:52 | & ... | Address taken of banned string handling function 'strtod'. | +| test.cpp:294:42:294:52 | strtod | Reference to banned string handling function 'strtod'. | +| test.cpp:295:41:295:52 | & ... | Address taken of banned string handling function 'strtof'. | +| test.cpp:296:41:296:51 | strtof | Reference to banned string handling function 'strtof'. | +| test.cpp:297:47:297:59 | & ... | Address taken of banned string handling function 'strtold'. | +| test.cpp:298:47:298:58 | strtold | Reference to banned string handling function 'strtold'. | +| test.cpp:302:26:302:37 | & ... | Address taken of banned string handling function 'fgetwc'. | +| test.cpp:303:26:303:36 | fgetwc | Reference to banned string handling function 'fgetwc'. | +| test.cpp:304:35:304:46 | & ... | Address taken of banned string handling function 'fputwc'. | +| test.cpp:305:35:305:45 | fputwc | Reference to banned string handling function 'fputwc'. | +| test.cpp:306:50:306:61 | & ... | Address taken of banned string handling function 'wcstol'. | +| test.cpp:307:50:307:60 | wcstol | Reference to banned string handling function 'wcstol'. | +| test.cpp:309:7:309:19 | & ... | Address taken of banned string handling function 'wcstoll'. | +| test.cpp:311:7:311:18 | wcstoll | Reference to banned string handling function 'wcstoll'. | +| test.cpp:313:7:313:19 | & ... | Address taken of banned string handling function 'wcstoul'. | +| test.cpp:315:7:315:18 | wcstoul | Reference to banned string handling function 'wcstoul'. | +| test.cpp:317:7:317:20 | & ... | Address taken of banned string handling function 'wcstoull'. | +| test.cpp:319:7:319:19 | wcstoull | Reference to banned string handling function 'wcstoull'. | +| test.cpp:320:48:320:59 | & ... | Address taken of banned string handling function 'wcstod'. | +| test.cpp:321:48:321:58 | wcstod | Reference to banned string handling function 'wcstod'. | +| test.cpp:322:47:322:58 | & ... | Address taken of banned string handling function 'wcstof'. | +| test.cpp:323:47:323:57 | wcstof | Reference to banned string handling function 'wcstof'. | +| test.cpp:325:7:325:19 | & ... | Address taken of banned string handling function 'wcstold'. | +| test.cpp:327:7:327:18 | wcstold | Reference to banned string handling function 'wcstold'. | +| test.cpp:332:7:332:21 | & ... | Address taken of banned string handling function 'strtoumax'. | +| test.cpp:333:49:333:62 | strtoumax | Reference to banned string handling function 'strtoumax'. | +| test.cpp:334:48:334:62 | & ... | Address taken of banned string handling function 'strtoimax'. | +| test.cpp:335:48:335:61 | strtoimax | Reference to banned string handling function 'strtoimax'. | +| test.cpp:337:7:337:21 | & ... | Address taken of banned string handling function 'wcstoumax'. | +| test.cpp:339:7:339:20 | wcstoumax | Reference to banned string handling function 'wcstoumax'. | +| test.cpp:341:7:341:21 | & ... | Address taken of banned string handling function 'wcstoimax'. | +| test.cpp:343:7:343:20 | wcstoimax | Reference to banned string handling function 'wcstoimax'. | diff --git a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref new file mode 100644 index 000000000..1b69df818 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref @@ -0,0 +1 @@ +rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-2/test.cpp b/cpp/misra/test/rules/RULE-21-2-2/test.cpp new file mode 100644 index 000000000..a61639e6a --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-2/test.cpp @@ -0,0 +1,367 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void test_cstring_functions() { + char l1[100]; + char l2[100]; + const char *l3 = "test"; + + strcat(l1, l2); // NON_COMPLIANT + strchr(l3, 'e'); // NON_COMPLIANT + strcmp(l1, l2); // NON_COMPLIANT + strcoll(l1, l2); // NON_COMPLIANT + strcpy(l1, l3); // NON_COMPLIANT + strcspn(l1, l2); // NON_COMPLIANT + strerror(0); // NON_COMPLIANT + strlen(l3); // NON_COMPLIANT + strncat(l1, l2, 10); // NON_COMPLIANT + strncmp(l1, l2, 10); // NON_COMPLIANT + strncpy(l1, l3, 10); // NON_COMPLIANT + strpbrk(l1, l2); // NON_COMPLIANT + strrchr(l3, 'e'); // NON_COMPLIANT + strspn(l1, l2); // NON_COMPLIANT + strstr(l1, l3); // NON_COMPLIANT + strtok(l1, l2); // NON_COMPLIANT + strxfrm(l1, l2, 50); // NON_COMPLIANT +} + +void test_cstdlib_string_functions() { + const char *l1 = "123"; + char *l2; + + strtol(l1, &l2, 10); // NON_COMPLIANT + strtoll(l1, &l2, 10); // NON_COMPLIANT + strtoul(l1, &l2, 10); // NON_COMPLIANT + strtoull(l1, &l2, 10); // NON_COMPLIANT + strtod(l1, &l2); // NON_COMPLIANT + strtof(l1, &l2); // NON_COMPLIANT + strtold(l1, &l2); // NON_COMPLIANT +} + +void test_cwchar_functions() { + wchar_t l1[100]; + const wchar_t *l2 = L"123"; + wchar_t *l3; + FILE *l4 = nullptr; + + fgetwc(l4); // NON_COMPLIANT + fputwc(L'a', l4); // NON_COMPLIANT + wcstol(l2, &l3, 10); // NON_COMPLIANT + wcstoll(l2, &l3, 10); // NON_COMPLIANT + wcstoul(l2, &l3, 10); // NON_COMPLIANT + wcstoull(l2, &l3, 10); // NON_COMPLIANT + wcstod(l2, &l3); // NON_COMPLIANT + wcstof(l2, &l3); // NON_COMPLIANT + wcstold(l2, &l3); // NON_COMPLIANT +} + +void test_cinttypes_functions() { + const char *l1 = "123"; + char *l2; + const wchar_t *l3 = L"123"; + wchar_t *l4; + + strtoumax(l1, &l2, 10); // NON_COMPLIANT + strtoimax(l1, &l2, 10); // NON_COMPLIANT + wcstoumax(l3, &l4, 10); // NON_COMPLIANT + wcstoimax(l3, &l4, 10); // NON_COMPLIANT +} + +void test_cstring_function_pointer_addresses() { + char *(*l1)(char *, const char *) = &strcat; // NON_COMPLIANT + char *(*l2)(char *, const char *) = strcat; // NON_COMPLIANT + const char *(*l3)(const char *, int) = &strchr; // NON_COMPLIANT + const char *(*l4)(const char *, int) = strchr; // NON_COMPLIANT + int (*l5)(const char *, const char *) = &strcmp; // NON_COMPLIANT + int (*l6)(const char *, const char *) = strcmp; // NON_COMPLIANT + int (*l7)(const char *, const char *) = &strcoll; // NON_COMPLIANT + int (*l8)(const char *, const char *) = strcoll; // NON_COMPLIANT + char *(*l9)(char *, const char *) = &strcpy; // NON_COMPLIANT + char *(*l10)(char *, const char *) = strcpy; // NON_COMPLIANT + size_t (*l11)(const char *, const char *) = &strcspn; // NON_COMPLIANT + size_t (*l12)(const char *, const char *) = strcspn; // NON_COMPLIANT + char *(*l13)(int) = &strerror; // NON_COMPLIANT + char *(*l14)(int) = strerror; // NON_COMPLIANT + size_t (*l15)(const char *) = &strlen; // NON_COMPLIANT + size_t (*l16)(const char *) = strlen; // NON_COMPLIANT + char *(*l17)(char *, const char *, size_t) = &strncat; // NON_COMPLIANT + char *(*l18)(char *, const char *, size_t) = strncat; // NON_COMPLIANT + int (*l19)(const char *, const char *, size_t) = &strncmp; // NON_COMPLIANT + int (*l20)(const char *, const char *, size_t) = strncmp; // NON_COMPLIANT + char *(*l21)(char *, const char *, size_t) = &strncpy; // NON_COMPLIANT + char *(*l22)(char *, const char *, size_t) = strncpy; // NON_COMPLIANT + const char *(*l23)(const char *, const char *) = &strpbrk; // NON_COMPLIANT + const char *(*l24)(const char *, const char *) = strpbrk; // NON_COMPLIANT + const char *(*l25)(const char *, int) = &strrchr; // NON_COMPLIANT + const char *(*l26)(const char *, int) = strrchr; // NON_COMPLIANT + size_t (*l27)(const char *, const char *) = &strspn; // NON_COMPLIANT + size_t (*l28)(const char *, const char *) = strspn; // NON_COMPLIANT + const char *(*l29)(const char *, const char *) = &strstr; // NON_COMPLIANT + const char *(*l30)(const char *, const char *) = strstr; // NON_COMPLIANT + char *(*l31)(char *, const char *) = &strtok; // NON_COMPLIANT + char *(*l32)(char *, const char *) = strtok; // NON_COMPLIANT + size_t (*l33)(char *, const char *, size_t) = &strxfrm; // NON_COMPLIANT + size_t (*l34)(char *, const char *, size_t) = strxfrm; // NON_COMPLIANT +} + +void test_cstdlib_function_pointer_addresses() { + long (*l1)(const char *, char **, int) = &strtol; // NON_COMPLIANT + long (*l2)(const char *, char **, int) = strtol; // NON_COMPLIANT + long long (*l3)(const char *, char **, int) = &strtoll; // NON_COMPLIANT + long long (*l4)(const char *, char **, int) = strtoll; // NON_COMPLIANT + unsigned long (*l5)(const char *, char **, int) = &strtoul; // NON_COMPLIANT + unsigned long (*l6)(const char *, char **, int) = strtoul; // NON_COMPLIANT + unsigned long long (*l7)(const char *, char **, int) = + &strtoull; // NON_COMPLIANT + unsigned long long (*l8)(const char *, char **, int) = + strtoull; // NON_COMPLIANT + double (*l9)(const char *, char **) = &strtod; // NON_COMPLIANT + double (*l10)(const char *, char **) = strtod; // NON_COMPLIANT + float (*l11)(const char *, char **) = &strtof; // NON_COMPLIANT + float (*l12)(const char *, char **) = strtof; // NON_COMPLIANT + long double (*l13)(const char *, char **) = &strtold; // NON_COMPLIANT + long double (*l14)(const char *, char **) = strtold; // NON_COMPLIANT +} + +void test_cwchar_function_pointer_addresses() { + wint_t (*l1)(FILE *) = &fgetwc; // NON_COMPLIANT + wint_t (*l2)(FILE *) = fgetwc; // NON_COMPLIANT + wint_t (*l3)(wchar_t, FILE *) = &fputwc; // NON_COMPLIANT + wint_t (*l4)(wchar_t, FILE *) = fputwc; // NON_COMPLIANT + long (*l5)(const wchar_t *, wchar_t **, int) = &wcstol; // NON_COMPLIANT + long (*l6)(const wchar_t *, wchar_t **, int) = wcstol; // NON_COMPLIANT + long long (*l7)(const wchar_t *, wchar_t **, int) = &wcstoll; // NON_COMPLIANT + long long (*l8)(const wchar_t *, wchar_t **, int) = wcstoll; // NON_COMPLIANT + unsigned long (*l9)(const wchar_t *, wchar_t **, int) = + &wcstoul; // NON_COMPLIANT + unsigned long (*l10)(const wchar_t *, wchar_t **, int) = + wcstoul; // NON_COMPLIANT + unsigned long long (*l11)(const wchar_t *, wchar_t **, int) = + &wcstoull; // NON_COMPLIANT + unsigned long long (*l12)(const wchar_t *, wchar_t **, int) = + wcstoull; // NON_COMPLIANT + double (*l13)(const wchar_t *, wchar_t **) = &wcstod; // NON_COMPLIANT + double (*l14)(const wchar_t *, wchar_t **) = wcstod; // NON_COMPLIANT + float (*l15)(const wchar_t *, wchar_t **) = &wcstof; // NON_COMPLIANT + float (*l16)(const wchar_t *, wchar_t **) = wcstof; // NON_COMPLIANT + long double (*l17)(const wchar_t *, wchar_t **) = &wcstold; // NON_COMPLIANT + long double (*l18)(const wchar_t *, wchar_t **) = wcstold; // NON_COMPLIANT +} + +void test_cinttypes_function_pointer_addresses() { + uintmax_t (*l1)(const char *, char **, int) = &strtoumax; // NON_COMPLIANT + uintmax_t (*l2)(const char *, char **, int) = strtoumax; // NON_COMPLIANT + intmax_t (*l3)(const char *, char **, int) = &strtoimax; // NON_COMPLIANT + intmax_t (*l4)(const char *, char **, int) = strtoimax; // NON_COMPLIANT + uintmax_t (*l5)(const wchar_t *, wchar_t **, int) = + &wcstoumax; // NON_COMPLIANT + uintmax_t (*l6)(const wchar_t *, wchar_t **, int) = + wcstoumax; // NON_COMPLIANT + intmax_t (*l7)(const wchar_t *, wchar_t **, int) = + &wcstoimax; // NON_COMPLIANT + intmax_t (*l8)(const wchar_t *, wchar_t **, int) = wcstoimax; // NON_COMPLIANT +} + +void test_std_cstring_functions() { + char l1[100]; + char l2[100]; + const char *l3 = "test"; + + std::strcat(l1, l2); // NON_COMPLIANT + std::strchr(l3, 'e'); // NON_COMPLIANT + std::strcmp(l1, l2); // NON_COMPLIANT + std::strcoll(l1, l2); // NON_COMPLIANT + std::strcpy(l1, l3); // NON_COMPLIANT + std::strcspn(l1, l2); // NON_COMPLIANT + std::strerror(0); // NON_COMPLIANT + std::strlen(l3); // NON_COMPLIANT + std::strncat(l1, l2, 10); // NON_COMPLIANT + std::strncmp(l1, l2, 10); // NON_COMPLIANT + std::strncpy(l1, l3, 10); // NON_COMPLIANT + std::strpbrk(l1, l2); // NON_COMPLIANT + std::strrchr(l3, 'e'); // NON_COMPLIANT + std::strspn(l1, l2); // NON_COMPLIANT + std::strstr(l1, l3); // NON_COMPLIANT + std::strtok(l1, l2); // NON_COMPLIANT + std::strxfrm(l1, l2, 50); // NON_COMPLIANT +} + +void test_std_cstdlib_string_functions() { + const char *l1 = "123"; + char *l2; + + std::strtol(l1, &l2, 10); // NON_COMPLIANT + std::strtoll(l1, &l2, 10); // NON_COMPLIANT + std::strtoul(l1, &l2, 10); // NON_COMPLIANT + std::strtoull(l1, &l2, 10); // NON_COMPLIANT + std::strtod(l1, &l2); // NON_COMPLIANT + std::strtof(l1, &l2); // NON_COMPLIANT + std::strtold(l1, &l2); // NON_COMPLIANT +} + +void test_std_cwchar_functions() { + wchar_t l1[100]; + const wchar_t *l2 = L"123"; + wchar_t *l3; + FILE *l4 = nullptr; + + std::fgetwc(l4); // NON_COMPLIANT + std::fputwc(L'a', l4); // NON_COMPLIANT + std::wcstol(l2, &l3, 10); // NON_COMPLIANT + std::wcstoll(l2, &l3, 10); // NON_COMPLIANT + std::wcstoul(l2, &l3, 10); // NON_COMPLIANT + std::wcstoull(l2, &l3, 10); // NON_COMPLIANT + std::wcstod(l2, &l3); // NON_COMPLIANT + std::wcstof(l2, &l3); // NON_COMPLIANT + std::wcstold(l2, &l3); // NON_COMPLIANT +} + +void test_std_cinttypes_functions() { + const char *l1 = "123"; + char *l2; + const wchar_t *l3 = L"123"; + wchar_t *l4; + + std::strtoumax(l1, &l2, 10); // NON_COMPLIANT + std::strtoimax(l1, &l2, 10); // NON_COMPLIANT + std::wcstoumax(l3, &l4, 10); // NON_COMPLIANT + std::wcstoimax(l3, &l4, 10); // NON_COMPLIANT +} + +void test_std_cstring_function_pointer_addresses() { + char *(*l1)(char *, const char *) = &std::strcat; // NON_COMPLIANT + char *(*l2)(char *, const char *) = std::strcat; // NON_COMPLIANT + const char *(*l3)(const char *, int) = &std::strchr; // NON_COMPLIANT + const char *(*l4)(const char *, int) = std::strchr; // NON_COMPLIANT + int (*l5)(const char *, const char *) = &std::strcmp; // NON_COMPLIANT + int (*l6)(const char *, const char *) = std::strcmp; // NON_COMPLIANT + int (*l7)(const char *, const char *) = &std::strcoll; // NON_COMPLIANT + int (*l8)(const char *, const char *) = std::strcoll; // NON_COMPLIANT + char *(*l9)(char *, const char *) = &std::strcpy; // NON_COMPLIANT + char *(*l10)(char *, const char *) = std::strcpy; // NON_COMPLIANT + size_t (*l11)(const char *, const char *) = &std::strcspn; // NON_COMPLIANT + size_t (*l12)(const char *, const char *) = std::strcspn; // NON_COMPLIANT + char *(*l13)(int) = &std::strerror; // NON_COMPLIANT + char *(*l14)(int) = std::strerror; // NON_COMPLIANT + size_t (*l15)(const char *) = &std::strlen; // NON_COMPLIANT + size_t (*l16)(const char *) = std::strlen; // NON_COMPLIANT + char *(*l17)(char *, const char *, size_t) = &std::strncat; // NON_COMPLIANT + char *(*l18)(char *, const char *, size_t) = std::strncat; // NON_COMPLIANT + int (*l19)(const char *, const char *, size_t) = + &std::strncmp; // NON_COMPLIANT + int (*l20)(const char *, const char *, size_t) = + std::strncmp; // NON_COMPLIANT + char *(*l21)(char *, const char *, size_t) = &std::strncpy; // NON_COMPLIANT + char *(*l22)(char *, const char *, size_t) = std::strncpy; // NON_COMPLIANT + const char *(*l23)(const char *, const char *) = + &std::strpbrk; // NON_COMPLIANT + const char *(*l24)(const char *, const char *) = + std::strpbrk; // NON_COMPLIANT + const char *(*l25)(const char *, int) = &std::strrchr; // NON_COMPLIANT + const char *(*l26)(const char *, int) = std::strrchr; // NON_COMPLIANT + size_t (*l27)(const char *, const char *) = &std::strspn; // NON_COMPLIANT + size_t (*l28)(const char *, const char *) = std::strspn; // NON_COMPLIANT + const char *(*l29)(const char *, const char *) = + &std::strstr; // NON_COMPLIANT + const char *(*l30)(const char *, const char *) = std::strstr; // NON_COMPLIANT + char *(*l31)(char *, const char *) = &std::strtok; // NON_COMPLIANT + char *(*l32)(char *, const char *) = std::strtok; // NON_COMPLIANT + size_t (*l33)(char *, const char *, size_t) = &std::strxfrm; // NON_COMPLIANT + size_t (*l34)(char *, const char *, size_t) = std::strxfrm; // NON_COMPLIANT +} + +void test_std_cstdlib_function_pointer_addresses() { + long (*l1)(const char *, char **, int) = &std::strtol; // NON_COMPLIANT + long (*l2)(const char *, char **, int) = std::strtol; // NON_COMPLIANT + long long (*l3)(const char *, char **, int) = &std::strtoll; // NON_COMPLIANT + long long (*l4)(const char *, char **, int) = std::strtoll; // NON_COMPLIANT + unsigned long (*l5)(const char *, char **, int) = + &std::strtoul; // NON_COMPLIANT + unsigned long (*l6)(const char *, char **, int) = + std::strtoul; // NON_COMPLIANT + unsigned long long (*l7)(const char *, char **, int) = + &std::strtoull; // NON_COMPLIANT + unsigned long long (*l8)(const char *, char **, int) = + std::strtoull; // NON_COMPLIANT + double (*l9)(const char *, char **) = &std::strtod; // NON_COMPLIANT + double (*l10)(const char *, char **) = std::strtod; // NON_COMPLIANT + float (*l11)(const char *, char **) = &std::strtof; // NON_COMPLIANT + float (*l12)(const char *, char **) = std::strtof; // NON_COMPLIANT + long double (*l13)(const char *, char **) = &std::strtold; // NON_COMPLIANT + long double (*l14)(const char *, char **) = std::strtold; // NON_COMPLIANT +} + +void test_std_cwchar_function_pointer_addresses() { + wint_t (*l1)(FILE *) = &std::fgetwc; // NON_COMPLIANT + wint_t (*l2)(FILE *) = std::fgetwc; // NON_COMPLIANT + wint_t (*l3)(wchar_t, FILE *) = &std::fputwc; // NON_COMPLIANT + wint_t (*l4)(wchar_t, FILE *) = std::fputwc; // NON_COMPLIANT + long (*l5)(const wchar_t *, wchar_t **, int) = &std::wcstol; // NON_COMPLIANT + long (*l6)(const wchar_t *, wchar_t **, int) = std::wcstol; // NON_COMPLIANT + long long (*l7)(const wchar_t *, wchar_t **, int) = + &std::wcstoll; // NON_COMPLIANT + long long (*l8)(const wchar_t *, wchar_t **, int) = + std::wcstoll; // NON_COMPLIANT + unsigned long (*l9)(const wchar_t *, wchar_t **, int) = + &std::wcstoul; // NON_COMPLIANT + unsigned long (*l10)(const wchar_t *, wchar_t **, int) = + std::wcstoul; // NON_COMPLIANT + unsigned long long (*l11)(const wchar_t *, wchar_t **, int) = + &std::wcstoull; // NON_COMPLIANT + unsigned long long (*l12)(const wchar_t *, wchar_t **, int) = + std::wcstoull; // NON_COMPLIANT + double (*l13)(const wchar_t *, wchar_t **) = &std::wcstod; // NON_COMPLIANT + double (*l14)(const wchar_t *, wchar_t **) = std::wcstod; // NON_COMPLIANT + float (*l15)(const wchar_t *, wchar_t **) = &std::wcstof; // NON_COMPLIANT + float (*l16)(const wchar_t *, wchar_t **) = std::wcstof; // NON_COMPLIANT + long double (*l17)(const wchar_t *, wchar_t **) = + &std::wcstold; // NON_COMPLIANT + long double (*l18)(const wchar_t *, wchar_t **) = + std::wcstold; // NON_COMPLIANT +} + +void test_std_cinttypes_function_pointer_addresses() { + uintmax_t (*l1)(const char *, char **, int) = + &std::strtoumax; // NON_COMPLIANT + uintmax_t (*l2)(const char *, char **, int) = std::strtoumax; // NON_COMPLIANT + intmax_t (*l3)(const char *, char **, int) = &std::strtoimax; // NON_COMPLIANT + intmax_t (*l4)(const char *, char **, int) = std::strtoimax; // NON_COMPLIANT + uintmax_t (*l5)(const wchar_t *, wchar_t **, int) = + &std::wcstoumax; // NON_COMPLIANT + uintmax_t (*l6)(const wchar_t *, wchar_t **, int) = + std::wcstoumax; // NON_COMPLIANT + intmax_t (*l7)(const wchar_t *, wchar_t **, int) = + &std::wcstoimax; // NON_COMPLIANT + intmax_t (*l8)(const wchar_t *, wchar_t **, int) = + std::wcstoimax; // NON_COMPLIANT +} + +void test_compliant_alternatives() { + char l1[100]; + const char *l2 = "test"; + std::size_t l3 = 50; + + // Using std::string_view instead of strlen + std::string_view l4 = l2; + if (l4.size() + 1u < l3) { // COMPLIANT + l4.copy(l1, l4.size()); // COMPLIANT + l1[l4.size()] = 0; // COMPLIANT + } + + // Using std::string for string operations + std::string l5 = "hello"; + std::string l6 = "world"; + std::string l7 = l5 + l6; // COMPLIANT + + // Using standard library numeric conversions + std::string l8 = "123"; + std::int32_t l9 = std::stoi(l8); // COMPLIANT + double l10 = std::stod(l8); // COMPLIANT +} \ No newline at end of file From c6077982efa4121997a8e99116a257e647d2b4e2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 14:49:54 +0100 Subject: [PATCH 17/36] Add a library to support the detection of banned functions This supports accurate detection of usage of banned functions: - Detects both accesses and calls - Reports the macro definition if the use is within a macro defined in the users code. - Otherwise reports the location of the expression. --- .../codingstandards/cpp/BannedFunctions.qll | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/BannedFunctions.qll diff --git a/cpp/common/src/codingstandards/cpp/BannedFunctions.qll b/cpp/common/src/codingstandards/cpp/BannedFunctions.qll new file mode 100644 index 000000000..174d0a843 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/BannedFunctions.qll @@ -0,0 +1,69 @@ +/** + * A library for supporting the consistent detection of banned functions in C++ code. + */ + +import cpp +import AlertReporting + +/** + * A signature for a banned function. + */ +signature class BannedFunction extends Function; + +/** + * A module for detecting uses of banned functions in C++ code. + */ +module BannedFunctions { + final private class FinalExpr = Expr; + + /** + * An expression that uses a banned function. + * + * It can be either a function call or a function access (taking the address of the function). + */ + class UseExpr extends FinalExpr { + string action; + F bannedFunction; + + UseExpr() { + this.(FunctionCall).getTarget() = bannedFunction and + action = "Call to" + or + this.(FunctionAccess).getTarget() = bannedFunction and + action = "Address taken for" + } + + string getFunctionName() { result = bannedFunction.getName() } + + string getAction() { result = action } + + Element getPrimaryElement() { + // If this is defined in a macro in the users source location, then report the macro + // expansion, otherwise report the element itself. This ensures that we always report + // the use of the terminating function, but combine usages when the macro is defined + // by the user. + exists(Element e | e = MacroUnwrapper::unwrapElement(this) | + if exists(e.getFile().getRelativePath()) then result = e else result = this + ) + } + } + + final private class FinalElement = Element; + + /** + * A `Use` of a banned function. + * + * This is an `Element` in a program which represents the use of a banned function. + * For uses within macro expansions, this may report the location of the macro, if + * it is defined within the user's source code. + */ + class Use extends FinalElement { + UseExpr use; + + Use() { this = use.getPrimaryElement() } + + string getFunctionName() { result = use.getFunctionName() } + + string getAction() { result = use.getAction() } + } +} From 7a28f0264163870bf08d27866a1fdc8ab6f625ce Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 14:52:18 +0100 Subject: [PATCH 18/36] Rule 18.5.2 - Use BannedFunctions library Use library to avoid duplication. --- .../AvoidProgramTerminatingFunctions.ql | 44 +++---------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql index c262030c9..adafebd44 100644 --- a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql +++ b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql @@ -16,55 +16,25 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.AlertReporting +import codingstandards.cpp.BannedFunctions -predicate isTerminatingFunction(Function f, string functionName) { - functionName = f.getName() and - ( - functionName in ["abort", "exit", "_Exit", "quick_exit"] and - (f.hasQualifiedName("", functionName) or f.hasQualifiedName("std", functionName)) +class TerminatingFunction extends Function { + TerminatingFunction() { + this.hasQualifiedName(["", "std"], ["abort", "exit", "_Exit", "quick_exit"]) or // std::terminate does not occur in the global namespace. - functionName = "terminate" and f.hasQualifiedName("std", functionName) - ) -} - -class TerminatingFunctionUse extends Expr { - string action; - string functionName; - - TerminatingFunctionUse() { - exists(Function f | isTerminatingFunction(f, functionName) | - this.(FunctionCall).getTarget() = f and - action = "Call to" - or - this.(FunctionAccess).getTarget() = f and - action = "Address taken for" - ) - } - - string getFunctionName() { result = functionName } - - string getAction() { result = action } - - Element getPrimaryElement() { - // If this is defined in a macro in the users source location, then report the macro - // expansion, otherwise report the element itself. This ensures that we always report - // the use of the terminating function, but combine usages when the macro is defined - // by the user. - exists(Element e | e = MacroUnwrapper::unwrapElement(this) | - if exists(e.getFile().getRelativePath()) then result = e else result = this - ) + this.hasQualifiedName("std", "terminate") } } -predicate isInAssertMacroInvocation(TerminatingFunctionUse use) { +predicate isInAssertMacroInvocation(BannedFunctions::UseExpr use) { exists(MacroInvocation mi | mi.getMacroName() = "assert" and mi.getAnExpandedElement() = use ) } -from TerminatingFunctionUse use +from BannedFunctions::UseExpr use where not isExcluded(use, BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery()) and // Exclude the uses in the assert macro From 7fa6646738101ce0f6625a5b64953f9a279d407b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 14:52:43 +0100 Subject: [PATCH 19/36] Rule 21.2.2 - use BannedFunction library --- .../UnsafeStringHandlingFunctions.ql | 40 +-- .../UnsafeStringHandlingFunctions.expected | 296 +++++++++--------- 2 files changed, 162 insertions(+), 174 deletions(-) diff --git a/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql index 6a2638d21..ff888c9c2 100644 --- a/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql +++ b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql @@ -14,32 +14,20 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions -predicate isBannedStringFunction(Function f) { - f.hasGlobalName([ - "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn", - "strerror", "strlen", "strncat", "strncmp", "strncpy", "strpbrk", - "strrchr", "strspn", "strstr", "strtok", "strxfrm", - "strtol", "strtoll", "strtoul", "strtoull", "strtod", "strtof", "strtold", - "fgetwc", "fputwc", "wcstol", "wcstoll", "wcstoul", "wcstoull", - "wcstod", "wcstof", "wcstold", - "strtoumax", "strtoimax", "wcstoumax", "wcstoimax" - ]) +class StringFunction extends Function { + StringFunction() { + this.hasGlobalName([ + "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn", "strerror", "strlen", + "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn", "strstr", "strtok", + "strxfrm", "strtol", "strtoll", "strtoul", "strtoull", "strtod", "strtof", "strtold", + "fgetwc", "fputwc", "wcstol", "wcstoll", "wcstoul", "wcstoull", "wcstod", "wcstof", + "wcstold", "strtoumax", "strtoimax", "wcstoumax", "wcstoimax" + ]) + } } -from Expr e, Function f, string msg -where - not isExcluded(e, BannedAPIsPackage::unsafeStringHandlingFunctionsQuery()) and - ( - (e.(FunctionCall).getTarget() = f and isBannedStringFunction(f) and - msg = "Call to banned string handling function '" + f.getName() + "'.") - or - (e.(AddressOfExpr).getOperand().(FunctionAccess).getTarget() = f and isBannedStringFunction(f) and - msg = "Address taken of banned string handling function '" + f.getName() + "'.") - or - (e.(FunctionAccess).getTarget() = f and isBannedStringFunction(f) and - not e.getParent() instanceof FunctionCall and - not e.getParent() instanceof AddressOfExpr and - msg = "Reference to banned string handling function '" + f.getName() + "'.") - ) -select e, msg \ No newline at end of file +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::unsafeStringHandlingFunctionsQuery()) +select use, use.getAction() + " banned string handling function '" + use.getFunctionName() + "'." diff --git a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected index 29e347add..fc0efb103 100644 --- a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected +++ b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected @@ -35,80 +35,80 @@ | test.cpp:72:3:72:11 | call to strtoimax | Call to banned string handling function 'strtoimax'. | | test.cpp:73:3:73:11 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | | test.cpp:74:3:74:11 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | -| test.cpp:78:39:78:45 | & ... | Address taken of banned string handling function 'strcat'. | -| test.cpp:79:39:79:44 | strcat | Reference to banned string handling function 'strcat'. | -| test.cpp:80:42:80:48 | & ... | Address taken of banned string handling function 'strchr'. | -| test.cpp:81:42:81:47 | strchr | Reference to banned string handling function 'strchr'. | -| test.cpp:82:43:82:49 | & ... | Address taken of banned string handling function 'strcmp'. | -| test.cpp:83:43:83:48 | strcmp | Reference to banned string handling function 'strcmp'. | -| test.cpp:84:43:84:50 | & ... | Address taken of banned string handling function 'strcoll'. | -| test.cpp:85:43:85:49 | strcoll | Reference to banned string handling function 'strcoll'. | -| test.cpp:86:39:86:45 | & ... | Address taken of banned string handling function 'strcpy'. | -| test.cpp:87:40:87:45 | strcpy | Reference to banned string handling function 'strcpy'. | -| test.cpp:88:47:88:54 | & ... | Address taken of banned string handling function 'strcspn'. | -| test.cpp:89:47:89:53 | strcspn | Reference to banned string handling function 'strcspn'. | -| test.cpp:90:23:90:31 | & ... | Address taken of banned string handling function 'strerror'. | -| test.cpp:91:23:91:30 | strerror | Reference to banned string handling function 'strerror'. | -| test.cpp:92:33:92:39 | & ... | Address taken of banned string handling function 'strlen'. | -| test.cpp:93:33:93:38 | strlen | Reference to banned string handling function 'strlen'. | -| test.cpp:94:48:94:55 | & ... | Address taken of banned string handling function 'strncat'. | -| test.cpp:95:48:95:54 | strncat | Reference to banned string handling function 'strncat'. | -| test.cpp:96:52:96:59 | & ... | Address taken of banned string handling function 'strncmp'. | -| test.cpp:97:52:97:58 | strncmp | Reference to banned string handling function 'strncmp'. | -| test.cpp:98:48:98:55 | & ... | Address taken of banned string handling function 'strncpy'. | -| test.cpp:99:48:99:54 | strncpy | Reference to banned string handling function 'strncpy'. | -| test.cpp:100:52:100:59 | & ... | Address taken of banned string handling function 'strpbrk'. | -| test.cpp:101:52:101:58 | strpbrk | Reference to banned string handling function 'strpbrk'. | -| test.cpp:102:43:102:50 | & ... | Address taken of banned string handling function 'strrchr'. | -| test.cpp:103:43:103:49 | strrchr | Reference to banned string handling function 'strrchr'. | -| test.cpp:104:47:104:53 | & ... | Address taken of banned string handling function 'strspn'. | -| test.cpp:105:47:105:52 | strspn | Reference to banned string handling function 'strspn'. | -| test.cpp:106:52:106:58 | & ... | Address taken of banned string handling function 'strstr'. | -| test.cpp:107:52:107:57 | strstr | Reference to banned string handling function 'strstr'. | -| test.cpp:108:40:108:46 | & ... | Address taken of banned string handling function 'strtok'. | -| test.cpp:109:40:109:45 | strtok | Reference to banned string handling function 'strtok'. | -| test.cpp:110:49:110:56 | & ... | Address taken of banned string handling function 'strxfrm'. | -| test.cpp:111:49:111:55 | strxfrm | Reference to banned string handling function 'strxfrm'. | -| test.cpp:115:44:115:50 | & ... | Address taken of banned string handling function 'strtol'. | -| test.cpp:116:44:116:49 | strtol | Reference to banned string handling function 'strtol'. | -| test.cpp:117:49:117:56 | & ... | Address taken of banned string handling function 'strtoll'. | -| test.cpp:118:49:118:55 | strtoll | Reference to banned string handling function 'strtoll'. | -| test.cpp:119:53:119:60 | & ... | Address taken of banned string handling function 'strtoul'. | -| test.cpp:120:53:120:59 | strtoul | Reference to banned string handling function 'strtoul'. | -| test.cpp:122:7:122:15 | & ... | Address taken of banned string handling function 'strtoull'. | -| test.cpp:124:7:124:14 | strtoull | Reference to banned string handling function 'strtoull'. | -| test.cpp:125:41:125:47 | & ... | Address taken of banned string handling function 'strtod'. | -| test.cpp:126:42:126:47 | strtod | Reference to banned string handling function 'strtod'. | -| test.cpp:127:41:127:47 | & ... | Address taken of banned string handling function 'strtof'. | -| test.cpp:128:41:128:46 | strtof | Reference to banned string handling function 'strtof'. | -| test.cpp:129:47:129:54 | & ... | Address taken of banned string handling function 'strtold'. | -| test.cpp:130:47:130:53 | strtold | Reference to banned string handling function 'strtold'. | -| test.cpp:134:26:134:32 | & ... | Address taken of banned string handling function 'fgetwc'. | -| test.cpp:135:26:135:31 | fgetwc | Reference to banned string handling function 'fgetwc'. | -| test.cpp:136:35:136:41 | & ... | Address taken of banned string handling function 'fputwc'. | -| test.cpp:137:35:137:40 | fputwc | Reference to banned string handling function 'fputwc'. | -| test.cpp:138:50:138:56 | & ... | Address taken of banned string handling function 'wcstol'. | -| test.cpp:139:50:139:55 | wcstol | Reference to banned string handling function 'wcstol'. | -| test.cpp:140:55:140:62 | & ... | Address taken of banned string handling function 'wcstoll'. | -| test.cpp:141:55:141:61 | wcstoll | Reference to banned string handling function 'wcstoll'. | -| test.cpp:143:7:143:14 | & ... | Address taken of banned string handling function 'wcstoul'. | -| test.cpp:145:7:145:13 | wcstoul | Reference to banned string handling function 'wcstoul'. | -| test.cpp:147:7:147:15 | & ... | Address taken of banned string handling function 'wcstoull'. | -| test.cpp:149:7:149:14 | wcstoull | Reference to banned string handling function 'wcstoull'. | -| test.cpp:150:48:150:54 | & ... | Address taken of banned string handling function 'wcstod'. | -| test.cpp:151:48:151:53 | wcstod | Reference to banned string handling function 'wcstod'. | -| test.cpp:152:47:152:53 | & ... | Address taken of banned string handling function 'wcstof'. | -| test.cpp:153:47:153:52 | wcstof | Reference to banned string handling function 'wcstof'. | -| test.cpp:154:53:154:60 | & ... | Address taken of banned string handling function 'wcstold'. | -| test.cpp:155:53:155:59 | wcstold | Reference to banned string handling function 'wcstold'. | -| test.cpp:159:49:159:58 | & ... | Address taken of banned string handling function 'strtoumax'. | -| test.cpp:160:49:160:57 | strtoumax | Reference to banned string handling function 'strtoumax'. | -| test.cpp:161:48:161:57 | & ... | Address taken of banned string handling function 'strtoimax'. | -| test.cpp:162:48:162:56 | strtoimax | Reference to banned string handling function 'strtoimax'. | -| test.cpp:164:7:164:16 | & ... | Address taken of banned string handling function 'wcstoumax'. | -| test.cpp:166:7:166:15 | wcstoumax | Reference to banned string handling function 'wcstoumax'. | -| test.cpp:168:7:168:16 | & ... | Address taken of banned string handling function 'wcstoimax'. | -| test.cpp:169:54:169:62 | wcstoimax | Reference to banned string handling function 'wcstoimax'. | +| test.cpp:78:40:78:45 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:79:39:79:44 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:80:42:80:48 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:81:42:81:47 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:82:44:82:49 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:83:43:83:48 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:84:44:84:50 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:85:43:85:49 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:86:40:86:45 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:87:40:87:45 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:88:48:88:54 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:89:47:89:53 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:90:24:90:31 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:91:23:91:30 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:92:34:92:39 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:93:33:93:38 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:94:49:94:55 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:95:48:95:54 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:96:53:96:59 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:97:52:97:58 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:98:49:98:55 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:99:48:99:54 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:100:52:100:59 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:101:52:101:58 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:102:43:102:50 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:103:43:103:49 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:104:48:104:53 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:105:47:105:52 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:106:52:106:58 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:107:52:107:57 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:108:41:108:46 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:109:40:109:45 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:110:50:110:56 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:111:49:111:55 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:115:45:115:50 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:116:44:116:49 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:117:50:117:56 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:118:49:118:55 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:119:54:119:60 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:120:53:120:59 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:122:8:122:15 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:124:7:124:14 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:125:42:125:47 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:126:42:126:47 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:127:42:127:47 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:128:41:128:46 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:129:48:129:54 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:130:47:130:53 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:134:27:134:32 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:135:26:135:31 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:136:36:136:41 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:137:35:137:40 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:138:51:138:56 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:139:50:139:55 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:140:56:140:62 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:141:55:141:61 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:143:8:143:14 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:145:7:145:13 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:147:8:147:15 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:149:7:149:14 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:150:49:150:54 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:151:48:151:53 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:152:48:152:53 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:153:47:153:52 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:154:54:154:60 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:155:53:155:59 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:159:50:159:58 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:160:49:160:57 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:161:49:161:57 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:162:48:162:56 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:164:8:164:16 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:166:7:166:15 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:168:8:168:16 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | +| test.cpp:169:54:169:62 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | | test.cpp:177:3:177:13 | call to strcat | Call to banned string handling function 'strcat'. | | test.cpp:178:3:178:13 | call to strchr | Call to banned string handling function 'strchr'. | | test.cpp:179:3:179:13 | call to strcmp | Call to banned string handling function 'strcmp'. | @@ -146,77 +146,77 @@ | test.cpp:233:3:233:16 | call to strtoimax | Call to banned string handling function 'strtoimax'. | | test.cpp:234:3:234:16 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | | test.cpp:235:3:235:16 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | -| test.cpp:239:39:239:50 | & ... | Address taken of banned string handling function 'strcat'. | -| test.cpp:240:39:240:49 | strcat | Reference to banned string handling function 'strcat'. | -| test.cpp:241:42:241:53 | & ... | Address taken of banned string handling function 'strchr'. | -| test.cpp:242:42:242:52 | strchr | Reference to banned string handling function 'strchr'. | -| test.cpp:243:43:243:54 | & ... | Address taken of banned string handling function 'strcmp'. | -| test.cpp:244:43:244:53 | strcmp | Reference to banned string handling function 'strcmp'. | -| test.cpp:245:43:245:55 | & ... | Address taken of banned string handling function 'strcoll'. | -| test.cpp:246:43:246:54 | strcoll | Reference to banned string handling function 'strcoll'. | -| test.cpp:247:39:247:50 | & ... | Address taken of banned string handling function 'strcpy'. | -| test.cpp:248:40:248:50 | strcpy | Reference to banned string handling function 'strcpy'. | -| test.cpp:249:47:249:59 | & ... | Address taken of banned string handling function 'strcspn'. | -| test.cpp:250:47:250:58 | strcspn | Reference to banned string handling function 'strcspn'. | -| test.cpp:251:23:251:36 | & ... | Address taken of banned string handling function 'strerror'. | -| test.cpp:252:23:252:35 | strerror | Reference to banned string handling function 'strerror'. | -| test.cpp:253:33:253:44 | & ... | Address taken of banned string handling function 'strlen'. | -| test.cpp:254:33:254:43 | strlen | Reference to banned string handling function 'strlen'. | -| test.cpp:255:48:255:60 | & ... | Address taken of banned string handling function 'strncat'. | -| test.cpp:256:48:256:59 | strncat | Reference to banned string handling function 'strncat'. | -| test.cpp:258:7:258:19 | & ... | Address taken of banned string handling function 'strncmp'. | -| test.cpp:260:7:260:18 | strncmp | Reference to banned string handling function 'strncmp'. | -| test.cpp:261:48:261:60 | & ... | Address taken of banned string handling function 'strncpy'. | -| test.cpp:262:48:262:59 | strncpy | Reference to banned string handling function 'strncpy'. | -| test.cpp:264:7:264:19 | & ... | Address taken of banned string handling function 'strpbrk'. | -| test.cpp:266:7:266:18 | strpbrk | Reference to banned string handling function 'strpbrk'. | -| test.cpp:267:43:267:55 | & ... | Address taken of banned string handling function 'strrchr'. | -| test.cpp:268:43:268:54 | strrchr | Reference to banned string handling function 'strrchr'. | -| test.cpp:269:47:269:58 | & ... | Address taken of banned string handling function 'strspn'. | -| test.cpp:270:47:270:57 | strspn | Reference to banned string handling function 'strspn'. | -| test.cpp:272:7:272:18 | & ... | Address taken of banned string handling function 'strstr'. | -| test.cpp:273:52:273:62 | strstr | Reference to banned string handling function 'strstr'. | -| test.cpp:274:40:274:51 | & ... | Address taken of banned string handling function 'strtok'. | -| test.cpp:275:40:275:50 | strtok | Reference to banned string handling function 'strtok'. | -| test.cpp:276:49:276:61 | & ... | Address taken of banned string handling function 'strxfrm'. | -| test.cpp:277:49:277:60 | strxfrm | Reference to banned string handling function 'strxfrm'. | -| test.cpp:281:44:281:55 | & ... | Address taken of banned string handling function 'strtol'. | -| test.cpp:282:44:282:54 | strtol | Reference to banned string handling function 'strtol'. | -| test.cpp:283:49:283:61 | & ... | Address taken of banned string handling function 'strtoll'. | -| test.cpp:284:49:284:60 | strtoll | Reference to banned string handling function 'strtoll'. | -| test.cpp:286:7:286:19 | & ... | Address taken of banned string handling function 'strtoul'. | -| test.cpp:288:7:288:18 | strtoul | Reference to banned string handling function 'strtoul'. | -| test.cpp:290:7:290:20 | & ... | Address taken of banned string handling function 'strtoull'. | -| test.cpp:292:7:292:19 | strtoull | Reference to banned string handling function 'strtoull'. | -| test.cpp:293:41:293:52 | & ... | Address taken of banned string handling function 'strtod'. | -| test.cpp:294:42:294:52 | strtod | Reference to banned string handling function 'strtod'. | -| test.cpp:295:41:295:52 | & ... | Address taken of banned string handling function 'strtof'. | -| test.cpp:296:41:296:51 | strtof | Reference to banned string handling function 'strtof'. | -| test.cpp:297:47:297:59 | & ... | Address taken of banned string handling function 'strtold'. | -| test.cpp:298:47:298:58 | strtold | Reference to banned string handling function 'strtold'. | -| test.cpp:302:26:302:37 | & ... | Address taken of banned string handling function 'fgetwc'. | -| test.cpp:303:26:303:36 | fgetwc | Reference to banned string handling function 'fgetwc'. | -| test.cpp:304:35:304:46 | & ... | Address taken of banned string handling function 'fputwc'. | -| test.cpp:305:35:305:45 | fputwc | Reference to banned string handling function 'fputwc'. | -| test.cpp:306:50:306:61 | & ... | Address taken of banned string handling function 'wcstol'. | -| test.cpp:307:50:307:60 | wcstol | Reference to banned string handling function 'wcstol'. | -| test.cpp:309:7:309:19 | & ... | Address taken of banned string handling function 'wcstoll'. | -| test.cpp:311:7:311:18 | wcstoll | Reference to banned string handling function 'wcstoll'. | -| test.cpp:313:7:313:19 | & ... | Address taken of banned string handling function 'wcstoul'. | -| test.cpp:315:7:315:18 | wcstoul | Reference to banned string handling function 'wcstoul'. | -| test.cpp:317:7:317:20 | & ... | Address taken of banned string handling function 'wcstoull'. | -| test.cpp:319:7:319:19 | wcstoull | Reference to banned string handling function 'wcstoull'. | -| test.cpp:320:48:320:59 | & ... | Address taken of banned string handling function 'wcstod'. | -| test.cpp:321:48:321:58 | wcstod | Reference to banned string handling function 'wcstod'. | -| test.cpp:322:47:322:58 | & ... | Address taken of banned string handling function 'wcstof'. | -| test.cpp:323:47:323:57 | wcstof | Reference to banned string handling function 'wcstof'. | -| test.cpp:325:7:325:19 | & ... | Address taken of banned string handling function 'wcstold'. | -| test.cpp:327:7:327:18 | wcstold | Reference to banned string handling function 'wcstold'. | -| test.cpp:332:7:332:21 | & ... | Address taken of banned string handling function 'strtoumax'. | -| test.cpp:333:49:333:62 | strtoumax | Reference to banned string handling function 'strtoumax'. | -| test.cpp:334:48:334:62 | & ... | Address taken of banned string handling function 'strtoimax'. | -| test.cpp:335:48:335:61 | strtoimax | Reference to banned string handling function 'strtoimax'. | -| test.cpp:337:7:337:21 | & ... | Address taken of banned string handling function 'wcstoumax'. | -| test.cpp:339:7:339:20 | wcstoumax | Reference to banned string handling function 'wcstoumax'. | -| test.cpp:341:7:341:21 | & ... | Address taken of banned string handling function 'wcstoimax'. | -| test.cpp:343:7:343:20 | wcstoimax | Reference to banned string handling function 'wcstoimax'. | +| test.cpp:239:40:239:50 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:240:39:240:49 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:241:42:241:53 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:242:42:242:52 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:243:44:243:54 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:244:43:244:53 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:245:44:245:55 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:246:43:246:54 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:247:40:247:50 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:248:40:248:50 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:249:48:249:59 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:250:47:250:58 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:251:24:251:36 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:252:23:252:35 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:253:34:253:44 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:254:33:254:43 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:255:49:255:60 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:256:48:256:59 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:258:8:258:19 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:260:7:260:18 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:261:49:261:60 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:262:48:262:59 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:264:7:264:19 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:266:7:266:18 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:267:43:267:55 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:268:43:268:54 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:269:48:269:58 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:270:47:270:57 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:272:7:272:18 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:273:52:273:62 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:274:41:274:51 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:275:40:275:50 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:276:50:276:61 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:277:49:277:60 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:281:45:281:55 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:282:44:282:54 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:283:50:283:61 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:284:49:284:60 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:286:8:286:19 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:288:7:288:18 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:290:8:290:20 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:292:7:292:19 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:293:42:293:52 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:294:42:294:52 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:295:42:295:52 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:296:41:296:51 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:297:48:297:59 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:298:47:298:58 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:302:27:302:37 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:303:26:303:36 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:304:36:304:46 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:305:35:305:45 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:306:51:306:61 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:307:50:307:60 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:309:8:309:19 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:311:7:311:18 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:313:8:313:19 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:315:7:315:18 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:317:8:317:20 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:319:7:319:19 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:320:49:320:59 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:321:48:321:58 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:322:48:322:58 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:323:47:323:57 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:325:8:325:19 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:327:7:327:18 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:332:8:332:21 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:333:49:333:62 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:334:49:334:62 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:335:48:335:61 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:337:8:337:21 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:339:7:339:20 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:341:8:341:21 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | +| test.cpp:343:7:343:20 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | From d33b4eb8d2456183e85f82404c79da221016c152 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 23:11:10 +0100 Subject: [PATCH 20/36] Add `system` to cstdlib --- cpp/common/test/includes/standard-library/cstdlib | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/common/test/includes/standard-library/cstdlib b/cpp/common/test/includes/standard-library/cstdlib index 1b7df173a..3b1eefc4a 100644 --- a/cpp/common/test/includes/standard-library/cstdlib +++ b/cpp/common/test/includes/standard-library/cstdlib @@ -22,5 +22,6 @@ using ::strtold; using ::strtoll; using ::strtoul; using ::strtoull; +using ::system; } // namespace std #endif // _GHLIBCPP_CSTDLIB \ No newline at end of file From efa017fa0a0b7d14cfd85af410a3642450c62383 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 23:11:56 +0100 Subject: [PATCH 21/36] Rule 21.2.3 - BannedSystemFunction.ql Add a new query for detecting uses of the banned function `system`. [a] --- .../rules/RULE-21-2-3/BannedSystemFunction.ql | 36 +++++++++++++++ .../RULE-21-2-3/BannedSystemFunction.expected | 9 ++++ .../RULE-21-2-3/BannedSystemFunction.qlref | 1 + cpp/misra/test/rules/RULE-21-2-3/test.cpp | 45 +++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql create mode 100644 cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected create mode 100644 cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref create mode 100644 cpp/misra/test/rules/RULE-21-2-3/test.cpp diff --git a/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql b/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql new file mode 100644 index 000000000..b8cf0788f --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql @@ -0,0 +1,36 @@ +/** + * @id cpp/misra/banned-system-function + * @name RULE-21-2-3: The library function system from shall not be used + * @description Using the system() function from cstdlib or stdlib.h causes undefined behavior and + * potential security vulnerabilities. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-2-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class SystemFunction extends Function { + SystemFunction() { this.hasGlobalName("system") or this.hasQualifiedName("std", "system") } +} + +from Element element, string message +where + not isExcluded(element, BannedAPIsPackage::bannedSystemFunctionQuery()) and + ( + element instanceof BannedFunctions::Use and + message = + element.(BannedFunctions::Use).getAction() + " banned function '" + + element.(BannedFunctions::Use).getFunctionName() + "'." + or + element instanceof MacroInvocation and + element.(MacroInvocation).getMacroName() = "system" and + message = "Use of banned macro 'system'." + ) +select element, message diff --git a/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected new file mode 100644 index 000000000..fcb5a8aee --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected @@ -0,0 +1,9 @@ +| test.cpp:4:3:4:13 | call to system | Call to banned function 'system'. | +| test.cpp:8:14:8:24 | system | Address taken for banned function 'system'. | +| test.cpp:9:29:9:39 | system | Address taken for banned function 'system'. | +| test.cpp:13:40:13:50 | system | Address taken for banned function 'system'. | +| test.cpp:17:3:17:13 | call to system | Call to banned function 'system'. | +| test.cpp:22:3:22:13 | call to system | Call to banned function 'system'. | +| test.cpp:35:3:35:8 | call to system | Call to banned function 'system'. | +| test.cpp:39:29:39:34 | system | Address taken for banned function 'system'. | +| test.cpp:44:3:44:21 | system(x) | Use of banned macro 'system'. | diff --git a/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref new file mode 100644 index 000000000..2580c7a6a --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref @@ -0,0 +1 @@ +rules/RULE-21-2-3/BannedSystemFunction.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-3/test.cpp b/cpp/misra/test/rules/RULE-21-2-3/test.cpp new file mode 100644 index 000000000..89ed82d88 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-3/test.cpp @@ -0,0 +1,45 @@ +#include + +void test_direct_call_to_system() { + std::system("echo hello"); // NON_COMPLIANT +} + +void test_system_function_pointer() { + auto l1 = &std::system; // NON_COMPLIANT + int (*l2)(const char *) = std::system; // NON_COMPLIANT +} + +void test_system_address_taken() { + void *l1 = reinterpret_cast(&std::system); // NON_COMPLIANT +} + +void test_system_call_with_null() { + std::system(nullptr); // NON_COMPLIANT +} + +void test_system_call_with_variable() { + const char *l1 = "ls"; + std::system(l1); // NON_COMPLIANT +} + +void test_compliant_alternative() { + // Using compliant alternatives instead of system() + const char *l1 = "some command"; // COMPLIANT + // Implementation-specific alternatives would be used here +} + +// Test with C-style header (rule also applies to ) +#include + +void test_c_style_header_system() { + system("echo hello"); // NON_COMPLIANT +} + +void test_c_style_header_function_pointer() { + int (*l1)(const char *) = system; // NON_COMPLIANT +} + +#define system(x) 0 +void test_system_macro_expansion() { + system("echo test"); // NON_COMPLIANT +} From eccc416f512ae347bf718c5f7962dfc954b80013 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 12:54:57 +0100 Subject: [PATCH 22/36] Rule 23.11.1 - UseSmarPtrFactoryFunctions.ql A new query to report uses of the raw pointer constructors of the std::unique_ptr and std::shared_ptr classes. [a] --- .../test/includes/standard-library/memory.h | 3 + .../UseSmartPtrFactoryFunctions.ql | 32 +++++++ .../UseSmartPtrFactoryFunctions.expected | 9 ++ .../UseSmartPtrFactoryFunctions.qlref | 1 + cpp/misra/test/rules/RULE-23-11-1/test.cpp | 84 +++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql create mode 100644 cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected create mode 100644 cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref create mode 100644 cpp/misra/test/rules/RULE-23-11-1/test.cpp diff --git a/cpp/common/test/includes/standard-library/memory.h b/cpp/common/test/includes/standard-library/memory.h index 985ee4160..494f42842 100644 --- a/cpp/common/test/includes/standard-library/memory.h +++ b/cpp/common/test/includes/standard-library/memory.h @@ -23,6 +23,7 @@ class unique_ptr { unique_ptr(T *ptr) {} unique_ptr(const unique_ptr &t) = delete; unique_ptr(unique_ptr &&t) {} + unique_ptr(pointer p, Deleter d) noexcept {} ~unique_ptr() {} T &operator*() const { return *ptr; } T *operator->() const noexcept { return ptr; } @@ -93,8 +94,10 @@ template class shared_ptr : public __shared_ptr { shared_ptr(T *ptr); shared_ptr(const shared_ptr &r) noexcept; template shared_ptr(const shared_ptr &r) noexcept; + template shared_ptr(const shared_ptr &r, T *p) noexcept; shared_ptr(shared_ptr &&r) noexcept; template shared_ptr(shared_ptr &&r) noexcept; + template shared_ptr(T *p, D d); shared_ptr(unique_ptr &&t) {} ~shared_ptr() {} T &operator*() const noexcept; diff --git a/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql new file mode 100644 index 000000000..65faa9cfd --- /dev/null +++ b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql @@ -0,0 +1,32 @@ +/** + * @id cpp/misra/use-smart-ptr-factory-functions + * @name RULE-23-11-1: The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used + * @description Using raw pointer constructors of std::shared_ptr and std::unique_ptr instead of + * make_shared/make_unique can lead to memory leaks if exceptions occur during + * construction. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-23-11-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +from ConstructorCall call, Class smartPtrClass +where + not isExcluded(call, BannedAPIsPackage::useSmartPtrFactoryFunctionsQuery()) and + smartPtrClass = call.getTarget().getDeclaringType() and + ( + smartPtrClass.hasQualifiedName("std", "shared_ptr") or + smartPtrClass.hasQualifiedName("std", "unique_ptr") + ) and + call.getNumberOfArguments() >= 1 and + exists(Type argType | + argType = call.getArgument(0).getType().getUnspecifiedType() and + argType instanceof PointerType + ) +select call, "Use of raw pointer constructor for 'std::" + smartPtrClass.getSimpleName() + "'." diff --git a/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected new file mode 100644 index 000000000..a6d399c0d --- /dev/null +++ b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected @@ -0,0 +1,9 @@ +| test.cpp:23:25:23:27 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:28:25:28:27 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | +| test.cpp:34:3:34:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:40:3:40:32 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | +| test.cpp:46:6:46:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:47:6:47:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:57:27:57:29 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | +| test.cpp:67:25:67:31 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:74:39:74:45 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | diff --git a/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref new file mode 100644 index 000000000..337d1b2ad --- /dev/null +++ b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref @@ -0,0 +1 @@ +rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-23-11-1/test.cpp b/cpp/misra/test/rules/RULE-23-11-1/test.cpp new file mode 100644 index 000000000..1f0cb2cf7 --- /dev/null +++ b/cpp/misra/test/rules/RULE-23-11-1/test.cpp @@ -0,0 +1,84 @@ +#include +#include + +struct A { + std::int8_t i; +}; + +class B {}; + +void test_make_shared_compliant() { + auto p = std::make_shared(); // COMPLIANT + std::int8_t *pi = &(p->i); + std::shared_ptr q( + p, pi); // COMPLIANT - aliasing constructor, not taking ownership +} + +void test_make_unique_compliant() { + auto p = std::make_unique(); // COMPLIANT +} + +void test_raw_pointer_shared_ptr_non_compliant() { + A *l1 = new A(); + std::shared_ptr l2(l1); // NON_COMPLIANT +} + +void test_raw_pointer_unique_ptr_non_compliant() { + A *l1 = new A(); + std::unique_ptr l2(l1); // NON_COMPLIANT +} + +auto test_exception_safety_issue() { + auto *l1 = new A(); + auto l2 = std::make_unique(); // may throw + return std::shared_ptr(l1); // NON_COMPLIANT - memory leak + // if make_unique throws +} + +auto test_double_delete_issue(std::unique_ptr p) { + auto l1 = p.get(); + return std::unique_ptr(l1); // NON_COMPLIANT - causes double delete +} + +void f1(std::shared_ptr a, std::shared_ptr b); + +void test_function_argument_non_compliant() { + f1(std::shared_ptr(new A()), // NON_COMPLIANT + std::shared_ptr(new B())); // NON_COMPLIANT +} + +void test_function_argument_compliant() { + f1(std::make_shared(), // COMPLIANT + std::make_shared()); // COMPLIANT +} + +void test_array_raw_pointer_non_compliant() { + A *l1 = new A[10]; + std::unique_ptr l2(l1); // NON_COMPLIANT +} + +void test_array_make_unique_compliant() { + auto l1 = std::make_unique(10); // COMPLIANT +} + +void test_custom_deleter_shared_ptr() { + A *l1 = new A(); + auto l2 = [](A *p) { delete p; }; + std::shared_ptr l3(l1, l2); // NON_COMPLIANT - still + // using raw pointer constructor +} + +void test_custom_deleter_unique_ptr() { + A *l1 = new A(); + auto l2 = [](A *p) { delete p; }; + std::unique_ptr l3(l1, l2); // NON_COMPLIANT - still + // using raw pointer constructor +} + +void test_nullptr_shared_ptr() { + std::shared_ptr l1(nullptr); // COMPLIANT - no ownership taken +} + +void test_nullptr_unique_ptr() { + std::unique_ptr l1(nullptr); // COMPLIANT - no ownership taken +} \ No newline at end of file From 8a8c33dda4ed84e6e4598f1345a9cd1f88f4818b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 13:02:46 +0100 Subject: [PATCH 23/36] Update C++ stubs for ctype.h/cctype and wctype.h/cwctype --- .../test/includes/standard-library/cctype | 21 ++++++++++++- .../test/includes/standard-library/ctype.h | 5 ++-- .../test/includes/standard-library/cwctype | 30 +++++++++++++++++++ .../test/includes/standard-library/wctype.h | 28 +++++++++++++++++ 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cctype b/cpp/common/test/includes/standard-library/cctype index 98e0805cf..b45830acb 100644 --- a/cpp/common/test/includes/standard-library/cctype +++ b/cpp/common/test/includes/standard-library/cctype @@ -1 +1,20 @@ -#include "ctype.h" \ No newline at end of file +#ifndef _GHLIBCPP_CCTYPE +#define _GHLIBCPP_CCTYPE +#include "ctype.h" +namespace std { +using ::isalnum; +using ::isalpha; +using ::isblank; +using ::iscntrl; +using ::isdigit; +using ::isgraph; +using ::islower; +using ::isprint; +using ::ispunct; +using ::isspace; +using ::isupper; +using ::isxdigit; +using ::tolower; +using ::toupper; +} // namespace std +#endif // _GHLIBCPP_CCTYPE diff --git a/cpp/common/test/includes/standard-library/ctype.h b/cpp/common/test/includes/standard-library/ctype.h index e9264fd7c..d7dc85152 100644 --- a/cpp/common/test/includes/standard-library/ctype.h +++ b/cpp/common/test/includes/standard-library/ctype.h @@ -1,8 +1,9 @@ #ifndef _GHLIBCPP_CTYPE #define _GHLIBCPP_CTYPE -namespace std { + extern int isalnum(int); extern int isalpha(int); +extern int isblank(int); extern int iscntrl(int); extern int isdigit(int); extern int islower(int); @@ -14,5 +15,5 @@ extern int isupper(int); extern int isxdigit(int); extern int tolower(int); extern int toupper(int); -} // namespace std + #endif // _GHLIBCPP_CTYPE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cwctype b/cpp/common/test/includes/standard-library/cwctype index 490ed4edf..d2ce5c7e3 100644 --- a/cpp/common/test/includes/standard-library/cwctype +++ b/cpp/common/test/includes/standard-library/cwctype @@ -1,8 +1,38 @@ #ifndef _GHLIBCPP_CWCTYPE #define _GHLIBCPP_CWCTYPE +#include "wctype.h" namespace std { +// Types using ::wint_t; +using ::wctype_t; +using ::wctrans_t; + +// Wide character classification functions +using ::iswalnum; +using ::iswalpha; +using ::iswblank; +using ::iswcntrl; +using ::iswdigit; +using ::iswgraph; +using ::iswlower; +using ::iswprint; +using ::iswpunct; +using ::iswspace; +using ::iswupper; +using ::iswxdigit; + +// Wide character conversion functions +using ::towlower; +using ::towupper; + +// Generic wide character classification functions +using ::iswctype; +using ::wctype; + +// Generic wide character mapping functions +using ::towctrans; +using ::wctrans; } // namespace std #endif // _GHLIBCPP_CWCTYPE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/wctype.h b/cpp/common/test/includes/standard-library/wctype.h index b82c7a13f..d66b63a75 100644 --- a/cpp/common/test/includes/standard-library/wctype.h +++ b/cpp/common/test/includes/standard-library/wctype.h @@ -2,5 +2,33 @@ #define _GHLIBCPP_WCTYPE typedef long wint_t; +typedef long wctype_t; +typedef long wctrans_t; + +// Wide character classification functions +extern int iswalnum(wint_t wc); +extern int iswalpha(wint_t wc); +extern int iswblank(wint_t wc); +extern int iswcntrl(wint_t wc); +extern int iswdigit(wint_t wc); +extern int iswgraph(wint_t wc); +extern int iswlower(wint_t wc); +extern int iswprint(wint_t wc); +extern int iswpunct(wint_t wc); +extern int iswspace(wint_t wc); +extern int iswupper(wint_t wc); +extern int iswxdigit(wint_t wc); + +// Wide character conversion functions +extern wint_t towlower(wint_t wc); +extern wint_t towupper(wint_t wc); + +// Generic wide character classification functions +extern int iswctype(wint_t wc, wctype_t desc); +extern wctype_t wctype(const char *property); + +// Generic wide character mapping functions +extern wint_t towctrans(wint_t wc, wctrans_t desc); +extern wctrans_t wctrans(const char *property); #endif // _GHLIBCPP_WCTYPE \ No newline at end of file From b81423bc741d1f51e45cd760585270c00ec7a9ab Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 14:50:00 +0100 Subject: [PATCH 24/36] Improve C++ stubs for locales --- .../test/includes/standard-library/clocale | 5 +- .../test/includes/standard-library/locale | 25 ++++++++ .../test/includes/standard-library/locale.h | 59 +++++++++---------- 3 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 cpp/common/test/includes/standard-library/locale diff --git a/cpp/common/test/includes/standard-library/clocale b/cpp/common/test/includes/standard-library/clocale index 430c36daa..8ec16234b 100644 --- a/cpp/common/test/includes/standard-library/clocale +++ b/cpp/common/test/includes/standard-library/clocale @@ -1,4 +1,5 @@ -#pragma once +#ifndef _GHLIBCPP_CLOCALE +#define _GHLIBCPP_CLOCALE #define NULL 0 #define LC_ALL 0 @@ -15,3 +16,5 @@ using ::lconv; using ::localeconv; using ::setlocale; } // namespace std + +#endif // _GHLIBCPP_CLOCALE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/locale b/cpp/common/test/includes/standard-library/locale new file mode 100644 index 000000000..4d19e3dba --- /dev/null +++ b/cpp/common/test/includes/standard-library/locale @@ -0,0 +1,25 @@ + +#ifndef _GHLIBCPP_LOCALE +#define _GHLIBCPP_LOCALE + +namespace std { + +class locale {}; + +template bool isspace(charT c, const locale &loc); +template bool isprint(charT c, const locale &loc); +template bool iscntrl(charT c, const locale &loc); +template bool isupper(charT c, const locale &loc); +template bool islower(charT c, const locale &loc); +template bool isalpha(charT c, const locale &loc); +template bool isdigit(charT c, const locale &loc); +template bool ispunct(charT c, const locale &loc); +template bool isxdigit(charT c, const locale &loc); +template bool isalnum(charT c, const locale &loc); +template bool isgraph(charT c, const locale &loc); +template bool isblank(charT c, const locale &loc); +template charT toupper(charT c, const locale &loc); +template charT tolower(charT c, const locale &loc); +} // namespace std + +#endif // _GHLIBCPP_LOCALE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/locale.h b/cpp/common/test/includes/standard-library/locale.h index 19a890553..2501c9c5d 100644 --- a/cpp/common/test/includes/standard-library/locale.h +++ b/cpp/common/test/includes/standard-library/locale.h @@ -1,38 +1,37 @@ -#ifndef _GHLIBCPP_LOCALE -#define _GHLIBCPP_LOCALE +#ifndef _GHLIBCPP_LOCALE_H +#define _GHLIBCPP_LOCALE_H -#define LC_ALL 6 +#define LC_ALL 6 struct lconv { - char *decimal_point; - char *thousands_sep; - char *grouping; + char *decimal_point; + char *thousands_sep; + char *grouping; - char *int_curr_symbol; - char *currency_symbol; - char *mon_decimal_point; - char *mon_thousands_sep; - char *mon_grouping; - char *positive_sign; - char *negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; - char int_p_cs_precedes; - char int_p_sep_by_space; - char int_n_cs_precedes; - char int_n_sep_by_space; - char int_p_sign_posn; - char int_n_sign_posn; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; }; - -char *setlocale (int, const char *); +char *setlocale(int, const char *); struct lconv *localeconv(void); -#endif // _GHLIBCPP_LOCALE \ No newline at end of file +#endif // _GHLIBCPP_LOCALE_H \ No newline at end of file From cfceb9bd96d96dbce497bb6227f1cf1828baa2be Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 15:11:25 +0100 Subject: [PATCH 25/36] Add C++ string_view stub --- .../includes/standard-library/string_view | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 cpp/common/test/includes/standard-library/string_view diff --git a/cpp/common/test/includes/standard-library/string_view b/cpp/common/test/includes/standard-library/string_view new file mode 100644 index 000000000..7897d2cf7 --- /dev/null +++ b/cpp/common/test/includes/standard-library/string_view @@ -0,0 +1,79 @@ +#pragma once +#ifndef _GHLIBCPP_STRING_VIEW +#define _GHLIBCPP_STRING_VIEW + +#include "stddef.h" + +namespace std { + +template class basic_string_view { +public: + typedef CharT value_type; + typedef const CharT *pointer; + typedef const CharT *const_pointer; + typedef const CharT &reference; + typedef const CharT &const_reference; + typedef const CharT *const_iterator; + typedef const_iterator iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + // Constructors + basic_string_view() noexcept; + basic_string_view(const basic_string_view &) noexcept = default; + basic_string_view(const CharT *s, size_type count); + basic_string_view(const CharT *s); + + // Assignment + basic_string_view &operator=(const basic_string_view &) noexcept = default; + + // Element access + const_reference operator[](size_type pos) const; + const_reference at(size_type pos) const; + const_reference front() const; + const_reference back() const; + const_pointer data() const noexcept; + + // Capacity + size_type size() const noexcept; + size_type length() const noexcept; + size_type max_size() const noexcept; + bool empty() const noexcept; + + // Modifiers + void remove_prefix(size_type n); + void remove_suffix(size_type n); + void swap(basic_string_view &v) noexcept; + + // String operations + size_type copy(CharT *dest, size_type count, size_type pos = 0) const; + basic_string_view substr(size_type pos = 0, size_type len = npos) const; + + // Comparison + int compare(basic_string_view v) const noexcept; + int compare(size_type pos1, size_type n1, basic_string_view v) const; + int compare(const CharT *s) const; + + // Search + size_type find(basic_string_view v, size_type pos = 0) const noexcept; + size_type find(CharT c, 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; + + // Constants + static const size_type npos = static_cast(-1); + +private: + const CharT *data_; + size_type size_; +}; + +// Type aliases +typedef basic_string_view string_view; +typedef basic_string_view wstring_view; +typedef basic_string_view u16string_view; +typedef basic_string_view u32string_view; + +} // namespace std + +#endif // _GHLIBCPP_STRING_VIEW From 52b97e6e4fdaa230f389766e6a73e0e946b82f41 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 15:12:02 +0100 Subject: [PATCH 26/36] Rule 24.5.1 - CharacterHandlingFunctionRestrictions.ql Add a new query to detect uses of prohibited character handling functions. --- .../CharacterHandlingFunctionRestrictions.ql | 42 ++++ ...acterHandlingFunctionRestrictions.expected | 132 +++++++++++ ...haracterHandlingFunctionRestrictions.qlref | 1 + cpp/misra/test/rules/RULE-24-5-1/test.cpp | 219 ++++++++++++++++++ 4 files changed, 394 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql create mode 100644 cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected create mode 100644 cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref create mode 100644 cpp/misra/test/rules/RULE-24-5-1/test.cpp diff --git a/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql new file mode 100644 index 000000000..6a779b0e6 --- /dev/null +++ b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql @@ -0,0 +1,42 @@ +/** + * @id cpp/misra/character-handling-function-restrictions + * @name RULE-24-5-1: The character handling functions from and shall not be used + * @description Using character classification and case mapping functions from and + * causes undefined behavior when arguments are not representable as unsigned + * char or not equal to EOF. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-24-5-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class BannedCharacterHandlingFunction extends Function { + BannedCharacterHandlingFunction() { + this.hasGlobalOrStdName([ + "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", + "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper", + "iswalnum", "iswalpha", "iswblank", "iswcntrl", "iswctype", "iswdigit", "iswgraph", + "iswlower", "iswprint", "iswpunct", "iswspace", "iswupper", "iswxdigit", "towctrans", + "towlower", "towupper", "wctrans", "wctype" + ]) and + not ( + this.hasGlobalOrStdName([ + "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", + "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper" + ]) and + this.getACallToThisFunction().(FunctionCall).getNumberOfArguments() = 2 + ) + } +} + +from BannedFunctions::Use use +where + not isExcluded(use, BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery()) +select use, use.getAction() + " banned character handling function '" + use.getFunctionName() + "' from or ." \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected new file mode 100644 index 000000000..1c02073fb --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected @@ -0,0 +1,132 @@ +| test.cpp:11:3:11:14 | call to isalnum | Call to banned character handling function 'isalnum' from or . | +| test.cpp:12:3:12:14 | call to isalpha | Call to banned character handling function 'isalpha' from or . | +| test.cpp:13:3:13:14 | call to isblank | Call to banned character handling function 'isblank' from or . | +| test.cpp:14:3:14:14 | call to iscntrl | Call to banned character handling function 'iscntrl' from or . | +| test.cpp:15:3:15:14 | call to isdigit | Call to banned character handling function 'isdigit' from or . | +| test.cpp:16:3:16:14 | call to isgraph | Call to banned character handling function 'isgraph' from or . | +| test.cpp:17:3:17:14 | call to islower | Call to banned character handling function 'islower' from or . | +| test.cpp:18:3:18:14 | call to isprint | Call to banned character handling function 'isprint' from or . | +| test.cpp:19:3:19:14 | call to ispunct | Call to banned character handling function 'ispunct' from or . | +| test.cpp:20:3:20:14 | call to isspace | Call to banned character handling function 'isspace' from or . | +| test.cpp:21:3:21:14 | call to isupper | Call to banned character handling function 'isupper' from or . | +| test.cpp:22:3:22:15 | call to isxdigit | Call to banned character handling function 'isxdigit' from or . | +| test.cpp:25:3:25:14 | call to tolower | Call to banned character handling function 'tolower' from or . | +| test.cpp:26:3:26:14 | call to toupper | Call to banned character handling function 'toupper' from or . | +| test.cpp:33:3:33:9 | call to isalnum | Call to banned character handling function 'isalnum' from or . | +| test.cpp:34:3:34:9 | call to isalpha | Call to banned character handling function 'isalpha' from or . | +| test.cpp:35:3:35:9 | call to isblank | Call to banned character handling function 'isblank' from or . | +| test.cpp:36:3:36:9 | call to iscntrl | Call to banned character handling function 'iscntrl' from or . | +| test.cpp:37:3:37:9 | call to isdigit | Call to banned character handling function 'isdigit' from or . | +| test.cpp:38:3:38:9 | call to isgraph | Call to banned character handling function 'isgraph' from or . | +| test.cpp:39:3:39:9 | call to islower | Call to banned character handling function 'islower' from or . | +| test.cpp:40:3:40:9 | call to isprint | Call to banned character handling function 'isprint' from or . | +| test.cpp:41:3:41:9 | call to ispunct | Call to banned character handling function 'ispunct' from or . | +| test.cpp:42:3:42:9 | call to isspace | Call to banned character handling function 'isspace' from or . | +| test.cpp:43:3:43:9 | call to isupper | Call to banned character handling function 'isupper' from or . | +| test.cpp:44:3:44:10 | call to isxdigit | Call to banned character handling function 'isxdigit' from or . | +| test.cpp:47:3:47:9 | call to tolower | Call to banned character handling function 'tolower' from or . | +| test.cpp:48:3:48:9 | call to toupper | Call to banned character handling function 'toupper' from or . | +| test.cpp:55:3:55:15 | call to iswalnum | Call to banned character handling function 'iswalnum' from or . | +| test.cpp:56:3:56:15 | call to iswalpha | Call to banned character handling function 'iswalpha' from or . | +| test.cpp:57:3:57:15 | call to iswblank | Call to banned character handling function 'iswblank' from or . | +| test.cpp:58:3:58:15 | call to iswcntrl | Call to banned character handling function 'iswcntrl' from or . | +| test.cpp:59:3:59:15 | call to iswdigit | Call to banned character handling function 'iswdigit' from or . | +| test.cpp:60:3:60:15 | call to iswgraph | Call to banned character handling function 'iswgraph' from or . | +| test.cpp:61:3:61:15 | call to iswlower | Call to banned character handling function 'iswlower' from or . | +| test.cpp:62:3:62:15 | call to iswprint | Call to banned character handling function 'iswprint' from or . | +| test.cpp:63:3:63:15 | call to iswpunct | Call to banned character handling function 'iswpunct' from or . | +| test.cpp:64:3:64:15 | call to iswspace | Call to banned character handling function 'iswspace' from or . | +| test.cpp:65:3:65:15 | call to iswupper | Call to banned character handling function 'iswupper' from or . | +| test.cpp:66:3:66:16 | call to iswxdigit | Call to banned character handling function 'iswxdigit' from or . | +| test.cpp:69:3:69:15 | call to towlower | Call to banned character handling function 'towlower' from or . | +| test.cpp:70:3:70:15 | call to towupper | Call to banned character handling function 'towupper' from or . | +| test.cpp:73:3:73:13 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:74:3:74:15 | call to iswctype | Call to banned character handling function 'iswctype' from or . | +| test.cpp:74:21:74:31 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:75:3:75:14 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:76:3:76:16 | call to towctrans | Call to banned character handling function 'towctrans' from or . | +| test.cpp:76:22:76:33 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:83:3:83:10 | call to iswalnum | Call to banned character handling function 'iswalnum' from or . | +| test.cpp:84:3:84:10 | call to iswalpha | Call to banned character handling function 'iswalpha' from or . | +| test.cpp:85:3:85:10 | call to iswblank | Call to banned character handling function 'iswblank' from or . | +| test.cpp:86:3:86:10 | call to iswcntrl | Call to banned character handling function 'iswcntrl' from or . | +| test.cpp:87:3:87:10 | call to iswdigit | Call to banned character handling function 'iswdigit' from or . | +| test.cpp:88:3:88:10 | call to iswgraph | Call to banned character handling function 'iswgraph' from or . | +| test.cpp:89:3:89:10 | call to iswlower | Call to banned character handling function 'iswlower' from or . | +| test.cpp:90:3:90:10 | call to iswprint | Call to banned character handling function 'iswprint' from or . | +| test.cpp:91:3:91:10 | call to iswpunct | Call to banned character handling function 'iswpunct' from or . | +| test.cpp:92:3:92:10 | call to iswspace | Call to banned character handling function 'iswspace' from or . | +| test.cpp:93:3:93:10 | call to iswupper | Call to banned character handling function 'iswupper' from or . | +| test.cpp:94:3:94:11 | call to iswxdigit | Call to banned character handling function 'iswxdigit' from or . | +| test.cpp:97:3:97:10 | call to towlower | Call to banned character handling function 'towlower' from or . | +| test.cpp:98:3:98:10 | call to towupper | Call to banned character handling function 'towupper' from or . | +| test.cpp:101:3:101:8 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:102:3:102:10 | call to iswctype | Call to banned character handling function 'iswctype' from or . | +| test.cpp:102:16:102:21 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:103:3:103:9 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:104:3:104:11 | call to towctrans | Call to banned character handling function 'towctrans' from or . | +| test.cpp:104:17:104:23 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:109:20:109:32 | isalnum | Address taken for banned character handling function 'isalnum' from or . | +| test.cpp:110:20:110:32 | isalpha | Address taken for banned character handling function 'isalpha' from or . | +| test.cpp:111:20:111:32 | isblank | Address taken for banned character handling function 'isblank' from or . | +| test.cpp:112:20:112:32 | iscntrl | Address taken for banned character handling function 'iscntrl' from or . | +| test.cpp:113:20:113:32 | isdigit | Address taken for banned character handling function 'isdigit' from or . | +| test.cpp:114:20:114:32 | isgraph | Address taken for banned character handling function 'isgraph' from or . | +| test.cpp:115:20:115:32 | islower | Address taken for banned character handling function 'islower' from or . | +| test.cpp:116:20:116:32 | isprint | Address taken for banned character handling function 'isprint' from or . | +| test.cpp:117:20:117:32 | ispunct | Address taken for banned character handling function 'ispunct' from or . | +| test.cpp:118:21:118:33 | isspace | Address taken for banned character handling function 'isspace' from or . | +| test.cpp:119:21:119:33 | isupper | Address taken for banned character handling function 'isupper' from or . | +| test.cpp:120:21:120:34 | isxdigit | Address taken for banned character handling function 'isxdigit' from or . | +| test.cpp:121:21:121:33 | tolower | Address taken for banned character handling function 'tolower' from or . | +| test.cpp:122:21:122:33 | toupper | Address taken for banned character handling function 'toupper' from or . | +| test.cpp:125:22:125:28 | isalnum | Address taken for banned character handling function 'isalnum' from or . | +| test.cpp:126:22:126:28 | isalpha | Address taken for banned character handling function 'isalpha' from or . | +| test.cpp:127:22:127:28 | isblank | Address taken for banned character handling function 'isblank' from or . | +| test.cpp:128:22:128:28 | iscntrl | Address taken for banned character handling function 'iscntrl' from or . | +| test.cpp:129:22:129:28 | isdigit | Address taken for banned character handling function 'isdigit' from or . | +| test.cpp:130:22:130:28 | isgraph | Address taken for banned character handling function 'isgraph' from or . | +| test.cpp:131:22:131:28 | islower | Address taken for banned character handling function 'islower' from or . | +| test.cpp:132:22:132:28 | isprint | Address taken for banned character handling function 'isprint' from or . | +| test.cpp:133:22:133:28 | ispunct | Address taken for banned character handling function 'ispunct' from or . | +| test.cpp:134:22:134:28 | isspace | Address taken for banned character handling function 'isspace' from or . | +| test.cpp:135:22:135:28 | isupper | Address taken for banned character handling function 'isupper' from or . | +| test.cpp:136:22:136:29 | isxdigit | Address taken for banned character handling function 'isxdigit' from or . | +| test.cpp:137:22:137:28 | tolower | Address taken for banned character handling function 'tolower' from or . | +| test.cpp:138:22:138:28 | toupper | Address taken for banned character handling function 'toupper' from or . | +| test.cpp:141:25:141:37 | iswalnum | Address taken for banned character handling function 'iswalnum' from or . | +| test.cpp:142:25:142:37 | iswalpha | Address taken for banned character handling function 'iswalpha' from or . | +| test.cpp:143:25:143:37 | iswblank | Address taken for banned character handling function 'iswblank' from or . | +| test.cpp:144:25:144:37 | iswcntrl | Address taken for banned character handling function 'iswcntrl' from or . | +| test.cpp:145:25:145:37 | iswdigit | Address taken for banned character handling function 'iswdigit' from or . | +| test.cpp:146:25:146:37 | iswgraph | Address taken for banned character handling function 'iswgraph' from or . | +| test.cpp:147:25:147:37 | iswlower | Address taken for banned character handling function 'iswlower' from or . | +| test.cpp:148:25:148:37 | iswprint | Address taken for banned character handling function 'iswprint' from or . | +| test.cpp:149:25:149:37 | iswpunct | Address taken for banned character handling function 'iswpunct' from or . | +| test.cpp:150:25:150:37 | iswspace | Address taken for banned character handling function 'iswspace' from or . | +| test.cpp:151:25:151:37 | iswupper | Address taken for banned character handling function 'iswupper' from or . | +| test.cpp:152:25:152:38 | iswxdigit | Address taken for banned character handling function 'iswxdigit' from or . | +| test.cpp:153:28:153:40 | towlower | Address taken for banned character handling function 'towlower' from or . | +| test.cpp:154:28:154:40 | towupper | Address taken for banned character handling function 'towupper' from or . | +| test.cpp:155:36:155:46 | wctype | Address taken for banned character handling function 'wctype' from or . | +| test.cpp:156:35:156:47 | iswctype | Address taken for banned character handling function 'iswctype' from or . | +| test.cpp:157:37:157:48 | wctrans | Address taken for banned character handling function 'wctrans' from or . | +| test.cpp:158:39:158:52 | towctrans | Address taken for banned character handling function 'towctrans' from or . | +| test.cpp:161:25:161:32 | iswalnum | Address taken for banned character handling function 'iswalnum' from or . | +| test.cpp:162:25:162:32 | iswalpha | Address taken for banned character handling function 'iswalpha' from or . | +| test.cpp:163:25:163:32 | iswblank | Address taken for banned character handling function 'iswblank' from or . | +| test.cpp:164:25:164:32 | iswcntrl | Address taken for banned character handling function 'iswcntrl' from or . | +| test.cpp:165:25:165:32 | iswdigit | Address taken for banned character handling function 'iswdigit' from or . | +| test.cpp:166:25:166:32 | iswgraph | Address taken for banned character handling function 'iswgraph' from or . | +| test.cpp:167:25:167:32 | iswlower | Address taken for banned character handling function 'iswlower' from or . | +| test.cpp:168:25:168:32 | iswprint | Address taken for banned character handling function 'iswprint' from or . | +| test.cpp:169:25:169:32 | iswpunct | Address taken for banned character handling function 'iswpunct' from or . | +| test.cpp:170:25:170:32 | iswspace | Address taken for banned character handling function 'iswspace' from or . | +| test.cpp:171:25:171:32 | iswupper | Address taken for banned character handling function 'iswupper' from or . | +| test.cpp:172:25:172:33 | iswxdigit | Address taken for banned character handling function 'iswxdigit' from or . | +| test.cpp:173:28:173:35 | towlower | Address taken for banned character handling function 'towlower' from or . | +| test.cpp:174:28:174:35 | towupper | Address taken for banned character handling function 'towupper' from or . | +| test.cpp:175:36:175:41 | wctype | Address taken for banned character handling function 'wctype' from or . | +| test.cpp:176:35:176:42 | iswctype | Address taken for banned character handling function 'iswctype' from or . | +| test.cpp:177:37:177:43 | wctrans | Address taken for banned character handling function 'wctrans' from or . | +| test.cpp:178:39:178:47 | towctrans | Address taken for banned character handling function 'towctrans' from or . | diff --git a/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref new file mode 100644 index 000000000..a2ac2abea --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref @@ -0,0 +1 @@ +rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-1/test.cpp b/cpp/misra/test/rules/RULE-24-5-1/test.cpp new file mode 100644 index 000000000..6c06441c8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-1/test.cpp @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include + +void test_cctype_functions() { + char l1 = 'A'; + + // Character classification functions from + std::isalnum(l1); // NON_COMPLIANT + std::isalpha(l1); // NON_COMPLIANT + std::isblank(l1); // NON_COMPLIANT + std::iscntrl(l1); // NON_COMPLIANT + std::isdigit(l1); // NON_COMPLIANT + std::isgraph(l1); // NON_COMPLIANT + std::islower(l1); // NON_COMPLIANT + std::isprint(l1); // NON_COMPLIANT + std::ispunct(l1); // NON_COMPLIANT + std::isspace(l1); // NON_COMPLIANT + std::isupper(l1); // NON_COMPLIANT + std::isxdigit(l1); // NON_COMPLIANT + + // Character case mapping functions from + std::tolower(l1); // NON_COMPLIANT + std::toupper(l1); // NON_COMPLIANT +} + +void test_ctype_h_functions() { + char l1 = 'A'; + + // Character classification functions from + isalnum(l1); // NON_COMPLIANT + isalpha(l1); // NON_COMPLIANT + isblank(l1); // NON_COMPLIANT + iscntrl(l1); // NON_COMPLIANT + isdigit(l1); // NON_COMPLIANT + isgraph(l1); // NON_COMPLIANT + islower(l1); // NON_COMPLIANT + isprint(l1); // NON_COMPLIANT + ispunct(l1); // NON_COMPLIANT + isspace(l1); // NON_COMPLIANT + isupper(l1); // NON_COMPLIANT + isxdigit(l1); // NON_COMPLIANT + + // Character case mapping functions from + tolower(l1); // NON_COMPLIANT + toupper(l1); // NON_COMPLIANT +} + +void test_cwctype_functions() { + wchar_t l1 = L'A'; + + // Wide character classification functions from + std::iswalnum(l1); // NON_COMPLIANT + std::iswalpha(l1); // NON_COMPLIANT + std::iswblank(l1); // NON_COMPLIANT + std::iswcntrl(l1); // NON_COMPLIANT + std::iswdigit(l1); // NON_COMPLIANT + std::iswgraph(l1); // NON_COMPLIANT + std::iswlower(l1); // NON_COMPLIANT + std::iswprint(l1); // NON_COMPLIANT + std::iswpunct(l1); // NON_COMPLIANT + std::iswspace(l1); // NON_COMPLIANT + std::iswupper(l1); // NON_COMPLIANT + std::iswxdigit(l1); // NON_COMPLIANT + + // Wide character case mapping functions from + std::towlower(l1); // NON_COMPLIANT + std::towupper(l1); // NON_COMPLIANT + + // Wide character type functions from + std::wctype("alpha"); // NON_COMPLIANT + std::iswctype(l1, std::wctype("alpha")); // NON_COMPLIANT + std::wctrans("tolower"); // NON_COMPLIANT + std::towctrans(l1, std::wctrans("tolower")); // NON_COMPLIANT +} + +void test_wctype_h_functions() { + wchar_t l1 = L'A'; + + // Wide character classification functions from + iswalnum(l1); // NON_COMPLIANT + iswalpha(l1); // NON_COMPLIANT + iswblank(l1); // NON_COMPLIANT + iswcntrl(l1); // NON_COMPLIANT + iswdigit(l1); // NON_COMPLIANT + iswgraph(l1); // NON_COMPLIANT + iswlower(l1); // NON_COMPLIANT + iswprint(l1); // NON_COMPLIANT + iswpunct(l1); // NON_COMPLIANT + iswspace(l1); // NON_COMPLIANT + iswupper(l1); // NON_COMPLIANT + iswxdigit(l1); // NON_COMPLIANT + + // Wide character case mapping functions from + towlower(l1); // NON_COMPLIANT + towupper(l1); // NON_COMPLIANT + + // Wide character type functions from + wctype("alpha"); // NON_COMPLIANT + iswctype(l1, wctype("alpha")); // NON_COMPLIANT + wctrans("tolower"); // NON_COMPLIANT + towctrans(l1, wctrans("tolower")); // NON_COMPLIANT +} + +void test_function_addresses() { + // Taking addresses of functions from + int (*l1)(int) = &std::isalnum; // NON_COMPLIANT + int (*l2)(int) = &std::isalpha; // NON_COMPLIANT + int (*l3)(int) = &std::isblank; // NON_COMPLIANT + int (*l4)(int) = &std::iscntrl; // NON_COMPLIANT + int (*l5)(int) = &std::isdigit; // NON_COMPLIANT + int (*l6)(int) = &std::isgraph; // NON_COMPLIANT + int (*l7)(int) = &std::islower; // NON_COMPLIANT + int (*l8)(int) = &std::isprint; // NON_COMPLIANT + int (*l9)(int) = &std::ispunct; // NON_COMPLIANT + int (*l10)(int) = &std::isspace; // NON_COMPLIANT + int (*l11)(int) = &std::isupper; // NON_COMPLIANT + int (*l12)(int) = &std::isxdigit; // NON_COMPLIANT + int (*l13)(int) = &std::tolower; // NON_COMPLIANT + int (*l14)(int) = &std::toupper; // NON_COMPLIANT + + // Taking addresses of functions from + int (*l15)(int) = &isalnum; // NON_COMPLIANT + int (*l16)(int) = &isalpha; // NON_COMPLIANT + int (*l17)(int) = &isblank; // NON_COMPLIANT + int (*l18)(int) = &iscntrl; // NON_COMPLIANT + int (*l19)(int) = &isdigit; // NON_COMPLIANT + int (*l20)(int) = &isgraph; // NON_COMPLIANT + int (*l21)(int) = &islower; // NON_COMPLIANT + int (*l22)(int) = &isprint; // NON_COMPLIANT + int (*l23)(int) = &ispunct; // NON_COMPLIANT + int (*l24)(int) = &isspace; // NON_COMPLIANT + int (*l25)(int) = &isupper; // NON_COMPLIANT + int (*l26)(int) = &isxdigit; // NON_COMPLIANT + int (*l27)(int) = &tolower; // NON_COMPLIANT + int (*l28)(int) = &toupper; // NON_COMPLIANT + + // Taking addresses of functions from + int (*l29)(wint_t) = &std::iswalnum; // NON_COMPLIANT + int (*l30)(wint_t) = &std::iswalpha; // NON_COMPLIANT + int (*l31)(wint_t) = &std::iswblank; // NON_COMPLIANT + int (*l32)(wint_t) = &std::iswcntrl; // NON_COMPLIANT + int (*l33)(wint_t) = &std::iswdigit; // NON_COMPLIANT + int (*l34)(wint_t) = &std::iswgraph; // NON_COMPLIANT + int (*l35)(wint_t) = &std::iswlower; // NON_COMPLIANT + int (*l36)(wint_t) = &std::iswprint; // NON_COMPLIANT + int (*l37)(wint_t) = &std::iswpunct; // NON_COMPLIANT + int (*l38)(wint_t) = &std::iswspace; // NON_COMPLIANT + int (*l39)(wint_t) = &std::iswupper; // NON_COMPLIANT + int (*l40)(wint_t) = &std::iswxdigit; // NON_COMPLIANT + wint_t (*l41)(wint_t) = &std::towlower; // NON_COMPLIANT + wint_t (*l42)(wint_t) = &std::towupper; // NON_COMPLIANT + wctype_t (*l43)(const char *) = &std::wctype; // NON_COMPLIANT + int (*l44)(wint_t, wctype_t) = &std::iswctype; // NON_COMPLIANT + wctrans_t (*l45)(const char *) = &std::wctrans; // NON_COMPLIANT + wint_t (*l46)(wint_t, wctrans_t) = &std::towctrans; // NON_COMPLIANT + + // Taking addresses of functions from + int (*l47)(wint_t) = &iswalnum; // NON_COMPLIANT + int (*l48)(wint_t) = &iswalpha; // NON_COMPLIANT + int (*l49)(wint_t) = &iswblank; // NON_COMPLIANT + int (*l50)(wint_t) = &iswcntrl; // NON_COMPLIANT + int (*l51)(wint_t) = &iswdigit; // NON_COMPLIANT + int (*l52)(wint_t) = &iswgraph; // NON_COMPLIANT + int (*l53)(wint_t) = &iswlower; // NON_COMPLIANT + int (*l54)(wint_t) = &iswprint; // NON_COMPLIANT + int (*l55)(wint_t) = &iswpunct; // NON_COMPLIANT + int (*l56)(wint_t) = &iswspace; // NON_COMPLIANT + int (*l57)(wint_t) = &iswupper; // NON_COMPLIANT + int (*l58)(wint_t) = &iswxdigit; // NON_COMPLIANT + wint_t (*l59)(wint_t) = &towlower; // NON_COMPLIANT + wint_t (*l60)(wint_t) = &towupper; // NON_COMPLIANT + wctype_t (*l61)(const char *) = &wctype; // NON_COMPLIANT + int (*l62)(wint_t, wctype_t) = &iswctype; // NON_COMPLIANT + wctrans_t (*l63)(const char *) = &wctrans; // NON_COMPLIANT + wint_t (*l64)(wint_t, wctrans_t) = &towctrans; // NON_COMPLIANT +} + +void test_compliant_locale_usage() { + char l1 = 'A'; + wchar_t l2 = L'A'; + std::locale l3{}; + + // Compliant usage with locale parameter + std::isalnum(l1, l3); // COMPLIANT + std::isalpha(l1, l3); // COMPLIANT + std::isblank(l1, l3); // COMPLIANT + std::iscntrl(l1, l3); // COMPLIANT + std::isdigit(l1, l3); // COMPLIANT + std::isgraph(l1, l3); // COMPLIANT + std::islower(l1, l3); // COMPLIANT + std::isprint(l1, l3); // COMPLIANT + std::ispunct(l1, l3); // COMPLIANT + std::isspace(l1, l3); // COMPLIANT + std::isupper(l1, l3); // COMPLIANT + std::isxdigit(l1, l3); // COMPLIANT + + std::tolower(l1, l3); // COMPLIANT + std::toupper(l1, l3); // COMPLIANT + + // Compliant wide character usage with locale parameter + std::isalnum(l2, l3); // COMPLIANT + std::isalpha(l2, l3); // COMPLIANT + std::isblank(l2, l3); // COMPLIANT + std::iscntrl(l2, l3); // COMPLIANT + std::isdigit(l2, l3); // COMPLIANT + std::isgraph(l2, l3); // COMPLIANT + std::islower(l2, l3); // COMPLIANT + std::isprint(l2, l3); // COMPLIANT + std::ispunct(l2, l3); // COMPLIANT + std::isspace(l2, l3); // COMPLIANT + std::isupper(l2, l3); // COMPLIANT + std::isxdigit(l2, l3); // COMPLIANT + + std::tolower(l2, l3); // COMPLIANT + std::toupper(l2, l3); // COMPLIANT +} \ No newline at end of file From ed16770370f7683f7b4fdd798188dd718ce51341 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 15:20:46 +0100 Subject: [PATCH 27/36] Rule 24.5.1 - improve structure/consistency of query --- .../CharacterHandlingFunctionRestrictions.ql | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql index 6a779b0e6..d3dba3c34 100644 --- a/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql +++ b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql @@ -20,23 +20,25 @@ import codingstandards.cpp.BannedFunctions class BannedCharacterHandlingFunction extends Function { BannedCharacterHandlingFunction() { this.hasGlobalOrStdName([ - "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", - "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper", - "iswalnum", "iswalpha", "iswblank", "iswcntrl", "iswctype", "iswdigit", "iswgraph", - "iswlower", "iswprint", "iswpunct", "iswspace", "iswupper", "iswxdigit", "towctrans", - "towlower", "towupper", "wctrans", "wctype" - ]) and - not ( - this.hasGlobalOrStdName([ "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", - "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper" + "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper", "iswalnum", "iswalpha", + "iswblank", "iswcntrl", "iswctype", "iswdigit", "iswgraph", "iswlower", "iswprint", + "iswpunct", "iswspace", "iswupper", "iswxdigit", "towctrans", "towlower", "towupper", + "wctrans", "wctype" ]) and - this.getACallToThisFunction().(FunctionCall).getNumberOfArguments() = 2 - ) + // Exclude the functions which pass a reference to a std::locale as the second parameter + not this.getParameter(1) + .getType() + .getUnspecifiedType() + .(ReferenceType) + .getBaseType() + .(UserType) + .hasQualifiedName("std", "locale") } } from BannedFunctions::Use use -where - not isExcluded(use, BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery()) -select use, use.getAction() + " banned character handling function '" + use.getFunctionName() + "' from or ." \ No newline at end of file +where not isExcluded(use, BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery()) +select use, + use.getAction() + " banned character handling function '" + use.getFunctionName() + + "' from or ." From 18e014316df844ee6b94935c7171e2485a2d796b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 17:24:47 +0100 Subject: [PATCH 28/36] Extend C++ stubs for locale --- .../test/includes/standard-library/locale | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/cpp/common/test/includes/standard-library/locale b/cpp/common/test/includes/standard-library/locale index 4d19e3dba..755c5f6ee 100644 --- a/cpp/common/test/includes/standard-library/locale +++ b/cpp/common/test/includes/standard-library/locale @@ -2,9 +2,45 @@ #ifndef _GHLIBCPP_LOCALE #define _GHLIBCPP_LOCALE +#include + namespace std { -class locale {}; +class locale { +public: + class facet; + class id; + typedef int category; + + static const category none = 0, collate = 0x010, ctype = 0x020, + monetary = 0x040, numeric = 0x080, time = 0x100, + messages = 0x200, + all = collate | ctype | monetary | numeric | time | + messages; + + locale() noexcept; + locale(const locale &other) noexcept; + explicit locale(const char *std_name); + explicit locale(const string &std_name); + locale(const locale &other, const char *std_name, category); + locale(const locale &other, const string &std_name, category); + template locale(const locale &other, Facet *f); + locale(const locale &other, const locale &one, category); + ~locale(); + const locale &operator=(const locale &other) noexcept; + template locale combine(const locale &other) const; + + basic_string name() const; + + bool operator==(const locale &other) const; + bool operator!=(const locale &other) const; + template + bool operator()(const basic_string &s1, + const basic_string &s2) const; + + static locale global(const locale &); + static const locale &classic(); +}; template bool isspace(charT c, const locale &loc); template bool isprint(charT c, const locale &loc); From 367a18a889055f3f6ef7fd3dce12499ecbad84cd Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 17:26:39 +0100 Subject: [PATCH 29/36] Rule 25.5.1 - LocaleGlobalFunctionNotAllowed.ql Add query for banned locale functions. [a] --- .../LocaleGlobalFunctionNotAllowed.ql | 28 +++++++++++ .../LocaleGlobalFunctionNotAllowed.expected | 9 ++++ .../LocaleGlobalFunctionNotAllowed.qlref | 1 + cpp/misra/test/rules/RULE-25-5-1/test.cpp | 47 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql create mode 100644 cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected create mode 100644 cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref create mode 100644 cpp/misra/test/rules/RULE-25-5-1/test.cpp diff --git a/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql b/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql new file mode 100644 index 000000000..5072da978 --- /dev/null +++ b/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql @@ -0,0 +1,28 @@ +/** + * @id cpp/misra/locale-global-function-not-allowed + * @name RULE-25-5-1: The setlocale and std::locale::global functions shall not be called + * @description Calling setlocale or std::locale::global functions can introduce data races with + * functions that use the locale, leading to undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-25-5-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class BannedLocaleFunction extends Function { + BannedLocaleFunction() { + this.hasGlobalOrStdName("setlocale") or + this.hasQualifiedName("std", "locale", "global") + } +} + +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::localeGlobalFunctionNotAllowedQuery()) +select use, use.getAction() + " banned function '" + use.getFunctionName() + "' from ." diff --git a/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected new file mode 100644 index 000000000..fde7f610e --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected @@ -0,0 +1,9 @@ +| test.cpp:6:3:6:16 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:7:3:7:16 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:8:3:8:16 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:12:3:12:21 | call to global | Call to banned function 'global' from . | +| test.cpp:13:3:13:21 | call to global | Call to banned function 'global' from . | +| test.cpp:36:5:36:18 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:40:5:40:18 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:45:3:45:21 | call to global | Call to banned function 'global' from . | +| test.cpp:46:3:46:21 | call to global | Call to banned function 'global' from . | diff --git a/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref new file mode 100644 index 000000000..f28199a5a --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref @@ -0,0 +1 @@ +rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-25-5-1/test.cpp b/cpp/misra/test/rules/RULE-25-5-1/test.cpp new file mode 100644 index 000000000..b45be36f7 --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-1/test.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +void test_setlocale_call() { + std::setlocale(LC_ALL, "C"); // NON_COMPLIANT + std::setlocale(LC_NUMERIC, "C"); // NON_COMPLIANT + std::setlocale(LC_TIME, "en_US.UTF-8"); // NON_COMPLIANT +} + +void test_locale_global_call() { + std::locale::global(std::locale("C")); // NON_COMPLIANT + std::locale::global(std::locale::classic()); // NON_COMPLIANT +} + +void test_compliant_locale_usage() { + wchar_t l1 = L'\u2002'; + std::locale l2("C"); + + if (std::isspace(l1, l2)) { // COMPLIANT + } + if (std::isalpha(l1, l2)) { // COMPLIANT + } + if (std::isdigit(l1, l2)) { // COMPLIANT + } +} + +void test_compliant_locale_construction() { + std::locale l3("C"); // COMPLIANT + std::locale l4 = std::locale::classic(); // COMPLIANT + std::locale l5; // COMPLIANT +} + +void test_nested_setlocale_calls() { + if (true) { + std::setlocale(LC_ALL, "ja_JP.utf8"); // NON_COMPLIANT + } + + for (int l6 = 0; l6 < 1; ++l6) { + std::setlocale(LC_CTYPE, "C"); // NON_COMPLIANT + } +} + +void test_locale_global_with_different_locales() { + std::locale::global(std::locale("en_US.UTF-8")); // NON_COMPLIANT + std::locale::global(std::locale("ja_JP.utf8")); // NON_COMPLIANT +} \ No newline at end of file From 8485924bf6f377357344010d9b7337eadaca7c4e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 17:28:13 +0100 Subject: [PATCH 30/36] Rule 24-5-2 - NoMemoryFunctionsFromCString.ql Adds a new query to detect use of banned cstring functions. [a] --- .../NoMemoryFunctionsFromCString.ql | 26 ++++++ .../NoMemoryFunctionsFromCString.expected | 23 +++++ .../NoMemoryFunctionsFromCString.qlref | 1 + cpp/misra/test/rules/RULE-24-5-2/test.cpp | 89 +++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql create mode 100644 cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected create mode 100644 cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref create mode 100644 cpp/misra/test/rules/RULE-24-5-2/test.cpp diff --git a/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql b/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql new file mode 100644 index 000000000..17bca5c0e --- /dev/null +++ b/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/no-memory-functions-from-c-string + * @name RULE-24-5-2: The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used + * @description Using memcpy, memmove or memcmp from can result in undefined behavior due + * to overlapping memory, non-trivially copyable objects, or unequal comparison of + * logically equal objects. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-24-5-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class BannedMemoryFunction extends Function { + BannedMemoryFunction() { this.hasGlobalOrStdName(["memcpy", "memmove", "memcmp"]) } +} + +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::noMemoryFunctionsFromCStringQuery()) +select use, use.getAction() + " banned function '" + use.getFunctionName() + "' from ." diff --git a/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected new file mode 100644 index 000000000..49ce89347 --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected @@ -0,0 +1,23 @@ +| test.cpp:9:3:9:8 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:10:3:10:13 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:17:3:17:9 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:18:3:18:14 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:25:12:25:17 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:26:12:26:22 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:30:52:30:57 | memcpy | Address taken for banned function 'memcpy' from . | +| test.cpp:31:52:31:58 | memmove | Address taken for banned function 'memmove' from . | +| test.cpp:32:56:32:61 | memcmp | Address taken for banned function 'memcmp' from . | +| test.cpp:34:52:34:62 | memcpy | Address taken for banned function 'memcpy' from . | +| test.cpp:36:7:36:18 | memmove | Address taken for banned function 'memmove' from . | +| test.cpp:38:7:38:17 | memcmp | Address taken for banned function 'memcmp' from . | +| test.cpp:50:7:50:12 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:53:7:53:17 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:61:7:61:12 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:64:7:64:17 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:71:3:71:8 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:72:3:72:9 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:74:3:74:13 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:75:3:75:14 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:78:1:78:28 | #define CUSTOM_MEMCPY memcpy | Call to banned function 'memcpy' from . | +| test.cpp:79:1:79:30 | #define CUSTOM_MEMMOVE memmove | Call to banned function 'memmove' from . | +| test.cpp:80:1:80:28 | #define CUSTOM_MEMCMP memcmp | Call to banned function 'memcmp' from . | diff --git a/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref new file mode 100644 index 000000000..53307ad85 --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref @@ -0,0 +1 @@ +rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-2/test.cpp b/cpp/misra/test/rules/RULE-24-5-2/test.cpp new file mode 100644 index 000000000..f189afdbc --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-2/test.cpp @@ -0,0 +1,89 @@ +#include +#include +#include + +void test_memcpy_usage() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + memcpy(l1, l2, 10); // NON_COMPLIANT + std::memcpy(l1, l2, 10); // NON_COMPLIANT +} + +void test_memmove_usage() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + memmove(l1, l2, 10); // NON_COMPLIANT + std::memmove(l1, l2, 10); // NON_COMPLIANT +} + +void test_memcmp_usage() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + int l3 = memcmp(l1, l2, 10); // NON_COMPLIANT + int l4 = std::memcmp(l1, l2, 10); // NON_COMPLIANT +} + +void test_function_pointers() { + void *(*l1)(void *, const void *, std::size_t) = memcpy; // NON_COMPLIANT + void *(*l2)(void *, const void *, std::size_t) = memmove; // NON_COMPLIANT + int (*l3)(const void *, const void *, std::size_t) = memcmp; // NON_COMPLIANT + + void *(*l4)(void *, const void *, std::size_t) = std::memcpy; // NON_COMPLIANT + void *(*l5)(void *, const void *, std::size_t) = + std::memmove; // NON_COMPLIANT + int (*l6)(const void *, const void *, std::size_t) = + std::memcmp; // NON_COMPLIANT +} + +struct S { + bool m1; + std::int64_t m2; +}; + +void test_struct_comparison() { + S l1{true, 42}; + S l2{true, 42}; + + if (memcmp(&l1, &l2, sizeof(S)) != 0) { // NON_COMPLIANT + } + + if (std::memcmp(&l1, &l2, sizeof(S)) != 0) { // NON_COMPLIANT + } +} + +void test_buffer_comparison() { + char l1[12]; + char l2[12]; + + if (memcmp(l1, l2, sizeof(l1)) != 0) { // NON_COMPLIANT + } + + if (std::memcmp(l1, l2, sizeof(l1)) != 0) { // NON_COMPLIANT + } +} + +void test_overlapping_memory() { + std::uint8_t l1[20]; + + memcpy(l1 + 5, l1, 10); // NON_COMPLIANT + memmove(l1 + 5, l1, 10); // NON_COMPLIANT + + std::memcpy(l1 + 5, l1, 10); // NON_COMPLIANT + std::memmove(l1 + 5, l1, 10); // NON_COMPLIANT +} + +#define CUSTOM_MEMCPY memcpy // NON_COMPLIANT +#define CUSTOM_MEMMOVE memmove // NON_COMPLIANT +#define CUSTOM_MEMCMP memcmp // NON_COMPLIANT + +void test_macro_expansion() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + CUSTOM_MEMCPY(l1, l2, 10); + CUSTOM_MEMMOVE(l1, l2, 10); + int l3 = CUSTOM_MEMCMP(l1, l2, 10); +} \ No newline at end of file From e26f32afacc866e9eb2370e008ccf19b98cff71e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 18:08:23 +0100 Subject: [PATCH 31/36] Rule 21.10.2 - NoCsetjmpHeader.ql New query to detect banned uses of the csetjmp header. [a] --- .../src/rules/RULE-21-10-2/NoCsetjmpHeader.ql | 53 +++++++++++++++++++ .../RULE-21-10-2/NoCsetjmpHeader.expected | 14 +++++ .../rules/RULE-21-10-2/NoCsetjmpHeader.qlref | 1 + cpp/misra/test/rules/RULE-21-10-2/test.cpp | 38 +++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql create mode 100644 cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected create mode 100644 cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref create mode 100644 cpp/misra/test/rules/RULE-21-10-2/test.cpp diff --git a/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql new file mode 100644 index 000000000..4cfc7770a --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql @@ -0,0 +1,53 @@ +/** + * @id cpp/misra/no-csetjmp-header + * @name RULE-21-10-2: The standard header file shall not be used + * @description Using facilities from the header causes undefined behavior by bypassing + * normal function return mechanisms and may result in non-trivial object destruction + * being omitted. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-10-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class CSetJmpHeader extends Include { + CSetJmpHeader() { this.getIncludeText().regexpMatch("[<\\\"](csetjmp|setjmp.h)[>\\\"]") } +} + +class JmpBufVariable extends Variable { + JmpBufVariable() { this.getType().(UserType).hasGlobalOrStdName("jmp_buf") } +} + +class LongjmpFunction extends Function { + LongjmpFunction() { this.hasGlobalOrStdName("longjmp") } +} + +class SetjmpMacroInvocation extends MacroInvocation { + SetjmpMacroInvocation() { this.getMacroName() = "setjmp" } +} + +from Element element, string message +where + not isExcluded(element, BannedAPIsPackage::noCsetjmpHeaderQuery()) and + ( + message = "Use of banned header " + element.(CSetJmpHeader).getIncludeText() + "." + or + message = + "Declaration of variable '" + element.(JmpBufVariable).getName() + + "' with banned type 'jmp_buf'." + or + message = + element.(BannedFunctions::Use).getAction() + " banned function '" + + element.(BannedFunctions::Use).getFunctionName() + "'." + or + element instanceof SetjmpMacroInvocation and + message = "Use of banned macro 'setjmp'." + ) +select element, message diff --git a/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected new file mode 100644 index 000000000..6ac8e4148 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected @@ -0,0 +1,14 @@ +| test.cpp:1:1:1:18 | #include "csetjmp" | Use of banned header "csetjmp". | +| test.cpp:2:1:2:19 | #include "setjmp.h" | Use of banned header "setjmp.h". | +| test.cpp:3:1:3:18 | #include | Use of banned header . | +| test.cpp:4:1:4:19 | #include | Use of banned header . | +| test.cpp:8:9:8:10 | g1 | Declaration of variable 'g1' with banned type 'jmp_buf'. | +| test.cpp:9:14:9:15 | g2 | Declaration of variable 'g2' with banned type 'jmp_buf'. | +| test.cpp:12:11:12:12 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | +| test.cpp:13:7:13:16 | setjmp(env) | Use of banned macro 'setjmp'. | +| test.cpp:14:5:14:11 | call to longjmp | Call to banned function 'longjmp'. | +| test.cpp:19:16:19:17 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | +| test.cpp:20:7:20:16 | setjmp(env) | Use of banned macro 'setjmp'. | +| test.cpp:21:5:21:16 | call to longjmp | Call to banned function 'longjmp'. | +| test.cpp:26:11:26:12 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | +| test.cpp:27:16:27:17 | l2 | Declaration of variable 'l2' with banned type 'jmp_buf'. | diff --git a/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref new file mode 100644 index 000000000..8e0712349 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref @@ -0,0 +1 @@ +rules/RULE-21-10-2/NoCsetjmpHeader.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-2/test.cpp b/cpp/misra/test/rules/RULE-21-10-2/test.cpp new file mode 100644 index 000000000..8fbed1953 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-2/test.cpp @@ -0,0 +1,38 @@ +#include "csetjmp" // NON_COMPLIANT +#include "setjmp.h" // NON_COMPLIANT +#include // NON_COMPLIANT +#include // NON_COMPLIANT +#include + +// Global variables for testing +jmp_buf g1; // NON_COMPLIANT +std::jmp_buf g2; // NON_COMPLIANT + +void test_setjmp_usage() { + jmp_buf l1; // NON_COMPLIANT + if (setjmp(l1) == 0) { // NON_COMPLIANT + longjmp(l1, 1); // NON_COMPLIANT + } +} + +void test_std_setjmp_usage() { + std::jmp_buf l1; // NON_COMPLIANT + if (setjmp(l1) == 0) { // NON_COMPLIANT + std::longjmp(l1, 1); // NON_COMPLIANT + } +} + +void test_jmp_buf_declaration() { + jmp_buf l1; // NON_COMPLIANT + std::jmp_buf l2; // NON_COMPLIANT +} + +void test_compliant_alternative() { + // Using structured exception handling or other alternatives + // instead of setjmp/longjmp + try { + throw std::runtime_error("error"); + } catch (const std::runtime_error &) { // COMPLIANT + // Handle error properly + } +} \ No newline at end of file From c603dba8c9fb0127b9f5cac5adc183df642e6b41 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 23:14:19 +0100 Subject: [PATCH 32/36] Rule 21.10.1 - Formatting and reporting improvements --- .../RULE-21-10-1/NoVariadicFunctionMacros.ql | 16 ++++++++++------ .../NoVariadicFunctionMacros.expected | 1 - 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql index 7e96f7022..fbe82d45c 100644 --- a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql +++ b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql @@ -18,7 +18,6 @@ import codingstandards.cpp.misra class VaListType extends Type { VaListType() { this.getName() = "va_list" or - this.getName() = "__va_list_tag" or this.(SpecifiedType).getBaseType() instanceof VaListType or this.(TypedefType).getBaseType() instanceof VaListType } @@ -29,10 +28,15 @@ where not isExcluded(element, BannedAPIsPackage::noVariadicFunctionMacrosQuery()) and ( element.(Variable).getType() instanceof VaListType and - message = "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'." - or - element.(Parameter).getType() instanceof VaListType and - message = "Declaration of parameter '" + element.(Parameter).getName() + "' of type 'va_list'." + ( + if element instanceof Parameter + then + message = + "Declaration of parameter '" + element.(Parameter).getName() + "' of type 'va_list'." + else + message = + "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'." + ) or element instanceof BuiltInVarArgsStart and message = "Call to 'va_start'." @@ -50,4 +54,4 @@ where message = "Declaration of typedef '" + element.(TypedefType).getName() + "' aliasing 'va_list' type." ) -select element, message \ No newline at end of file +select element, message diff --git a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected index 3c47cc4aa..bb52ced03 100644 --- a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected +++ b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected @@ -16,7 +16,6 @@ | test.cpp:31:3:31:12 | __builtin_va_end | Call to 'va_end'. | | test.cpp:32:3:32:12 | __builtin_va_end | Call to 'va_end'. | | test.cpp:35:37:35:38 | l1 | Declaration of parameter 'l1' of type 'va_list'. | -| test.cpp:35:37:35:38 | l1 | Declaration of variable 'l1' of type 'va_list'. | | test.cpp:36:15:36:32 | __builtin_va_arg | Call to 'va_arg'. | | test.cpp:40:11:40:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | | test.cpp:41:3:41:18 | __builtin_va_start | Call to 'va_start'. | From 55cebdbb247827e5dc10d148e27555f37db3606f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 23:19:12 +0100 Subject: [PATCH 33/36] Move Rule-6-9-2 to FixedWidthInt. --- rules.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.csv b/rules.csv index 68049625e..0af18d1f2 100644 --- a/rules.csv +++ b/rules.csv @@ -869,7 +869,7 @@ cpp,MISRA-C++-2023,RULE-6-8-2,Yes,Mandatory,Decidable,Single Translation Unit,A cpp,MISRA-C++-2023,RULE-6-8-3,Yes,Required,Decidable,Single Translation Unit,An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime,,Lifetime,Medium, cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,Declarations2,Medium, cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,Declarations2,Medium, -cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,BannedAPIs,Easy, +cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,FixedWithInt,Easy, cpp,MISRA-C++-2023,RULE-7-0-1,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion from type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-2,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion to type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-3,Yes,Required,Decidable,Single Translation Unit,The numerical value of a character shall not be used,M5-0-11,Conversions,Medium, From 54fe5ea5d6754f90c394886aa5b6c322c0ab678e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 10 Jun 2025 10:03:52 +0100 Subject: [PATCH 34/36] A3-9-1: Convert to shared query Convert AUTOSAR rule A3-9-1 to a shared query to reuse the implementation for MISRA C++ 2023 Rule 6.9.2. --- .../A3-9-1/VariableWidthIntegerTypesUsed.ql | 28 ++---- .../VariableWidthIntegerTypesUsed.qlref | 1 - .../VariableWidthIntegerTypesUsed.testref | 1 + .../VariableWidthPlainCharTypeUsed.expected | 4 +- cpp/autosar/test/rules/A3-9-1/test.cpp | 86 ++---------------- .../VariableWidthIntegerTypesUsed.qll | 38 ++++++++ .../VariableWidthIntegerTypesUsed.expected | 0 .../VariableWidthIntegerTypesUsed.ql | 4 + .../variablewidthintegertypesused/test.cpp | 89 +++++++++++++++++++ rule_packages/cpp/Declarations.json | 3 +- 10 files changed, 149 insertions(+), 105 deletions(-) delete mode 100644 cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref create mode 100644 cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref create mode 100644 cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll rename cpp/{autosar/test/rules/A3-9-1 => common/test/rules/variablewidthintegertypesused}/VariableWidthIntegerTypesUsed.expected (100%) create mode 100644 cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql create mode 100644 cpp/common/test/rules/variablewidthintegertypesused/test.cpp diff --git a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql index fa19ad998..dfc73cebc 100644 --- a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql +++ b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql @@ -17,26 +17,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.EncapsulatingFunctions -import codingstandards.cpp.BuiltInNumericTypes -import codingstandards.cpp.Type -import codingstandards.cpp.Operator +import codingstandards.cpp.rules.variablewidthintegertypesused.VariableWidthIntegerTypesUsed -from Variable v, Type typeStrippedOfSpecifiers -where - not isExcluded(v, DeclarationsPackage::variableWidthIntegerTypesUsedQuery()) and - typeStrippedOfSpecifiers = stripSpecifiers(v.getType()) and - ( - typeStrippedOfSpecifiers instanceof BuiltInIntegerType or - typeStrippedOfSpecifiers instanceof UnsignedCharType or - typeStrippedOfSpecifiers instanceof SignedCharType - ) and - not v instanceof ExcludedVariable and - // Dont consider template instantiations because instantiations with - // Fixed Width Types are recorded after stripping their typedef'd type, - // thereby, causing false positives (#540). - not v.isFromTemplateInstantiation(_) and - //post-increment/post-decrement operators are required by the standard to have a dummy int parameter - not v.(Parameter).getFunction() instanceof PostIncrementOperator and - not v.(Parameter).getFunction() instanceof PostDecrementOperator -select v, "Variable '" + v.getName() + "' has variable-width type." +class VariableWidthIntegerTypesUsedQuery extends VariableWidthIntegerTypesUsedSharedQuery { + VariableWidthIntegerTypesUsedQuery() { + this = DeclarationsPackage::variableWidthIntegerTypesUsedQuery() + } +} diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref deleted file mode 100644 index 797bbacc9..000000000 --- a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A3-9-1/VariableWidthIntegerTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref new file mode 100644 index 000000000..bb41437be --- /dev/null +++ b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected index 6631606cb..8602920f1 100644 --- a/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected +++ b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected @@ -1,3 +1,3 @@ | test.cpp:4:8:4:8 | c | Variable 'c' has variable-width char type. | -| test.cpp:38:14:38:15 | c1 | Variable 'c1' has variable-width char type. | -| test.cpp:56:17:56:18 | c2 | Variable 'c2' has variable-width char type. | +| test.cpp:10:14:10:15 | c1 | Variable 'c1' has variable-width char type. | +| test.cpp:14:17:14:18 | c2 | Variable 'c2' has variable-width char type. | diff --git a/cpp/autosar/test/rules/A3-9-1/test.cpp b/cpp/autosar/test/rules/A3-9-1/test.cpp index 7ffb87ca3..96ef45142 100644 --- a/cpp/autosar/test/rules/A3-9-1/test.cpp +++ b/cpp/autosar/test/rules/A3-9-1/test.cpp @@ -2,88 +2,16 @@ void test_variable_width_type_variables() { char c; // NON_COMPLIANT - unsigned char uc; // NON_COMPLIANT - signed char sc; // NON_COMPLIANT - - int i; // NON_COMPLIANT - unsigned int ui; // NON_COMPLIANT - unsigned u; // NON_COMPLIANT - signed int si; // NON_COMPLIANT - signed s; // NON_COMPLIANT - - short sh; // NON_COMPLIANT - unsigned short ush; // NON_COMPLIANT - signed short ssh; // NON_COMPLIANT - - long l; // NON_COMPLIANT - unsigned long ul; // NON_COMPLIANT - signed long sl; // NON_COMPLIANT - - std::int8_t i8; // COMPLIANT - std::int16_t i16; // COMPLIANT - std::int32_t i32; // COMPLIANT - std::int64_t i64; // COMPLIANT - - std::uint8_t u8; // COMPLIANT - std::uint16_t u16; // COMPLIANT - std::uint32_t u32; // COMPLIANT - std::uint64_t u64; // COMPLIANT -} - -int main(int argc, char *argv[]) { // COMPLIANT - // main as an exception + unsigned char uc; // COMPLIANT - covered by VariableWidthIntegerTypesUsed + signed char sc; // COMPLIANT - covered by VariableWidthIntegerTypesUsed } void test_variable_width_type_qualified_variables() { const char c1 = 0; // NON_COMPLIANT - const unsigned char uc1 = 0; // NON_COMPLIANT - const signed char sc1 = 0; // NON_COMPLIANt - - const int i1 = 0; // NON_COMPLIANT - const unsigned int ui1 = 0; // NON_COMPLIANT - const unsigned u1 = 0; // NON_COMPLIANT - const signed int si1 = 0; // NON_COMPLIANT - const signed s1 = 0; // NON_COMPLIANT - - const short sh1 = 0; // NON_COMPLIANT - const unsigned short ush1 = 0; // NON_COMPLIANT - const signed short ssh1 = 0; // NON_COMPLIANT - - const long l1 = 0; // NON_COMPLIANT - const unsigned long ul1 = 0; // NON_COMPLIANT - const signed long sl1 = 0; // NON_COMPLIANT + const unsigned char uc1 = 0; // COMPLIANT - (VariableWidthIntegerTypesUsed) + const signed char sc1 = 0; // COMPLIANT - (VariableWidthIntegerTypesUsed) volatile char c2; // NON_COMPLIANT - volatile unsigned char uc2; // NON_COMPLIANT - volatile signed char sc2; // NON_COMPLIANt - - volatile int i2; // NON_COMPLIANT - volatile unsigned int ui2; // NON_COMPLIANT - volatile unsigned u2; // NON_COMPLIANT - volatile signed int si2; // NON_COMPLIANT - volatile signed s2; // NON_COMPLIANT - - volatile short sh2; // NON_COMPLIANT - volatile unsigned short ush2; // NON_COMPLIANT - volatile signed short ssh2; // NON_COMPLIANT - - volatile long l2; // NON_COMPLIANT - volatile unsigned long ul2; // NON_COMPLIANT - volatile signed long sl2; // NON_COMPLIANT -} - -struct test_fix_fp_614 { - test_fix_fp_614 operator++(int); // COMPLIANT - test_fix_fp_614 operator--(int); // COMPLIANT -}; - -// COMPLIANT - instantiated with Fixed Width Types. -template constexpr void test_fix_fp_540(MyType value) { - value++; -} - -int call_test_fix_fp_540() { - test_fix_fp_540(19); - test_fix_fp_540(20); - return 0; -} + volatile unsigned char uc2; // COMPLIANT - (VariableWidthIntegerTypesUsed) + volatile signed char sc2; // COMPLIANT - (VariableWidthIntegerTypesUsed) +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll new file mode 100644 index 000000000..ce9aaf5fe --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll @@ -0,0 +1,38 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The basic numerical types of signed/unsigned char, int, short, long are not supposed + * to be used. The specific-length types from header need be used instead. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.EncapsulatingFunctions +import codingstandards.cpp.BuiltInNumericTypes +import codingstandards.cpp.Type +import codingstandards.cpp.Operator + +abstract class VariableWidthIntegerTypesUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof VariableWidthIntegerTypesUsedSharedQuery } + +query predicate problems(Variable v, string message) { + not isExcluded(v, getQuery()) and + exists(Type typeStrippedOfSpecifiers | + typeStrippedOfSpecifiers = stripSpecifiers(v.getType()) and + ( + typeStrippedOfSpecifiers instanceof BuiltInIntegerType or + typeStrippedOfSpecifiers instanceof UnsignedCharType or + typeStrippedOfSpecifiers instanceof SignedCharType + ) and + not v instanceof ExcludedVariable and + // Dont consider template instantiations because instantiations with + // Fixed Width Types are recorded after stripping their typedef'd type, + // thereby, causing false positives (#540). + not v.isFromTemplateInstantiation(_) and + //post-increment/post-decrement operators are required by the standard to have a dummy int parameter + not v.(Parameter).getFunction() instanceof PostIncrementOperator and + not v.(Parameter).getFunction() instanceof PostDecrementOperator + ) and + message = "Variable '" + v.getName() + "' has variable-width type." +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected similarity index 100% rename from cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected rename to cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected diff --git a/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql new file mode 100644 index 000000000..1c86ca86d --- /dev/null +++ b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.variablewidthintegertypesused.VariableWidthIntegerTypesUsed + +class TestFileQuery extends VariableWidthIntegerTypesUsedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/variablewidthintegertypesused/test.cpp b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp new file mode 100644 index 000000000..b5b390cd9 --- /dev/null +++ b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp @@ -0,0 +1,89 @@ +#include + +void test_variable_width_type_variables() { + char c; // COMPLIANT + unsigned char uc; // NON_COMPLIANT + signed char sc; // NON_COMPLIANT + + int i; // NON_COMPLIANT + unsigned int ui; // NON_COMPLIANT + unsigned u; // NON_COMPLIANT + signed int si; // NON_COMPLIANT + signed s; // NON_COMPLIANT + + short sh; // NON_COMPLIANT + unsigned short ush; // NON_COMPLIANT + signed short ssh; // NON_COMPLIANT + + long l; // NON_COMPLIANT + unsigned long ul; // NON_COMPLIANT + signed long sl; // NON_COMPLIANT + + std::int8_t i8; // COMPLIANT + std::int16_t i16; // COMPLIANT + std::int32_t i32; // COMPLIANT + std::int64_t i64; // COMPLIANT + + std::uint8_t u8; // COMPLIANT + std::uint16_t u16; // COMPLIANT + std::uint32_t u32; // COMPLIANT + std::uint64_t u64; // COMPLIANT +} + +int main(int argc, char *argv[]) { // COMPLIANT + // main as an exception +} + +void test_variable_width_type_qualified_variables() { + const char c1 = 0; // COMPLIANT + const unsigned char uc1 = 0; // NON_COMPLIANT + const signed char sc1 = 0; // NON_COMPLIANt + + const int i1 = 0; // NON_COMPLIANT + const unsigned int ui1 = 0; // NON_COMPLIANT + const unsigned u1 = 0; // NON_COMPLIANT + const signed int si1 = 0; // NON_COMPLIANT + const signed s1 = 0; // NON_COMPLIANT + + const short sh1 = 0; // NON_COMPLIANT + const unsigned short ush1 = 0; // NON_COMPLIANT + const signed short ssh1 = 0; // NON_COMPLIANT + + const long l1 = 0; // NON_COMPLIANT + const unsigned long ul1 = 0; // NON_COMPLIANT + const signed long sl1 = 0; // NON_COMPLIANT + + volatile char c2; // COMPLIANT + volatile unsigned char uc2; // NON_COMPLIANT + volatile signed char sc2; // NON_COMPLIANt + + volatile int i2; // NON_COMPLIANT + volatile unsigned int ui2; // NON_COMPLIANT + volatile unsigned u2; // NON_COMPLIANT + volatile signed int si2; // NON_COMPLIANT + volatile signed s2; // NON_COMPLIANT + + volatile short sh2; // NON_COMPLIANT + volatile unsigned short ush2; // NON_COMPLIANT + volatile signed short ssh2; // NON_COMPLIANT + + volatile long l2; // NON_COMPLIANT + volatile unsigned long ul2; // NON_COMPLIANT + volatile signed long sl2; // NON_COMPLIANT +} + +struct test_fix_fp_614 { + test_fix_fp_614 operator++(int); // COMPLIANT + test_fix_fp_614 operator--(int); // COMPLIANT +}; + +// COMPLIANT - instantiated with Fixed Width Types. +template constexpr void test_fix_fp_540(MyType value) { + value++; +} + +int call_test_fix_fp_540() { + test_fix_fp_540(19); + test_fix_fp_540(20); + return 0; +} diff --git a/rule_packages/cpp/Declarations.json b/rule_packages/cpp/Declarations.json index a5b8ebeec..2f9651e19 100644 --- a/rule_packages/cpp/Declarations.json +++ b/rule_packages/cpp/Declarations.json @@ -93,7 +93,8 @@ ], "implementation_scope": { "description": "This implementation excludes the plain char type from consideration." - } + }, + "shared_implementation_short_name": "VariableWidthIntegerTypesUsed" }, { "description": "The basic numerical type char is not supposed to be used. The specific-length types from header need be used instead.", From 5b37d13bede9c1eeabb963edf3541d7255f5acc2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 10 Jun 2025 10:10:11 +0100 Subject: [PATCH 35/36] Rule 6.9.2: AvoidStandardIntegerTypeNames.ql Adds a new query for detecting the use of the standard integer types. --- .../cpp/exclusions/cpp/BannedAPIs.qll | 19 ++++++++++++++- .../AvoidStandardIntegerTypeNames.ql | 23 +++++++++++++++++++ .../AvoidStandardIntegerTypeNames.testref | 1 + rule_packages/cpp/BannedAPIs.json | 21 +++++++++++++++++ rules.csv | 2 +- 5 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql create mode 100644 cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll index 571a48a62..ea4f78841 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll @@ -12,7 +12,8 @@ newtype BannedAPIsQuery = TUseSmartPtrFactoryFunctionsQuery() or TCharacterHandlingFunctionRestrictionsQuery() or TNoMemoryFunctionsFromCStringQuery() or - TLocaleGlobalFunctionNotAllowedQuery() + TLocaleGlobalFunctionNotAllowedQuery() or + TAvoidStandardIntegerTypeNamesQuery() predicate isBannedAPIsQueryMetadata(Query query, string queryId, string ruleId, string category) { query = @@ -95,6 +96,15 @@ predicate isBannedAPIsQueryMetadata(Query query, string queryId, string ruleId, "cpp/misra/locale-global-function-not-allowed" and ruleId = "RULE-25-5-1" and category = "required" + or + query = + // `Query` instance for the `avoidStandardIntegerTypeNames` query + BannedAPIsPackage::avoidStandardIntegerTypeNamesQuery() and + queryId = + // `@id` for the `avoidStandardIntegerTypeNames` query + "cpp/misra/avoid-standard-integer-type-names" and + ruleId = "RULE-6-9-2" and + category = "advisory" } module BannedAPIsPackage { @@ -160,4 +170,11 @@ module BannedAPIsPackage { // `Query` type for `localeGlobalFunctionNotAllowed` query TQueryCPP(TBannedAPIsPackageQuery(TLocaleGlobalFunctionNotAllowedQuery())) } + + Query avoidStandardIntegerTypeNamesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `avoidStandardIntegerTypeNames` query + TQueryCPP(TBannedAPIsPackageQuery(TAvoidStandardIntegerTypeNamesQuery())) + } } diff --git a/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql b/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql new file mode 100644 index 000000000..ef02deb89 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/avoid-standard-integer-type-names + * @name RULE-6-9-2: The names of the standard signed integer types and standard unsigned integer types should not be + * @description Using standard signed and unsigned integer type names instead of specified width + * types makes storage requirements unclear and implementation-dependent. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-9-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.variablewidthintegertypesused.VariableWidthIntegerTypesUsed + +class AvoidStandardIntegerTypeNamesQuery extends VariableWidthIntegerTypesUsedSharedQuery { + AvoidStandardIntegerTypeNamesQuery() { + this = BannedAPIsPackage::avoidStandardIntegerTypeNamesQuery() + } +} diff --git a/cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref b/cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref new file mode 100644 index 000000000..bb41437be --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref @@ -0,0 +1 @@ +cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql \ No newline at end of file diff --git a/rule_packages/cpp/BannedAPIs.json b/rule_packages/cpp/BannedAPIs.json index 591f50b5e..313b51331 100644 --- a/rule_packages/cpp/BannedAPIs.json +++ b/rule_packages/cpp/BannedAPIs.json @@ -179,6 +179,27 @@ } ], "title": "The setlocale and std::locale::global functions shall not be called" + }, + "RULE-6-9-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using standard signed and unsigned integer type names instead of specified width types makes storage requirements unclear and implementation-dependent.", + "kind": "problem", + "name": "The names of the standard signed integer types and standard unsigned integer types should not be", + "precision": "very-high", + "severity": "error", + "short_name": "AvoidStandardIntegerTypeNames", + "shared_implementation_short_name": "VariableWidthIntegerTypesUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The names of the standard signed integer types and standard unsigned integer types should not be used" } } } \ No newline at end of file diff --git a/rules.csv b/rules.csv index 0af18d1f2..68049625e 100644 --- a/rules.csv +++ b/rules.csv @@ -869,7 +869,7 @@ cpp,MISRA-C++-2023,RULE-6-8-2,Yes,Mandatory,Decidable,Single Translation Unit,A cpp,MISRA-C++-2023,RULE-6-8-3,Yes,Required,Decidable,Single Translation Unit,An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime,,Lifetime,Medium, cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,Declarations2,Medium, cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,Declarations2,Medium, -cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,FixedWithInt,Easy, +cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-7-0-1,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion from type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-2,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion to type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-3,Yes,Required,Decidable,Single Translation Unit,The numerical value of a character shall not be used,M5-0-11,Conversions,Medium, From f43336a0296afa52509ef69bea32cceb38064789 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 10 Jun 2025 10:44:36 +0100 Subject: [PATCH 36/36] VariableWidthIntegerTypesUsed - support function return types Expand support for A3-9-1 and MISRA C++ 2023 6.9.2 to include the use of integers in function return types. --- change_notes/2025-06-10-a3-9-1-functions.md | 2 + .../cpp/BuiltInNumericTypes.qll | 7 ++ .../VariableWidthIntegerTypesUsed.qll | 46 +++++++----- .../variablewidthintegertypesused/test.cpp | 70 ++++++++++++++++++- rule_packages/cpp/Declarations.json | 2 +- 5 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 change_notes/2025-06-10-a3-9-1-functions.md diff --git a/change_notes/2025-06-10-a3-9-1-functions.md b/change_notes/2025-06-10-a3-9-1-functions.md new file mode 100644 index 000000000..8366d2172 --- /dev/null +++ b/change_notes/2025-06-10-a3-9-1-functions.md @@ -0,0 +1,2 @@ + - `A3-9-1` - `VariableWidthIntegerTypesUsed.ql`: + - This query now reports the use of non-fixed width integer types in function return types, with the exception of `char` types and for `main` functions. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll b/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll index b145428a5..b15693081 100644 --- a/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll +++ b/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll @@ -20,3 +20,10 @@ class BuiltInIntegerType extends BuiltInType { class ExcludedVariable extends Parameter { ExcludedVariable() { getFunction() instanceof MainFunction } } + +/** + * Any main function. + */ +class ExcludedFunction extends Function { + ExcludedFunction() { this instanceof MainFunction } +} diff --git a/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll index ce9aaf5fe..047d501a2 100644 --- a/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll +++ b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll @@ -16,23 +16,37 @@ abstract class VariableWidthIntegerTypesUsedSharedQuery extends Query { } Query getQuery() { result instanceof VariableWidthIntegerTypesUsedSharedQuery } -query predicate problems(Variable v, string message) { - not isExcluded(v, getQuery()) and - exists(Type typeStrippedOfSpecifiers | - typeStrippedOfSpecifiers = stripSpecifiers(v.getType()) and +query predicate problems(Element e, string message) { + not isExcluded(e, getQuery()) and + exists(Type typeStrippedOfSpecifiers, Type rawType | + typeStrippedOfSpecifiers = stripSpecifiers(rawType) and ( typeStrippedOfSpecifiers instanceof BuiltInIntegerType or typeStrippedOfSpecifiers instanceof UnsignedCharType or typeStrippedOfSpecifiers instanceof SignedCharType - ) and - not v instanceof ExcludedVariable and - // Dont consider template instantiations because instantiations with - // Fixed Width Types are recorded after stripping their typedef'd type, - // thereby, causing false positives (#540). - not v.isFromTemplateInstantiation(_) and - //post-increment/post-decrement operators are required by the standard to have a dummy int parameter - not v.(Parameter).getFunction() instanceof PostIncrementOperator and - not v.(Parameter).getFunction() instanceof PostDecrementOperator - ) and - message = "Variable '" + v.getName() + "' has variable-width type." -} \ No newline at end of file + ) + | + exists(Variable v | v = e | + v.getType() = rawType and + not v instanceof ExcludedVariable and + // Dont consider template instantiations because instantiations with + // Fixed Width Types are recorded after stripping their typedef'd type, + // thereby, causing false positives (#540). + not v.isFromTemplateInstantiation(_) and + //post-increment/post-decrement operators are required by the standard to have a dummy int parameter + not v.(Parameter).getFunction() instanceof PostIncrementOperator and + not v.(Parameter).getFunction() instanceof PostDecrementOperator and + message = "Variable '" + v.getName() + "' has variable-width type." + ) + or + exists(Function f | f = e | + f.getType() = rawType and + not f instanceof ExcludedFunction and + // Dont consider template instantiations because instantiations with + // Fixed Width Types are recorded after stripping their typedef'd type, + // thereby, causing false positives (#540). + not f.isFromTemplateInstantiation(_) and + message = "Function '" + f.getName() + "' has variable-width return type." + ) + ) +} diff --git a/cpp/common/test/rules/variablewidthintegertypesused/test.cpp b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp index b5b390cd9..bee63342e 100644 --- a/cpp/common/test/rules/variablewidthintegertypesused/test.cpp +++ b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp @@ -82,8 +82,74 @@ template constexpr void test_fix_fp_540(MyType value) { value++; } -int call_test_fix_fp_540() { +void call_test_fix_fp_540() { test_fix_fp_540(19); test_fix_fp_540(20); - return 0; +} + +char test_char_return() { // COMPLIANT + return 'a'; +} +unsigned char test_unsigned_char_return() { // NON_COMPLIANT + return 'b'; +} +signed char test_signed_char_return() { // NON_COMPLIANT + return 'c'; +} +int test_int_return() { // NON_COMPLIANT + return 42; +} +unsigned int test_unsigned_int_return() { // NON_COMPLIANT + return 43; +} +unsigned test_unsigned_return() { // NON_COMPLIANT + return 44; +} +signed int test_signed_int_return() { // NON_COMPLIANT + return 45; +} +signed test_signed_return() { // NON_COMPLIANT + return 46; +} +short test_short_return() { // NON_COMPLIANT + return 47; +} +unsigned short test_unsigned_short_return() { // NON_COMPLIANT + return 48; +} +signed short test_signed_short_return() { // NON_COMPLIANT + return 49; +} +long test_long_return() { // NON_COMPLIANT + return 50; +} +unsigned long test_unsigned_long_return() { // NON_COMPLIANT + return 51; +} +signed long test_signed_long_return() { // NON_COMPLIANT + return 52; +} +std::int8_t test_int8_t_return() { // COMPLIANT + return 53; +} +std::int16_t test_int16_t_return() { // COMPLIANT + return 54; +} +std::int32_t test_int32_t_return() { // COMPLIANT + return 55; +} +std::int64_t test_int64_t_return() { // COMPLIANT + return 56; +} +std::uint8_t test_uint8_t_return() { // COMPLIANT + return 57; +} +std::uint16_t test_uint16_t_return() { // COMPLIANT + return 58; +} +std::uint32_t test_uint32_t_return() { // COMPLIANT + return 59; +} +std::uint64_t test_uint64_t_return() { // COMPLIANT + return 60; } diff --git a/rule_packages/cpp/Declarations.json b/rule_packages/cpp/Declarations.json index 2f9651e19..61d286026 100644 --- a/rule_packages/cpp/Declarations.json +++ b/rule_packages/cpp/Declarations.json @@ -92,7 +92,7 @@ "maintainability" ], "implementation_scope": { - "description": "This implementation excludes the plain char type from consideration." + "description": "This implementation excludes the plain char type. It also excludes the use of standard integer types in the definition of main functions, and the use of an integer parameter in the declaration of postfix operators." }, "shared_implementation_short_name": "VariableWidthIntegerTypesUsed" },