Coverity bounds issue when using enum in C++

1 day ago 2
ARTICLE AD BOX

Your array creates named constants: APPLE=0, ORANGE=1, PEAR=2, NUM_FRUIT=3. But the underlying type is int, and the compiler doesn't restrict what values a FRUIT_ID variable can actually hold. Only values 0, 1, 2 get through the if, so the array access is always safe.

Coverity analyzes the type of id. It knows FRUIT_ID is backed by int. So it reasons:

id is an int int can be -2147483648 to 2147483647 I see a check: id >= 0 && id < 3 But do I trust that check constrains the array access? ...i'm not sure. I'll flag it anyway

Why the distrust? Because this is perfectly legal C++:

void somewhere_else() { FRUIT_ID bad = static_cast<FRUIT_ID>(100); checkFruit(bad); // Ccompiles fine. No warning. }

Or worse:

void read_from_file(int value) { checkFruit(static_cast<FRUIT_ID>(value)); // value could be anything }

Your check catches these at runtime. But Coverity's analyzer doesn't always propagate the constraint from your if condition to the array index operation. It's a limitation of its dataflow analysis for enum types.

The main issue here is C++ enums are "strongly named" but "weakly typed." The names suggest a closed set; the type allows anything. Coverity errs on the side of caution because it can't prove all callers behave.

You have a few options depending on what trade-offs you're willing to make here-

1. Suppress the warning (easiest, if your check is genuinely sufficient):

bool checkFruit(const FRUIT_ID id) const { if (id >= 0 && id < NUM_FRUIT) { // coverity[overrun-local] return fruit[id].bitten; } return false; }

You're telling Coverity "I know what I'm doing here."

2. Use an intermediate int variable (I am assuming this should alos pass Coverity):

bool checkFruit(const FRUIT_ID id) const { int index = static_cast<int>(id); if (index >= 0 && index < NUM_FRUIT) { return fruit[index].bitten; } return false; }

Coverity tracks int bounds more reliably than enum bounds.

3. Use enum class with a fixed underlying type (comes from C++11+):

enum class FRUIT_ID : unsigned int { APPLE = 0, ORANGE, PEAR, NUM_FRUIT };

This makes the type explicit and can help some analyzers reason better. You'll need static_cast to use it as an index though.

4. Use std::array with .at() for bounds-checked access:

std::array<Fruit, NUM_FRUIT> fruit; bool checkFruit(const FRUIT_ID id) const { try { return fruit.at(static_cast<size_t>(id)).bitten; } catch (const std::out_of_range&) { return false; } }

Overkill for most cases, but makes the bounds check explicit and exception-safe.

Read Entire Article