Asaf Asaf - 23 days ago 6
C++ Question

Is it a Visual C++ optimizer bug or do I have a bug in my code?

We're in the process of migrating from VS2013 to VS2017.

Below is a probably not so minimal code sample, but it's the best I could do.
The gist of it is that a specific float value is sent to a function, but the function receives the wrong value - this is because of a registers mismatch in the calling function.

This code runs incorrectly on VC141 (VS 2017) and VC140 (VS 2015), but runs correctly on VC120 (VS 2013) and on the clang version which comes built in with VS 2017 (Clang with Microsoft CodeGen (v141_clang_c2) - whatever clang compatible version it is).

The problem manifests when compiling for x64 platform in Release (with optimizations). When removing optimizations the code works fine, so my guess is the optimizer.
The wrong behavior is in

badFunc()
when calling
test()
.

The code:

#include <iostream>
#include <vector>

struct FloatWrapper
{
FloatWrapper() : m_value(0) {}
explicit FloatWrapper(float value) : m_value(value) {}
float getValue() const { return m_value; }

private:
float m_value;
};

class Tester
{
public:

virtual bool test(FloatWrapper elevation) const
{
std::cout << "Expected=" << m_expected.getValue() << ", received=" << elevation.getValue() << '\n';
return elevation.getValue() == m_expected.getValue();
}

Tester(FloatWrapper expected) : m_expected(expected)
{
}

FloatWrapper m_expected;

};

struct DataBlock
{
FloatWrapper a, b;
};

bool badFunc(const Tester& query, std::vector<DataBlock> blocks)
{
auto block = blocks[0];

if (!query.test(block.b))
{
std::cout << "Tried to send " << block.b.getValue() << '\n';
return false;
}

return true;
}


int main(int argc, const char** argv)
{
DataBlock block;
block.b = FloatWrapper(0.2f);

Tester tester(block.b);

return badFunc(tester, { block }) ? 0 : 1;
}


Compiler command line:

/GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /Fd"x64\Release\vc141.pdb" /Zc:inline /fp:precise /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Fp"x64\Release\compiler_bug_vc14.pch" /diagnostics:classic


Linker command line:

/OUT:"x64\Release\compiler_bug_vc14.exe" /MANIFEST /LTCG:incremental /NXCOMPAT /PDB:"x64\Release\compiler_bug_vc14.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG:FULL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO /PGD:"x64\Release\compiler_bug_vc14.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Release\compiler_bug_vc14.exe.intermediate.manifest" /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1

Answer Source

The answer is yes - it is an optimizer bug. Microsoft say they fixed it and it is currently (24 Sep `17) pending release.

See https://developercommunity.visualstudio.com/content/problem/84976/optimizer-bug-in-vc140141-passing-the-wrong-float.html