Hi,
I have an issue with ccpcheck where I think there are some inconsistencies with how the MISRA rules are checked and what is treated as a composite expression.
Looking at the MISRA 2012 standard, it states:
A composite expression is defined as a non-contant expression which is the direct result of a composite operator (* , / , %, binary +, binary -, bitwise &, bitwise |, bitwise ^, bitwise ~, <<, >> and conditional (?:) if either the second or third operand is a composite expression)
It also specifies that:
A parenthesized composite expression is also a composite expression
A unary + or unary - expression whose operand is a composite expression is also a composite expression
The result of assignment and compound assignment, postfix and prefix increment and decrement, and cast are not composite expressions
A constant expression is not a composite expression
Unless I have misunderstood, the tool does not (at least consistently) account for the fact that constant expressions are not composite expressions. I thus get failures on misra-2012c-10.7 when using several macro constants to calculate the value of other macro constants which I then use in the code. There are also some issues with the U/u suffix and uint16_t vs uint8_t I don't understand, which seems to compound the issue. Thus I did some testing (sorry for not being able to come up with a cleaner example):
Which gives the following output (I have numbered the violations to be able to refer back to it:)
1a: main.c:12:20: [misra-c2012-7.2] Required: A "u" or "U" suffix shall be applied to all integer constants that are represented in an unsigned type
uint8_t c8b = (0x100 - 0x80);
^
2a: main.c:15:19: [misra-c2012-7.2] Required: A "u" or "U" suffix shall be applied to all integer constants that are represented in an unsigned type
uint8_t f8b = 0x80;
^
3a: main.c:6:19: [misra-c2012-10.3] Required: The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category
uint16_t d16b = 0x80ul;
^
4a: main.c:13:17: [misra-c2012-10.3] Required: The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category
uint8_t d8b = 0x80ul;
^
5a: main.c:3:19: [misra-c2012-10.6] Required: The value of a composite expression shall not be an assigned to an object with wider essential type
uint16_t a16b = (0x100ul - 0x80ul);
^
6a: main.c:4:19: [misra-c2012-10.6] Required: The value of a composite expression shall not be an assigned to an object with wider essential type
uint16_t b16b = (0x100u - 0x80u);
^
So let me go though the violatons:
1a. Correct, however, why doesn't "uint16_t c16b = (0x100 - 0x80);" cause a violation of 7.2 as well?
case1: c8b = 0b10000000 - MSB (sign bit) = 1 which will cause problem
case2: c16b = 0b000000010000000 - MSB (sign bit) = 0 which is no problem
is the checker configured to ignore 7.2 on case2 since there will be no problem? This is not consistent with the formulation of 7.2 as I understand it?
2a. Correct, however, why doesn't "uint16_t f16b = 0x80;" cause a violation of 7.2?
3a. Correct
4a. Correct
5a. As I understand it, this should not fail on 10.6, but rather 10.3? Moreover, the RHS of the assignment is not a composite expression since the expression is constant? It seems like the tool evaluates the rhs expression as an 8bit even though the operands are specified as unsigned long?
6a. As I understand it, this should not fail since neither "uint16_t e16b = 0x80u;" nor "uint8_t e8b = 0x80u;" causes a violation? Moreover the RHS of the assignment is not a composite expression since the expression is constant? It seems like the tool evaluates the rhs of the expression as 8bit even though the operands are specified as unsigned and, as I said, "uint16_t e16b = 0x80u;" does not fail?
Finally, here is my original issue with 10.7, which I think is connected to the issues above, but someone with more familiarity of the tool might understand better if they are connected or not:
//bar.c #define A 400U#define B 100U#define C 200U#define AB_DIFF (A - B)#define AC_DIFF (A - C)#define MAX_VALUE_1 (A/B)#define MAX_VALUE_2 4Ustaticvoidfoobar(void){uint16_tvar=2U;uint16_tab_result=var*AB_DIFF;//AB_DIFF does not fit in 8 bitsuint16_tac_result=var*AC_DIFF;//AC_DIFF is small enough to fit in 8 bitsuint16_tresult=var*200U;//200U can fit in 8 bitsvar++;var%=MAX_VALUE_1;var%=MAX_VALUE_2;}
gives the following violations:
1b: main.c:15:30: [misra-c2012-10.7] Required: If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed, then the other operand shall not have a wider essential type
uint16_t ac_result = var * AC_DIFF; //AC_DIFF is small enough to fit in 8 bits
^
2b: main.c:18:12: [misra-c2012-10.7] Required: If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed, then the other operand shall not have a wider essential type
var %= MAX_VALUE_1;
^
1b. How come "uint16_t ab_result = var * AB_DIFF;" does not fail while " uint16_t ac_result = var * AC_DIFF" do? How come "uint16_t result = var * 200U;" does not fail, when it produces that same code as " uint16_t ac_result = var * AC_DIFF"? Again, it seems like AC_DIFF is treated as a composite expression when my claim is that it is not, as it is a constant expression.
How can I handle that case when I'm trying to create a library that is configured through macros similar to A/B/C is used to calculate macros similar to AB/AC_DIFF and is used in a similar fashion as the assignment of ab/ac_result? In other words, how can I account for the fact that there are valid combinations of values for A/B/C that can both yield an AB/AC_diff that fits in 8 bits and other combinations that fit in 16 bit? Surely the correct answer is to just use uint16_t for ab/ac_result? However, the tool gives me errors when values for A/B/C is selected such that AB/AC_DIFF fit in 8 bits. Trying to do any casting just yields 10.8 violations in my experience. If this is not a failing of the tool, how are you supposed to resolve this issue?
2b. How come "var %= MAX_VALUE_1;" fails while "var %= MAX_VALUE_2;" does not when they are effectively the same? Again, there seems to be an issue where it treats MAX_VALUE_1 as a composite expression when I think it is a constant expression. If this is how the tool should work, what is the correct approach here?
I appreciate any feedback on this, mainly a confirmation that the issues with 10.7 above are false positives so that I may suppress them?
Thanks!
Last edit: Henrik Nyholm 2022-02-02
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks!
Glad you want to fix it asap, but there is no need to rush on my side, just wondering if it would be possible to add a ticket on https://trac.cppcheck.net/ so that I may document this false positive as a known issue in my project?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi,
I have an issue with ccpcheck where I think there are some inconsistencies with how the MISRA rules are checked and what is treated as a composite expression.
Looking at the MISRA 2012 standard, it states:
It also specifies that:
Unless I have misunderstood, the tool does not (at least consistently) account for the fact that constant expressions are not composite expressions. I thus get failures on misra-2012c-10.7 when using several macro constants to calculate the value of other macro constants which I then use in the code. There are also some issues with the U/u suffix and uint16_t vs uint8_t I don't understand, which seems to compound the issue. Thus I did some testing (sorry for not being able to come up with a cleaner example):
Which gives the following output (I have numbered the violations to be able to refer back to it:)
So let me go though the violatons:
1a. Correct, however, why doesn't "uint16_t c16b = (0x100 - 0x80);" cause a violation of 7.2 as well?
case1: c8b = 0b10000000 - MSB (sign bit) = 1 which will cause problem
case2: c16b = 0b000000010000000 - MSB (sign bit) = 0 which is no problem
is the checker configured to ignore 7.2 on case2 since there will be no problem? This is not consistent with the formulation of 7.2 as I understand it?
2a. Correct, however, why doesn't "uint16_t f16b = 0x80;" cause a violation of 7.2?
3a. Correct
4a. Correct
5a. As I understand it, this should not fail on 10.6, but rather 10.3? Moreover, the RHS of the assignment is not a composite expression since the expression is constant? It seems like the tool evaluates the rhs expression as an 8bit even though the operands are specified as unsigned long?
6a. As I understand it, this should not fail since neither "uint16_t e16b = 0x80u;" nor "uint8_t e8b = 0x80u;" causes a violation? Moreover the RHS of the assignment is not a composite expression since the expression is constant? It seems like the tool evaluates the rhs of the expression as 8bit even though the operands are specified as unsigned and, as I said, "uint16_t e16b = 0x80u;" does not fail?
Finally, here is my original issue with 10.7, which I think is connected to the issues above, but someone with more familiarity of the tool might understand better if they are connected or not:
gives the following violations:
1b. How come "uint16_t ab_result = var * AB_DIFF;" does not fail while " uint16_t ac_result = var * AC_DIFF" do? How come "uint16_t result = var * 200U;" does not fail, when it produces that same code as " uint16_t ac_result = var * AC_DIFF"? Again, it seems like AC_DIFF is treated as a composite expression when my claim is that it is not, as it is a constant expression.
How can I handle that case when I'm trying to create a library that is configured through macros similar to A/B/C is used to calculate macros similar to AB/AC_DIFF and is used in a similar fashion as the assignment of ab/ac_result? In other words, how can I account for the fact that there are valid combinations of values for A/B/C that can both yield an AB/AC_diff that fits in 8 bits and other combinations that fit in 16 bit? Surely the correct answer is to just use uint16_t for ab/ac_result? However, the tool gives me errors when values for A/B/C is selected such that AB/AC_DIFF fit in 8 bits. Trying to do any casting just yields 10.8 violations in my experience. If this is not a failing of the tool, how are you supposed to resolve this issue?
2b. How come "var %= MAX_VALUE_1;" fails while "var %= MAX_VALUE_2;" does not when they are effectively the same? Again, there seems to be an issue where it treats MAX_VALUE_1 as a composite expression when I think it is a constant expression. If this is how the tool should work, what is the correct approach here?
I appreciate any feedback on this, mainly a confirmation that the issues with 10.7 above are false positives so that I may suppress them?
Thanks!
Last edit: Henrik Nyholm 2022-02-02
I investigated the 10.7 warnings. And yes in deed it seems these are false positives. I'll need to adjust that.
Thanks for the reply @danielmarjamaki!
Is there a ticket associated with this so that I can use that as documentation for suppressing the violations?
Hi again @danielmarjamaki,
just asking again in case you did not see my last question?
Thank you for your support!
I think these observations are very good and I wanted to fix this asap. But I have not fixed it yet.
Last edit: Daniel Marjamäki 2022-02-11
Thanks!
Glad you want to fix it asap, but there is no need to rush on my side, just wondering if it would be possible to add a ticket on https://trac.cppcheck.net/ so that I may document this false positive as a known issue in my project?
I have updated the checking for 10.6. Feel free to test if it works properly. A fix for 7.2 is on the way.
7.2 has been tweaked. Feel free to test that out also.