7

I am using fmt::format from the fmtlib extensively. After updating Visual Studio 2022 from 17.3.5 to 17.4.0 I have a problem in Release Builds with Code like the following:

const std::string s1 = format("{}.{}", "abc", "test" );

While s1 and s1.c_str() is "abc.test" in Debug Builds, in Release Builds using fmtlib only s1 is "abc.test" and s1.c_str() returns "abc.test" followed by some garbage (e.g. "abc.testð_àô").

I have written a small test program:

#include <iostream>
#include <string>
#ifdef USE_STD_FORMAT
#include <format>
using std::format;
#else
#include <fmt/format.h>
using fmt::format;
#endif

void check(const std::string& s, const std::string& expected)
{
    if (s != expected)
        std::cout << "FAILED I: '" << s << "' != '" << expected << "'\n";
    else if (strcmp(s.c_str(), expected.c_str()) != 0)
        std::cout << "FAILED II: '" << s.c_str() << "' != '" << expected.c_str() << "'\n";
}

void test(const char* p1, const char* p2)
{
    const std::string s1 = format("{}.{}", p1, p2);
    const std::string s2 = std::string(p1).append(".").append(p2);

    check(s1, s2.c_str());
}

int main()
{
    std::cout << "_MSC_FULL_VER: " << _MSC_FULL_VER << "\n";
#if USE_STD_FORMAT
    std::cout << "using std::format\n";
#else
    std::cout << "using fmt::format\n";
#endif

    test("abc", "test");
    test("abc", "test");
}

Built with VS2022 17.3.5 the output is:

C:\Temp\VS2022_17.4\x64>C:\Temp\VS2022_17.4\x64\Debug\VS2022_17.4.exe
_MSC_FULL_VER: 193331630
using fmt::format

C:\Temp\VS2022_17.4\x64>C:\Temp\VS2022_17.4\x64\Release\VS2022_17.4.exe
_MSC_FULL_VER: 193331630
using fmt::format

C:\Temp\VS2022_17.4\x64>C:\Temp\VS2022_17.4\x64\Release_StdFormat\VS2022_17.4.exe
_MSC_FULL_VER: 193331630
using std::format

Build with VS2022 17.4.0 the output is

C:\temp\VS2022_17.4\x64>C:\temp\VS2022_17.4\x64\Debug\VS2022_17.4.exe
_MSC_FULL_VER: 193431933
using fmt::format

C:\temp\VS2022_17.4\x64>C:\temp\VS2022_17.4\x64\Release\VS2022_17.4.exe
_MSC_FULL_VER: 193431933
using fmt::format
FAILED II: 'abc.testð_àô ' != 'abc.test'
FAILED II: 'abc.testð_àô ' != 'abc.test'

C:\temp\VS2022_17.4\x64>C:\temp\VS2022_17.4\x64\Release_StdFormat\VS2022_17.4.exe
_MSC_FULL_VER: 193431933
using std::format

Because it works with std::format in both Visual Studio versions and it works with VS2022 17.3.6 with both format versions I don't know if it is a problem in Visual Studio or in fmtlib or in my code.

vitaut
  • 49,672
  • 25
  • 199
  • 336
Stefan F.
  • 141
  • 2
  • About your includes ,there is a preprocessor test #if __has_include( include-file ) – engf-010 Nov 11 '22 at 13:23
  • 2
    if you think it's a compiler-bug (IMHO it looks like it) ,in visual studio there is a feedback button in right upper-corner (below the close button) which automatically redirect you to the webpage where you can file the issue (might already be filed). – engf-010 Nov 11 '22 at 13:36
  • 2
    Well, the most useful new feature in 17.4.0 is that they made it easy to rollback an update. Looks like you'll need it, sorting out who is responsible for agilely fixing this problem tends to take a while. https://www.neowin.net/news/visual-studio-2022-174-lets-you-roll-back-to-a-previous-version/ – Hans Passant Nov 11 '22 at 14:04
  • 2
    I reported the problem to microsoft: https://developercommunity.visualstudio.com/t/Code-using-fmtlib-format-breaks-after-Vi/10198870 – Stefan F. Nov 11 '22 at 14:38

1 Answers1

1

This is a bug in Microsoft STL, quoting https://developercommunity.visualstudio.com/t/Code-using-fmtlib-format-breaks-after-Vi/10198870:

The issue is that the constructor for std::string was not adding the null terminator itself so when being constructed with a char * that is not null terminated, c_str() will return garbage until a zero byte is hit.

vitaut
  • 49,672
  • 25
  • 199
  • 336