Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the Sub-expression overflow reasoning

Tags:

c++

64-bit

I am trying to understand the reasoning behind this particular suggestion in Visual Studio 2022, as it doesn't seem to make sense to me. Here's the simple code:

static constexpr uint32_t MAX_ELEMENTS = 100000;
const std::vector<int> A{ some random ints };


std::vector<bool> found(MAX_ELEMENTS);
for (int value : A)
{
    if (value > 0 && value <= MAX_ELEMENTS)
        found[value - 1] = true;             // Problem it complains about is the value - 1.
}

It suggests that a "sub-expression may overflow before being added to a wider type". Now obviously the condition-if prevents this from ever happening, but what's the reasoning here?

Now if this was a Spectre thing, I could understand that the compiler would add a memory fence to stop any speculative execution of the statement after the if, but I don't think that's the answer here.

My only thinking is that it has to do with the subscript operator on the vector; that its index is of a type larger than int and is implicitly cast to size_t?

Just seems a little unintuitive that the below is an issue:

found[value - 1]

and its perfectly fine to do this,

int a = value - 1;
found[a];

when the end result is the same. What am I missing here in terms of understanding?

like image 566
The Welder Avatar asked May 25 '26 18:05

The Welder


1 Answers

In this case, it is a false positive, as you suspected. This is a rule that sometimes gets used in stricter code bases. (This particular warning is an error in MISRA, for example.)

A lot of warnings are like this... the compiler writers are trying to detect a situation where the behavior of the program is unexpected or unintentional, but the warnings are not always correct. For example,

uint64_t x = 0xffffffffu << 16;

On a system with 32-bit int, the standard is very clear what the value of this is supposed to be... it's supposed to be:

uint64_t x = 0xffff0000u;

However, it does look like someone meant to write this instead:

uint64_t x = (uint64_t)0xffff0000 << 16;

That's what the warning is trying to catch. That's the reasoning behind this rule. In your case, the compiler is doing a bad job of it.

You can see a more detailed justification for the warning in the compiler documentation: Warning C26451.

Spectre has nothing to do with it.

It's perfectly fine...

To do this:

int a = value - 1;
found[a];

In this case the "intent" is more obvious, because the programmer has explicitly written out "int" as the type.

Solutions

This is a code style issue, so there are a few different solutions and you pick whatever one you feel comfortable with.

  • Leave the warning on (noisy, may distract you from real warnings)

  • Assign the expression to an int first (verbose)

  • Disable the warning across the code base (if you don't think it's helpful)

  • Disable the warning around this location with a #pragma warning (very verbose)

like image 51
Dietrich Epp Avatar answered May 27 '26 08:05

Dietrich Epp