https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120213
Bug ID: 120213
Summary: analyzer report a false positive
Product: gcc
Version: 15.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: raffaellobertini at gmail dot com
Target Milestone: ---
compile this code:
```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_CHARS 1
void split_string(const char* str)
{
const size_t l = strnlen(str, 2);
if (l > NUM_CHARS)
{
char s[NUM_CHARS + 1];
memcpy(s, str, NUM_CHARS);
s[NUM_CHARS] = '\0';
split_string(s);
split_string(&str[NUM_CHARS]);
return;
}
printf("%s", str);
}
int main()
{
split_string("H");
return 0;
}
```
using a cmake conifg of:
```
add_executable(split-string src/split-string.c)
target_compile_options(split-string
PRIVATE "-Wall" "-Wextra"
$<$<COMPILE_LANGUAGE:C>: -fanalyzer>
)
```
the output reported is a warning: "warning: stack-based buffer over-read
[CWE-126]"
Also the output seems a little bit corrupted:
```
[build] 13 | memcpy(s, str, NUM_CHARS);
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~
[build] 'main': events 1-2
[build] Γöé
[build] Γöé 23 | int main()
[build] Γöé | ^~~~
[build] Γöé | |
[build] Γöé | (1) entry to 'main'
[build] Γöé 24 | {
[build] Γöé 25 | split_string("H");
[build] Γöé | ~~~~~~~~~~~~~~~~~
[build] Γöé | |
[build] Γöé | (2) calling 'split_string' from 'main'
[build] Γöé
[build] ΓööΓöÇΓöÇ> 'split_string': events 3-7
[build] Γöé
[build] Γöé 7 | void split_string(const char* str)
[build] Γöé | ^~~~~~~~~~~~
[build] Γöé | |
[build] Γöé | (3) entry to 'split_string'
[build] Γöé......
[build] Γöé 10 | if (l > NUM_CHARS)
[build] Γöé | ~
[build] Γöé | |
[build] Γöé | (5) following 'true' branch (when 'l >
1')... ΓöÇ>ΓöÇΓöÉ
[build] Γöé |
Γöé
[build] Γöé |
Γöé
[build] Γöé
|ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
[build] Γöé 11 |Γöé {
[build] Γöé 12 |Γöé char s[NUM_CHARS + 1];
[build] Γöé |Γöé ~
[build] Γöé |Γöé |
[build] Γöé |Γöé (4) capacity: 2 bytes
[build] Γöé 13 |Γöé memcpy(s, str, NUM_CHARS);
[build] Γöé |Γöé ~~~~~~~~~~~~~~~~~~~~~~~~~
[build] Γöé |Γöé |
[build] Γöé |ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ>(6) ...to here
[build] Γöé 14 | s[NUM_CHARS] = '\0';
[build] Γöé 15 | split_string(s);
[build] Γöé | ~~~~~~~~~~~~~~~
[build] Γöé | |
[build] Γöé | (7) calling 'split_string' from
'split_string'
[build] Γöé
[build] ΓööΓöÇΓöÇ> 'split_string': events 8-12
[build] Γöé
[build] Γöé 7 | void split_string(const char* str)
[build] Γöé | ^~~~~~~~~~~~
[build] Γöé | |
[build] Γöé | (8) entry to 'split_string'
[build] Γöé......
[build] Γöé 10 | if (l > NUM_CHARS)
[build] Γöé | ~
[build] Γöé | |
[build] Γöé | (10) following 'true' branch (when
'l > 1')... ΓöÇ>ΓöÇΓöÉ
[build] Γöé |
Γöé
[build] Γöé |
Γöé
[build] Γöé
|ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
[...]
```
It looks like the analyzer is assuming the branch of `if (l> NUM_CHARS)` true
even when is false, basically doesn't logically follow the first 2 lines of the
spit_string function.
At least it looks like so to me.