My CCS 6.1 ARM compiler (for LM3Sxxxx Stellaris) throws a warning:
"MISRA Rule 10.1. The value of an expression of integer type shall not be implicitly converted to a different underlying type if the expression is
not constant and is a function argument"
for following code:
static uint32_t diagBaseAddress;
void diagCbGetBaseAddress(uint32_t * addr);
...
diagCbGetBaseAddress(&diagBaseAddress); // line where warning is issued
...
I don't see a problem in my code. Is it false positive or my bug?
Yes, it is a false positive. Rule 10.1 of MISRA-C:2004 is concerned about implicit type promotions of integer types. Pointers have nothing to do with that rule.
Though make sure that none of the adjacent code lines contain the actual problem, the tool could simply be pointing at the wrong line.
(I can tell it is the 2004 version because it mentions underlying type. In the 2012 version, the concept of underlying type was replaced.)
Related
I always wondered why warnings passing argument 1 from of 'foo' makes pointer from integer without a cast and alike are only warnings and not errors.
Actually these warnings are almost always errors.
Does somebody know what's the idea behind this?
Is it mostly to allow prehistoric code to be compiled without errors?
Or just to comply to the standard? Then latter maybe needs some fixing.
Example:
int foo(int *bar)
{
*bar = 42;
}
void bar()
{
int n = 0;
foo(n); // this is obviously an error
...
}
Per 6.5.2.2 Function Calls, ΒΆ 7:
If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type
The relevant text in 6.5.16.1 Simple Assignment is:
Constraints
One of the following shall hold:
the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type;
the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;
the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
the left operand has type atomic, qualified, or unqualified _Bool, and the right is a pointer.
None of these allow the left operand as a pointer and the right operand as an integer. Thus, such an assignment (and by the first quoted text above, the function call) is a constraint violation. This means the compiler is required by the standard to "diagnose" it. However it's up to the compiler what it does beyond that. Yes, an error would be highly preferable, but just printing a warning is a low-quality way to satisfy the requirement to "diagnose" constraint violations like this.
Does somebody know what's the idea behind this?
Is it mostly to allow prehistoric code to be compiled without errors?
Or just to comply to the standard? Then latter maybe needs some fixing.
It is to comply with the standard in the sense that the standard requires conforming implementations to diagnose such issues, as #R.. describes in his answer. Implementations are not required to reject programs on account of such issues, however. As for why some compilers instead accept such programs, that would need to be evaluated on a per-implementation basis, but this quotation from the first edition of K&R may shed a bit of light:
5.6 Pointers are not Integers
You may notice in older C programs a rather cavalier attitude toward
copying pointers. It has generally been true that on most machines a
pointer may be assigned to an integer and back again; no scaling or
conversion takes place, and no bits are lost. Regrettably, this has
led to the taking of liberties with routines that return pointers
which are then merely passed to other routines -- the requisite
pointer declarations are often left out.
(Kernighan & Ritchie, The C Programming Language, 1st ed., 1978)
Notice in the first place that this long predates even C89. I'm a bit amused today that the authors were then talking about "older" C programs. But note too that even at that time, the C language as defined by K&R did not formally permit implicit conversion between pointers and integers (though it did permit casting between them).
Nevertheless, there were programs that relied on implicit conversion anyway, apparently because it happened to work on the targeted implementations. It was attractive, by some people's standards at the time, in conjunction with primordial C's implicit typing rules. One could let a variable or function intended to return or store a pointer default to type int by omitting its declaration altogether, and as long as it was interpreted as a pointer wherever it ultimately was used, everything usually happened to work as intended.
I'm inclined to guess that everything continuing to work as intended, thereby supporting backwards compatibility, was a consideration for compiler developers in continuing to accept implicit conversions, so that's "allow[ing] prehistoric code to be compiled." I note, however, that these days code with implicit conversions of this kind are much less likely to work as intended than they used to be, for many machines these days have 64-bit pointers but only 32-bit ints.
The behaviour of assigning an arithmetic type to a pointer is not well formed in the C standard. (See the answer provided by R.. for relevant sections.)
Your compiler (or the settings you're using) have decided to treat that as a warning.
Compilers have default settings and often support language extensions and those may be quite liberal.
Notice for anything outside the language specification it's up to the implementers of the compiler to decide what's an error or if they're going to interpret it as a language extension and (hopefully) issue a warning that the the code is off the offical piste.
I agree that's not best. My recommendation would be to treat is an error because it almost certainly is and casting an int to a pointer is the standard supported way of being explicit and getting the same result (e.g. int *n).
I think you're using GCC and it's notorious for "helpfully" compiling things that it could better serve you by rejecting and making you use standard constructs.
Enable all warnings (-Wall on the gcc command-line) and make sure you understand and address them all appropriately.
In the following code from core_cm4.h why is there a double cast ((uint32_t)(int32_t)IRQn)?
For example in the following function:
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
What is the purpose of this?
Since CM4 software implements negative interrupt sources for core, you have to cast value first to 32bit signed integer and later to unsigned 32bit to make proper right shift with padding zeros on the left side of number.
CM4 uses -15 to -1 as CM4-Core sources and from 0 to next as vendor specific sources.
By looking at that snippet, it is clear that whoever wrote it was confused over how implicit type promotion rules work. In addition, the >> 5UL looks very fishy and when I see that I immediately suspect that this code base suffers from a poor understanding of MISRA-C; possibly they are using a bad static analyser which spits out false positives.
A visit at Github proves my suspicion to be correct, there's comments stating that the intention is to follow MISRA-C:2004.
MISRA-C demands that no dangerous, implicit type promotions may occur. The casts are some failed attempts to silence a static analyser, without an understanding why the tool gave those warnings.
Correct, MISRA-C (2004 and 2012) compliant code would be this:
NVIC->ISER[((uint32_t)IRQn>>5UL)] = (1UL << ((uint32_t)IRQn & 0x1FUL));
(MISRA-C has a requirement that complex sub-expressions must use parenthesis despite what operator precedence there is.)
This code is still messy, so it should preferably be rewritten for readability, into something that will produce exactly the same machine code:
uint32_t ISER_index = ((uint32_t)IRQn >> 5UL);
uint32_t shift_n = ((uint32_t)IRQn & 0x1FUL);
NVIC->ISER[ISER_index] = (1UL << shift_n);
Side note:
MISRA-C:2004 demanded that the result of the shift expression should be immediately cast to the "underlying type" (MISRA term). Thus one could also have written (IRQn_Type)(IRQn >> 5UL) and it would still be MISRA-C:2004 compliant.
However, there is nothing in MISRA preventing you to adding your own cast to a different type, such as uint32_t, before the shift. This is a better thing to do, since it eliminates the implicit promotion entirely.
For those who are confused about how the implicit type promotions work in C, see Implicit type promotion rules.
Assuming IRQn is an integer (any signed integer type) in the range you say, then (uint32_t)(int32_t)IRQn is exactly the same as (uint32_t)IRQn.
The author of the code possibly didn't understand C type conversion rules; which are based on values, not representations. Converting -3, for example, to uint32_t always gives UINT32_MAX - 2 regardless of which data type the -3 was. It's the value of "negative 3" that matters.
(The other answer explains the difference between using a cast and no cast at all).
How can I make gcc warn when a void* is assigned or passed as a parameter to a type that is a more specific kind of pointer, like my_struct* without a cast? I would like to make sure all casting is explicit.
Update: The scope of this question has been extended to non-gcc linters as well.
Update2: Minuses everywhere? I'm flummoxed by the amount of controversy that a simple, purely technical question can generate.
How can I make gcc warn when a void* is assigned or passed as a
parameter to a type that is a more specific kind of pointer
Being able to assign a void * to a more-specific type without a cast is a required part of the C programming language. Per Paragraph 1 of 6.3.2.3 Pointers of the C Standard:
A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal
to the original pointer.
You're asking to be warned about a required part of C. It's not far removed from asking for a warning when 5 is assigned to an int.
As noted by #MarcGlisse, though, GCC does provide the -Wc++-compat warning option:
-Wc++-compat (C and Objective-C only)
Warn about ISO C constructs that are outside of the common subset of ISO C and ISO C++, e.g. request for implicit conversion from void * to a pointer to non-void type.
As noted by #MarcGlisse, gcc provides the -Wc++-compat warning option. Among other non-C++-compatible constructs, it warns about silent conversion of void*.
#AndrewHenle linked to an answer to another question which indicates that requiring an explicit cast has the downside of increasing the likelihood that incompatible conversion may result, for example, if the programmer accidentally casts a numeric value.
I think that's significantly less of a concern, since by an explicit cast the programmer certifies that they know what they're doing. Neverthless, even that small drawback can be addressed by using the following macro in conjunction with -Wc++-compat:
#define VOID_CAST(T, x) ({ __typeof__(x) void_cast_x __attribute__((__unused__)) = ((__typeof__(x))((void*)(x))); ((T*)(x)); })
With luck, the "useless" assignment will be optimized out and the benefit of using VOID_CAST is that it will generate an error or warning if x is not a void* to begin with.
I have recently downloaded the MinGw compiler and for some reason it does not display and warning messages when I should be doing a explicit casts.
For example:
double x=9.97;
int y=x;
This seems to be ok with the compiler. I was just wondering do I need to install some other package
There is no cast required when assigning a double to an int. The decimal part is simply truncated. If you want warnings on this you can use -Wconversion or -Wfloat-conversion.
To complement the other answer, a technical explanation about implicit conversion semantics can be found on http://en.cppreference.com/w/c/language/conversion:
A finite value of any real floating type can be implicitly converted to any integer type. Except where covered by boolean conversion above, the rules are:
- The fractional part is discarded (truncated towards zero).
. If the resulting value can be represented by the target type, that value is used
. otherwise, the behavior is undefined
I am in the early stages of framing stuff out on a new project.
I defined a function with a return type of "bool"
I got this output from PC-Lint
Including file sockets.h (hdr)
bool sock_close(uint8_t socket_id);
^
"LINT: sockets.h (52, 1) Note 970: Use of modifier or type '_Bool' outside of a typedef [MISRA 2012 Directive 4.6, advisory]"
I went ahead and defined this in another header to shut lint up:
typedef bool bool_t;
Then I started wondering why I had to do that and why it changed anything. I turned to MISRA 2012 Dir 4.6. It is concerned mostly about the width of primitive types like short, int, and long, their width, and how they are signed.
The standard does not give any amplification, rational, exception, or example for bool.
bool is explicitly defined as _Bool in stdbool.h in C99. So does this criteria really apply bool?
I thought _Bool was explicitly always the "smallest standard unsigned integer type large enough to store the values 0 and 1" according to section 6.2.5 of C99. So we know bool is unsigned. Is it then just a matter of the fact that _Bool is not fixed width and subject being promoted somehow that's the issue? Because the rational would seem to contradict that notion.
Adherence to this guideline does not guarantee portability because the size of the int type may determine whether or not an expression is subject to integer promotion.
How does just putting typedef bool bool_t; change anything - because I do nothing to indicate the width or the signdedness in doing so? The width of bool_t will just be platform dependent too. Is there a better way to redefine bool?
A type must not be defined with a specific length unless the implemented type is actually of that length
so typedef bool bool8_t; should be totally illegal.
Is Gimpel wrong in their interpretation of Directive 4.6 or are they spot on?
Use of modifier or type '_Bool' outside of a typedef [MISRA 2012 Directive 4.6, advisory]
That's nonsense, directive 4.6 is only concerned about using the types in stdint.h rather than int, short etc. The directive is about the basic numerical types. bool has nothing to do with that directive whatsoever, as it is not a numerical type.
For reasons unknown, MISRA-C:2012 examples use a weird type called bool_t, which isn't standard. But MISRA does by no means enforce this type to be used anywhere, particularly they do not enforce it in directive 4.6, which doesn't even mention booleans. MISRA does not discourage the use of bool or _Bool anywhere.
Is Gimpel wrong in their interpretation of Directive 4.6
Yes, their tool is giving incorrect diagnostics.
In addition, you may have to configure the tool (if possible) to tell it which bool type that is used. 5.3.2 mentions that you might have to do so if not using _Bool, implying that all static analysers must understand _Bool. But even if the bool type is correctly configured, dir 4.6 has nothing to do with it.
A potential concern with Boolean types is that a lot of code prior to C99 used a single-byte type to hold true/false values, and a fair amount of it may have used the name "bool". Attempting to store any multiple of 256 into most such types would be regarded as storing zero, while storing a non-zero multiple of 256 into a c99 "bool" would yield 1. If a piece of code which uses a C99 "bool" is ported into a piece of code that uses a typedef'ed byte, the resulting code could very easily malfunction (it's somewhat less likely that code written for a typedef'ed byte would rely upon any particular behavior when storing a value other than 0 or 1).