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.