28
// This snippet
for (const float t : std::array{ 0.0f, 0.33f, 0.66f, 1.0f }) {
  std::cout << "t = " << t << "\n";
}
// Yields the following (incorrect) values:
t = -3.91649e-28
t = 4.59037e-41
t = 2.66247e-44
t = 0

// Whereas this snippet ...
auto vals = std::array{ 0.0f, 0.33f, 0.66f, 1.0f };
for (const float t : vals) {
  std::cout << "t = " << t << "\n";
}
// Yields the following (correct) values:
t = 0
t = 0.33
t = 0.66
t = 1

Is the first snippet undefined behavior, or is this a compiler bug?

Update: This was compiled with Visual Studio 16.7.2 and 16.7.3 using std=c++17 and /Ox. The error persists in my bug project, but I have not been able to reproduce it in a small project using similar build flags. The problem persist if I use integers instead of floating points.

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
  • 2
    both work exactly the same using gcc – artm Sep 09 '20 at 10:01
  • Which version of MSVC? It works for me with 19.26.28806 (Visual Studio 2019). Did you enable C++17? Could you provide complete compilable code? – Daniel Langr Sep 09 '20 at 10:41
  • Could not reproduce with MSVS 16.6.30204.135 (amd64) – SebastianH Sep 09 '20 at 10:42
  • Unable to reproduce. Works for me, vs 2017, version 15.9.4 – Gonen I Sep 09 '20 at 10:55
  • I have not yet been able to produce it in a fresh project. – Viktor Sehr Sep 09 '20 at 11:08
  • @ViktorSehr Then, there is likely some memory corruption in your code, such as buffer overflow. For instance, look at this assembly, where the values of the array elements are stored at line 14 and loaded at line 1170: https://godbolt.org/z/MY85q3 (coded as `0x3f8000003f28f5c33ea8f5c300000000`). You likely overwrite them somehow in between. – Daniel Langr Sep 09 '20 at 11:16
  • 6
    Re your "Update". Being unable to create a "small project" (i.e. a [mcve]) that exhibits a problem that occurs in a larger code base means that the problem is unlikely to be what you think it is. In the larger code base, there is probably some other (possibly unrelated) code that happens to trigger the behaviour you see (e.g. because that code exhibits undefined behaviour in some way). The reason you can't reproduce it in a "small project" is because you are removing the code which actually causes the problem from that "small project". And it is unlikely to be a compiler bug. – Peter Sep 09 '20 at 11:48
  • Thanks for the responses, the problem unfortunately seems to persist wherever I put this loop in my large code-base (which runs fine except from this). Memory corruption seems to be the logical problem, but I cannot understand why it's only visible in this loop. I'm continuing to investigate anyway. – Viktor Sehr Sep 09 '20 at 12:10
  • Adding to what @DanielLangr said, using \Ox causes the compiler to not even call array initialization functions. Instead, the array data seems to be loaded into a XMM register and then to the stack. The memory loaded to the XMM register also seems to be fine. – Pedro Boechat Oct 04 '20 at 13:19

1 Answers1

21

No, it is not UB since range-for loop does extend lifetime of temporary range. https://en.cppreference.com/w/cpp/language/range-for

If range_expression returns a temporary, its lifetime is extended until the end of the loop, as indicated by binding to the forwarding reference __range, but beware that the lifetime of any temporary within range_expression is not extended.

Taking into consideration fact, that gcc has no problem with this code it is probably MSVC bug.

bartop
  • 9,971
  • 1
  • 23
  • 54
  • 2
    Thanks, then this is a bug in MSVC under certain conditions, trying to investigate how I can reproduce it in a small project. – Viktor Sehr Sep 09 '20 at 11:09