From aab3a88bf9e9f9be34f811d71262dec635236dfb Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 23 Jul 2023 15:08:58 +0100 Subject: [PATCH 01/11] Pointers: 0 is a null pointer constant According to MISRA C 2012 8.11 zero is a null pointer constant, and so should not be flagged as non_compliant. --- c/common/src/codingstandards/c/Pointers.qll | 7 +------ ...ConversionBetweenPointerToObjectAndIntegerType.expected | 3 --- c/misra/test/rules/RULE-11-4/test.c | 4 ++-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/c/common/src/codingstandards/c/Pointers.qll b/c/common/src/codingstandards/c/Pointers.qll index 458c2271eb..6410b81322 100644 --- a/c/common/src/codingstandards/c/Pointers.qll +++ b/c/common/src/codingstandards/c/Pointers.qll @@ -62,12 +62,7 @@ class ArrayPointerArithmeticExpr extends PointerArithmeticExpr, ArrayExpr { predicate isNullPointerConstant(Expr e) { e.findRootCause() instanceof NULLMacro or - exists(CStyleCast c | - not c.isImplicit() and - c.getExpr() = e and - e instanceof Zero and - c.getType() instanceof VoidPointerType - ) + e instanceof Zero or isNullPointerConstant(e.(Conversion).getExpr()) } diff --git a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected index 5fedfdcce4..060de9944f 100644 --- a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected +++ b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected @@ -1,6 +1,3 @@ -| test.c:5:21:5:42 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | -| test.c:5:35:5:42 | (int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | | test.c:6:21:6:37 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | | test.c:8:8:8:24 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | -| test.c:10:22:10:22 | (unsigned int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | | test.c:12:22:12:39 | (unsigned int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | diff --git a/c/misra/test/rules/RULE-11-4/test.c b/c/misra/test/rules/RULE-11-4/test.c index 25e3f3c4b2..1e3a798b86 100644 --- a/c/misra/test/rules/RULE-11-4/test.c +++ b/c/misra/test/rules/RULE-11-4/test.c @@ -2,12 +2,12 @@ void f1(void) { unsigned int v1 = (unsigned int)(void *)0; // COMPLIANT - unsigned int v2 = (unsigned int)(int *)0; // NON_COMPLIANT + unsigned int v2 = (unsigned int)(int *)0; // COMPLIANT unsigned int v3 = (unsigned int)&v2; // NON_COMPLIANT v3 = v2; // COMPLIANT v3 = (unsigned int)&v2; // NON_COMPLIANT v3 = NULL; // COMPLIANT - unsigned int *v4 = 0; // NON_COMPLIANT + unsigned int *v4 = 0; // COMPLIANT unsigned int *v5 = NULL; // COMPLIANT unsigned int *v6 = (unsigned int *)v2; // NON_COMPLIANT } \ No newline at end of file From 5ad86efd7427cf1f14833a6b28959788cf8c9346 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 23 Jul 2023 21:05:13 +0100 Subject: [PATCH 02/11] RULE-11-4: Compress macro results Where results arise from macro expansions, where there's no possibility that the cast was passed in through a macro argument, we compress the results by reporting the macro location once instead of each use. --- ...ionBetweenPointerToObjectAndIntegerType.ql | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql index 4071cf63b5..72e713c7f1 100644 --- a/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql +++ b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql @@ -13,15 +13,34 @@ import cpp import codingstandards.c.misra +import codingstandards.cpp.Macro import codingstandards.c.Pointers -from CStyleCast cast, Type typeFrom, Type typeTo +MacroInvocation getAMacroInvocation(CStyleCast cast) { result.getAnExpandedElement() = cast } + +Macro getPrimaryMacro(CStyleCast cast) { + exists(MacroInvocation mi | + mi = getAMacroInvocation(cast) and + not exists(MacroInvocation otherMi | + otherMi = getAMacroInvocation(cast) and otherMi.getParentInvocation() = mi + ) and + result = mi.getMacro() and + not result instanceof FunctionLikeMacro + ) +} + +from Locatable primaryLocation, CStyleCast cast, Type typeFrom, Type typeTo where not isExcluded(cast, Pointers1Package::castBetweenObjectPointerAndDifferentObjectTypeQuery()) and typeFrom = cast.getExpr().getUnderlyingType() and typeTo = cast.getUnderlyingType() and [typeFrom, typeTo] instanceof IntegralType and [typeFrom, typeTo] instanceof PointerToObjectType and - not isNullPointerConstant(cast.getExpr()) -select cast, + not isNullPointerConstant(cast.getExpr()) and + // If this alert is arising through a macro expansion, flag the macro instead, to + // help make the alerts more manageable + if exists(getPrimaryMacro(cast)) + then primaryLocation = getPrimaryMacro(cast) + else primaryLocation = cast +select primaryLocation, "Cast performed between a pointer to object type and a pointer to an integer type." From 916df884a479765497265267a0fc36f40ae564fa Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 23 Jul 2023 21:28:35 +0100 Subject: [PATCH 03/11] RULE 11.4: Improve reporting Improve the message by (a) reporting which order the cast is (b) what the actual types are (c) by providing a link to the macro invocation if the cast is created by a function like macro --- ...ionBetweenPointerToObjectAndIntegerType.ql | 63 +++++++++++++++---- ...weenPointerToObjectAndIntegerType.expected | 9 ++- c/misra/test/rules/RULE-11-4/test.c | 12 ++++ 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql index 72e713c7f1..625aec2220 100644 --- a/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql +++ b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql @@ -24,23 +24,62 @@ Macro getPrimaryMacro(CStyleCast cast) { not exists(MacroInvocation otherMi | otherMi = getAMacroInvocation(cast) and otherMi.getParentInvocation() = mi ) and - result = mi.getMacro() and - not result instanceof FunctionLikeMacro + result = mi.getMacro() ) } -from Locatable primaryLocation, CStyleCast cast, Type typeFrom, Type typeTo +Macro getNonFunctionPrimaryMacro(CStyleCast cast) { + result = getPrimaryMacro(cast) and + not result instanceof FunctionLikeMacro +} + +from + Locatable primaryLocation, CStyleCast cast, Type typeFrom, Type typeTo, string message, + string extraMessage, Locatable optionalPlaceholderLocation, string optionalPlaceholderMessage where not isExcluded(cast, Pointers1Package::castBetweenObjectPointerAndDifferentObjectTypeQuery()) and typeFrom = cast.getExpr().getUnderlyingType() and typeTo = cast.getUnderlyingType() and - [typeFrom, typeTo] instanceof IntegralType and - [typeFrom, typeTo] instanceof PointerToObjectType and + ( + typeFrom instanceof PointerToObjectType and + typeTo instanceof IntegralType and + message = + "Cast from pointer to object type '" + typeFrom + "' to integer type '" + typeTo + "'" + + extraMessage + "." + or + typeFrom instanceof IntegralType and + typeTo instanceof PointerToObjectType and + message = + "Cast from integer type '" + typeFrom + "' to pointer to object type '" + typeTo + "'" + + extraMessage + "." + ) and not isNullPointerConstant(cast.getExpr()) and - // If this alert is arising through a macro expansion, flag the macro instead, to - // help make the alerts more manageable - if exists(getPrimaryMacro(cast)) - then primaryLocation = getPrimaryMacro(cast) - else primaryLocation = cast -select primaryLocation, - "Cast performed between a pointer to object type and a pointer to an integer type." + // If this alert is arising through a non-function-like macro expansion, flag the macro instead, to + // help make the alerts more manageable. We only do this for non-function-like macros because they + // cannot be context specific. + if exists(getNonFunctionPrimaryMacro(cast)) + then + primaryLocation = getNonFunctionPrimaryMacro(cast) and + extraMessage = "" and + optionalPlaceholderLocation = primaryLocation and + optionalPlaceholderMessage = "" + else ( + primaryLocation = cast and + // If the cast is in a macro expansion which is context specific, we still report the original + // location, but also add a link to the most specific macro that contains the cast, to aid + // validation. + if exists(getPrimaryMacro(cast)) + then + extraMessage = " from expansion of macro $@" and + exists(Macro m | + m = getPrimaryMacro(cast) and + optionalPlaceholderLocation = m and + optionalPlaceholderMessage = m.getName() + ) + else ( + extraMessage = "" and + optionalPlaceholderLocation = cast and + optionalPlaceholderMessage = "" + ) + ) +select primaryLocation, message, optionalPlaceholderLocation, optionalPlaceholderMessage diff --git a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected index 060de9944f..44d5ca5943 100644 --- a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected +++ b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected @@ -1,3 +1,6 @@ -| test.c:6:21:6:37 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | -| test.c:8:8:8:24 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | -| test.c:12:22:12:39 | (unsigned int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | +| test.c:6:21:6:37 | (unsigned int)... | Cast from pointer to object type 'unsigned int *' to integer type 'unsigned int'. | test.c:6:21:6:37 | (unsigned int)... | | +| test.c:8:8:8:24 | (unsigned int)... | Cast from pointer to object type 'unsigned int *' to integer type 'unsigned int'. | test.c:8:8:8:24 | (unsigned int)... | | +| test.c:12:22:12:39 | (unsigned int *)... | Cast from integer type 'unsigned int' to pointer to object type 'unsigned int *'. | test.c:12:22:12:39 | (unsigned int *)... | | +| test.c:15:1:15:24 | #define FOO (int *)0x200 | Cast from integer type 'int' to pointer to object type 'int *'. | test.c:15:1:15:24 | #define FOO (int *)0x200 | | +| test.c:23:3:23:22 | (int *)... | Cast from integer type 'int' to pointer to object type 'int *' from expansion of macro $@. | test.c:17:1:17:34 | #define FOO_FUNCTIONAL(x) (int *)x | FOO_FUNCTIONAL | +| test.c:24:14:24:25 | (int *)... | Cast from integer type 'int' to pointer to object type 'int *' from expansion of macro $@. | test.c:18:1:18:23 | #define FOO_INSERT(x) x | FOO_INSERT | diff --git a/c/misra/test/rules/RULE-11-4/test.c b/c/misra/test/rules/RULE-11-4/test.c index 1e3a798b86..5a78387247 100644 --- a/c/misra/test/rules/RULE-11-4/test.c +++ b/c/misra/test/rules/RULE-11-4/test.c @@ -10,4 +10,16 @@ void f1(void) { unsigned int *v4 = 0; // COMPLIANT unsigned int *v5 = NULL; // COMPLIANT unsigned int *v6 = (unsigned int *)v2; // NON_COMPLIANT +} + +#define FOO (int *)0x200 // NON_COMPLIANT +#define FOO_WRAPPER FOO; +#define FOO_FUNCTIONAL(x) (int *)x +#define FOO_INSERT(x) x + +void test_macros() { + FOO; // Issue is reported at the macro + FOO_WRAPPER; // Issue is reported at the macro + FOO_FUNCTIONAL(0x200); // NON_COMPLIANT + FOO_INSERT((int *)0x200); // NON_COMPLIANT } \ No newline at end of file From 49d0aef4a6997c7b8d49f787b9903f3517b665c5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 28 Jul 2023 17:09:43 -0700 Subject: [PATCH 04/11] Add change note. --- change_notes/2023-07-28-rule-11-4-improvements.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 change_notes/2023-07-28-rule-11-4-improvements.md diff --git a/change_notes/2023-07-28-rule-11-4-improvements.md b/change_notes/2023-07-28-rule-11-4-improvements.md new file mode 100644 index 0000000000..d97e554a26 --- /dev/null +++ b/change_notes/2023-07-28-rule-11-4-improvements.md @@ -0,0 +1,4 @@ + - `RULE-11-4` + - Reduce false positives by considering `0` a null pointer constant. + - Improve reporting of the order of the cast and the actual types involved. + - Improve reporting where the result is expanded from a macro by either reporting the macro itself (if it is not dependent on the context) or by including a link to the macro in the alert message. \ No newline at end of file From 6702c6449293c742076f5973c870ac31fcb89ca1 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Sep 2024 09:22:40 +0100 Subject: [PATCH 05/11] Update 11.6 to reflect standard Rule text specifies that the exclusion is on integer constants with value 0 instead of null pointer constants --- .../RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql b/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql index 987d8a32bb..de75e9d37a 100644 --- a/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql +++ b/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql @@ -22,5 +22,5 @@ where typeTo = cast.getUnderlyingType() and [typeFrom, typeTo] instanceof ArithmeticType and [typeFrom, typeTo] instanceof VoidPointerType and - not isNullPointerConstant(cast.getExpr()) + not cast.getExpr() instanceof Zero select cast, "Cast performed between a pointer to void type and an arithmetic type." From 2672d08b7cd7af1a37d3a2897f38b505f75b8ee5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Sep 2024 09:23:33 +0100 Subject: [PATCH 06/11] Update change note to reflect impact on other queries --- change_notes/2023-07-28-rule-11-4-improvements.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/change_notes/2023-07-28-rule-11-4-improvements.md b/change_notes/2023-07-28-rule-11-4-improvements.md index d97e554a26..7c7411beec 100644 --- a/change_notes/2023-07-28-rule-11-4-improvements.md +++ b/change_notes/2023-07-28-rule-11-4-improvements.md @@ -1,4 +1,10 @@ - - `RULE-11-4` - - Reduce false positives by considering `0` a null pointer constant. + - `RULE-11-1` - `ConversionBetweenFunctionPointerAndOtherType.ql`: + - Fixed issue #331 - consider `0` a null pointer constant. + - `RULE-11-4` - `ConversionBetweenPointerToObjectAndIntegerType.ql`: + - Fixed issue #331 - consider `0` a null pointer constant. - Improve reporting of the order of the cast and the actual types involved. - - Improve reporting where the result is expanded from a macro by either reporting the macro itself (if it is not dependent on the context) or by including a link to the macro in the alert message. \ No newline at end of file + - Improve reporting where the result is expanded from a macro by either reporting the macro itself (if it is not dependent on the context) or by including a link to the macro in the alert message. + - `RULE-11-5` - `ConversionFromPointerToVoidIntoPointerToObject.ql`: + - Fixed issue #331 - consider `0` a null pointer constant. + - `RULE-11-6` - `CastBetweenPointerToVoidAndArithmeticType.ql`: + - Fixed issue #331 - accept integer constant expressions with value `0` instead of null pointer constants. \ No newline at end of file From 0ec5f7204d7cf17cfcf0bd5e8646bdc15beb0c27 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Sep 2024 10:00:24 +0100 Subject: [PATCH 07/11] RULE-11-9: do not accept 0 as a null pointer constant Rule 11.9 has a different set of requirements for null pointer constants to the other rules. --- ...MacroNullNotUsedAsIntegerNullPointerConstant.ql | 14 ++++++++++++-- cpp/common/src/codingstandards/cpp/Pointers.qll | 2 ++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql index b002ceb4c2..64414b2408 100644 --- a/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql +++ b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql @@ -18,8 +18,18 @@ import codingstandards.cpp.Type from Zero zero, Expr e, string type where not isExcluded(zero, Pointers1Package::macroNullNotUsedAsIntegerNullPointerConstantQuery()) and - // exclude the base-case (NULL macros and void pointer casts) - not isNullPointerConstant(zero) and + // Exclude the base-case (NULL macros and void pointer casts) + // Note: we cannot use the isNullPointerConstant predicate here because it permits + // the use of `0` without casting, which is prohibited here. + not ( + zero.findRootCause() instanceof NullMacro + or + // integer constant `0` explicitly cast to void pointer + exists(Conversion c | c = zero.getConversion() | + not c.isImplicit() and + c.getUnderlyingType() instanceof VoidPointerType + ) + ) and ( // ?: operator exists(ConditionalExpr parent | diff --git a/cpp/common/src/codingstandards/cpp/Pointers.qll b/cpp/common/src/codingstandards/cpp/Pointers.qll index a1126693a5..22dcbd187b 100644 --- a/cpp/common/src/codingstandards/cpp/Pointers.qll +++ b/cpp/common/src/codingstandards/cpp/Pointers.qll @@ -62,6 +62,8 @@ class ArrayPointerArithmeticExpr extends PointerArithmeticExpr, ArrayExpr { predicate isNullPointerConstant(Expr e) { e.findRootCause() instanceof NullMacro or + // 8.11 Pointer type conversions states: + // A null pointer constant, i.e. the value 0, optionally cast to void *. e instanceof Zero or isNullPointerConstant(e.(Conversion).getExpr()) From 71559521957d574f8a4fde473b3addbdc2ed5a02 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Sep 2024 10:05:46 +0100 Subject: [PATCH 08/11] RULE-11-9: Improve ternary test cases This rule intends to prohibit the use of 0 within branches of ternaries, where the ternary expression itself produces a pointer expression because the other branch of the ternary is a pointer. The previous test case didn't capture this behaviour, instead looking for assignments within branches. --- ...roNullNotUsedAsIntegerNullPointerConstant.expected | 4 ++-- c/misra/test/rules/RULE-11-9/test.c | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected index 8cdd34edd1..25ec87d11c 100644 --- a/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected +++ b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected @@ -1,4 +1,4 @@ | test.c:15:13:15:13 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:15:7:15:13 | ... == ... | Equality operator | | test.c:17:8:17:8 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:17:3:17:8 | ... = ... | Assignment to pointer | -| test.c:25:20:25:20 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:25:3:25:35 | ... ? ... : ... | Ternary operator | -| test.c:25:20:25:20 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:25:15:25:20 | ... = ... | Assignment to pointer | +| test.c:23:13:23:13 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:23:3:23:13 | ... ? ... : ... | Ternary operator | +| test.c:24:8:24:8 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:24:3:24:13 | ... ? ... : ... | Ternary operator | diff --git a/c/misra/test/rules/RULE-11-9/test.c b/c/misra/test/rules/RULE-11-9/test.c index 216ea2b280..8342660e2c 100644 --- a/c/misra/test/rules/RULE-11-9/test.c +++ b/c/misra/test/rules/RULE-11-9/test.c @@ -19,9 +19,12 @@ void *f1(void *p1, int p2) { p1 = NULL; // COMPLIANT if (p2 == 0) { // COMPLIANT return NULL; - } // COMPLIANT - (p1) ? (p1 = NULL) : (p1 = NULL); // COMPLIANT - (p2 > 0) ? (p1 = NULL) : (p1 = NULL); // COMPLIANT - (p2 > 0) ? (p1 = 0) : (p1 = NULL); // NON_COMPLIANT + } + p2 ? p1 : 0; // NON_COMPLIANT + p2 ? 0 : p1; // NON_COMPLIANT + p2 ? (void*) 0 : p1; // COMPLIANT + p2 ? p1 : (void*) 0; // COMPLIANT + p2 ? p2 : 0; // COMPLIANT - p2 is not a pointer type + p2 ? 0 : p2; // COMPLIANT - p2 is not a pointer type return 0; // COMPLIANT } \ No newline at end of file From 575be092f990b5f0f5e3a659df5264af008dca7b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Sep 2024 10:15:27 +0100 Subject: [PATCH 09/11] Fix issue with detecting ternary expressions. --- .../RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql | 4 ++-- .../MacroNullNotUsedAsIntegerNullPointerConstant.expected | 1 + c/misra/test/rules/RULE-11-9/test.c | 4 ++++ change_notes/2023-07-28-rule-11-4-improvements.md | 4 +++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql index 64414b2408..a5c34fb747 100644 --- a/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql +++ b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql @@ -34,9 +34,9 @@ where // ?: operator exists(ConditionalExpr parent | ( - parent.getThen().getAChild*() = zero and parent.getElse().getType() instanceof PointerType + parent.getThen() = zero and parent.getElse().getType() instanceof PointerType or - parent.getElse().getAChild*() = zero and parent.getThen().getType() instanceof PointerType + parent.getElse() = zero and parent.getThen().getType() instanceof PointerType ) and // exclude a common conditional pattern used in macros such as 'assert' not parent.isInMacroExpansion() and diff --git a/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected index 25ec87d11c..d854730296 100644 --- a/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected +++ b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected @@ -2,3 +2,4 @@ | test.c:17:8:17:8 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:17:3:17:8 | ... = ... | Assignment to pointer | | test.c:23:13:23:13 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:23:3:23:13 | ... ? ... : ... | Ternary operator | | test.c:24:8:24:8 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:24:3:24:13 | ... ? ... : ... | Ternary operator | +| test.c:31:14:31:14 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:31:9:31:14 | ... = ... | Assignment to pointer | diff --git a/c/misra/test/rules/RULE-11-9/test.c b/c/misra/test/rules/RULE-11-9/test.c index 8342660e2c..c9cce8687b 100644 --- a/c/misra/test/rules/RULE-11-9/test.c +++ b/c/misra/test/rules/RULE-11-9/test.c @@ -26,5 +26,9 @@ void *f1(void *p1, int p2) { p2 ? p1 : (void*) 0; // COMPLIANT p2 ? p2 : 0; // COMPLIANT - p2 is not a pointer type p2 ? 0 : p2; // COMPLIANT - p2 is not a pointer type + int x; + int *y; + p2 ? (p1 = 0) : p1; // NON_COMPLIANT - p1 is a pointer type + p2 ? (p2 = 0) : p1; // COMPLIANT - p2 is not a pointer type return 0; // COMPLIANT } \ No newline at end of file diff --git a/change_notes/2023-07-28-rule-11-4-improvements.md b/change_notes/2023-07-28-rule-11-4-improvements.md index 7c7411beec..3c385359a8 100644 --- a/change_notes/2023-07-28-rule-11-4-improvements.md +++ b/change_notes/2023-07-28-rule-11-4-improvements.md @@ -7,4 +7,6 @@ - `RULE-11-5` - `ConversionFromPointerToVoidIntoPointerToObject.ql`: - Fixed issue #331 - consider `0` a null pointer constant. - `RULE-11-6` - `CastBetweenPointerToVoidAndArithmeticType.ql`: - - Fixed issue #331 - accept integer constant expressions with value `0` instead of null pointer constants. \ No newline at end of file + - Fixed issue #331 - accept integer constant expressions with value `0` instead of null pointer constants. + - `RULE-11-9` - `MacroNullNotUsedAsIntegerNullPointerConstant.ql`: + - Remove false positives in branches of ternary expressions, where `0` was used correctly. \ No newline at end of file From 422f17090e7e8aca666aa8ed1983cffb46572c5c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 11 Sep 2024 14:54:57 +0100 Subject: [PATCH 10/11] Rule 11.1: Exclude null pointer constant Null pointer constants can be cast to a function pointer. --- .../ConversionBetweenFunctionPointerAndOtherType.expected | 1 - c/misra/test/rules/RULE-11-1/test.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected index ebe2c74742..0144180616 100644 --- a/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected +++ b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected @@ -1,7 +1,6 @@ | test.c:11:8:11:16 | (fp1 *)... | Cast performed between a function pointer and another type. | | test.c:11:8:11:16 | (fp1)... | Cast performed between a function pointer and another type. | | test.c:12:14:12:23 | (void *)... | Cast performed between a function pointer and another type. | -| test.c:14:8:14:15 | (fp2)... | Cast performed between a function pointer and another type. | | test.c:15:8:15:15 | (fp2)... | Cast performed between a function pointer and another type. | | test.c:22:12:22:13 | (fp1)... | Cast performed between a function pointer and another type. | | test.c:25:8:25:9 | (fp1)... | Cast performed between a function pointer and another type. | diff --git a/c/misra/test/rules/RULE-11-1/test.c b/c/misra/test/rules/RULE-11-1/test.c index 858c6e68a9..4fcabb0599 100644 --- a/c/misra/test/rules/RULE-11-1/test.c +++ b/c/misra/test/rules/RULE-11-1/test.c @@ -11,7 +11,7 @@ void f1(void) { v1 = (fp1 *)v2; // NON_COMPLIANT void *v3 = (void *)v1; // NON_COMPLIANT - v2 = (fp2 *)0; // NON_COMPLIANT + v2 = (fp2 *)0; // COMPLIANT - null pointer constant v2 = (fp2 *)1; // NON_COMPLIANT pfp2 v4; From 8729c437e87d8aa6661e6819c3baaf351ba416b0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 11 Sep 2024 14:55:25 +0100 Subject: [PATCH 11/11] Rule 11.9: Format test file --- c/misra/test/rules/RULE-11-9/test.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/c/misra/test/rules/RULE-11-9/test.c b/c/misra/test/rules/RULE-11-9/test.c index c9cce8687b..e87366d831 100644 --- a/c/misra/test/rules/RULE-11-9/test.c +++ b/c/misra/test/rules/RULE-11-9/test.c @@ -20,15 +20,15 @@ void *f1(void *p1, int p2) { if (p2 == 0) { // COMPLIANT return NULL; } - p2 ? p1 : 0; // NON_COMPLIANT - p2 ? 0 : p1; // NON_COMPLIANT - p2 ? (void*) 0 : p1; // COMPLIANT - p2 ? p1 : (void*) 0; // COMPLIANT - p2 ? p2 : 0; // COMPLIANT - p2 is not a pointer type - p2 ? 0 : p2; // COMPLIANT - p2 is not a pointer type + p2 ? p1 : 0; // NON_COMPLIANT + p2 ? 0 : p1; // NON_COMPLIANT + p2 ? (void *)0 : p1; // COMPLIANT + p2 ? p1 : (void *)0; // COMPLIANT + p2 ? p2 : 0; // COMPLIANT - p2 is not a pointer type + p2 ? 0 : p2; // COMPLIANT - p2 is not a pointer type int x; int *y; - p2 ? (p1 = 0) : p1; // NON_COMPLIANT - p1 is a pointer type - p2 ? (p2 = 0) : p1; // COMPLIANT - p2 is not a pointer type - return 0; // COMPLIANT + p2 ? (p1 = 0) : p1; // NON_COMPLIANT - p1 is a pointer type + p2 ? (p2 = 0) : p1; // COMPLIANT - p2 is not a pointer type + return 0; // COMPLIANT } \ No newline at end of file