[Bug other/103542] New: bogus -Warray-bounds while index is limited by switch/case
patrickdepinguin at gmail dot com
gcc-bugzilla@gcc.gnu.org
Fri Dec 3 15:33:43 GMT 2021
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103542
Bug ID: 103542
Summary: bogus -Warray-bounds while index is limited by
switch/case
Product: gcc
Version: 11.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: other
Assignee: unassigned at gcc dot gnu.org
Reporter: patrickdepinguin at gmail dot com
Target Milestone: ---
gcc 11.2.0 reports the following on a reduced test case:
$ powerpc-linux-gcc -c array-bounds-fruit.c -O2 -Wall -Werror
array-bounds-fruit.c: In function 'get_default_config.part.0':
array-bounds-fruit.c:69:37: error: array subscript 4 is above array bounds of
'struct fruit_config[4]' [-Werror=array-bounds]
69 | do_something(id, &config[id].num_lemons);
| ~~~~~~^~~~
array-bounds-fruit.c:19:28: note: while referencing 'config'
19 | static struct fruit_config config[4];
| ^~~~~~
cc1: all warnings being treated as errors
Above is for powerpc, but I have the same problem with ARM.
The offending line is inside a switch/case, within the block where 'id' is
tested to be 0, 1, 2, or 3.
gcc/g++ is considering a case where 'id' becomes 4, which is not possible in
this code.
If I make any more changes (even seemingly unrelated changes) to the test case,
the error disappears.
Test code:
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
enum {
ID_0 = 0,
ID_1 = 1,
ID_2 = 2,
ID_3 = 3,
MAX_IDS,
};
#define MAX_ENTRIES 256
struct fruit_config {
uint32_t num_apples;
uint32_t num_lemons;
uint32_t * lemons;
};
static struct fruit_config config[4];
static uint32_t unrelated_table[MAX_IDS][MAX_ENTRIES];
uint32_t do_something(const uint32_t id, uint32_t * number_of_entries)
{
uint32_t error = 0;
switch (id) {
/* merging these case statements with identical body removes the issue
*/
case ID_0: {
*number_of_entries = 0;
break;
}
case ID_1: {
*number_of_entries = 0;
break;
}
case ID_2: {
*number_of_entries = 0;
break;
}
case ID_3: {
*number_of_entries = 0;
break;
}
default: {
error = 0xff;
*number_of_entries = 0;
break;
}
}
return error;
}
struct fruit_config * get_default_config(const uint32_t id)
{
switch (id) {
case ID_0:
case ID_1:
case ID_2:
case ID_3:
{
uint32_t entry = 0;
for (entry = 0; entry <config[id].num_apples ; entry++) {
unrelated_table[0][0] = 0;
}
config[id].num_apples = 0;
do_something(id, &config[id].num_lemons);
/* removing following two lines removes the issue, even though
* the error already occurs above */
config[id].num_lemons = 0;
config[id].lemons = NULL;
/* removing use of error removes the issue */
extern void foo(uint32_t arg);
uint32_t error = 0;
foo(error);
break;
}
default: {
break;
}
}
return NULL;
}
void func_start(void)
{
uint32_t i = 0;
for (i = 0; i < MAX_IDS; i++) {
get_default_config(i);
}
}
More information about the Gcc-bugs
mailing list