Rule: c:S3519
Product: SonarQube Cloud
Type: False Positive
static const char *ini_exts[]= {"ini", 0};
int main()
{
for (int exts= 0; ini_exts[exts]; exts++)
printf("%s", ini_exts[exts]);
}
The error as reported on the condition of the for
loop:
Access of ‘ini_exts’ at index 2, while it holds only 2 ‘const char *’ elements
Because of the 0 pointer element in ini_exts
the exts
will never reach 2. So the error of “at index 2” isn’t valid.
Hi Daniel, welcome here!
You refer to the c:S3519
rule in this report, however, in C Sonar would not report this FP. See.
If you are using C++ though, that’s a different story due to the fact that global variables may run constructors from other translation units that would execute code before main
would start, potentially clobbering the non-const global variables.
Before I’d go in details why your example have a FP for C++, but not for C, let me start by saying how resolve this.
Just mark the ini_exts
const, to allow us to use the values from its initializer when its used in the loop. This should get rid of the FP.
Alternatively, compile your code as C code.
Alright. To explain the intricacies let me change 2 things:
- For generality, let’s assume the FP is not in
main
but in a function called foo
- Let’s assume we have other functions too in the translation unit, call it
bar
Why are these two points important:
There is usually only one main
function in an entire application, thus we usually need to analyze other functions than main
. We usually don’t even see main
in an analysis.
Usually global variables are global for the reason to access them from different places.
So these two changes should make the case a bit more realistic.
This means something like this:
static const char *ini_exts[]= {"ini", 0};
void foo() {
for (int exts= 0; ini_exts[exts]; exts++)
printf("%s", ini_exts[exts]);
}
void bar() {
f(ini_exts);
}
If bar
was called before foo
, then the decayed pointer of ini_exts
would be passed to f
that may modify ini_exts
and overwrite its initial values. So by the time we call foo
we can no longer reason about the content of ini_exts
, thus the loop may go out of bounds.