c++gccc++20glibcfortify-source

call to ‘__wmemcpy_chk_warn’: "wmemcpy called with length bigger than size of destination buffer"


I have this snippet of code (lets name it problem.cpp):

#include <string>

using str = std::wstring;
static str foo(str text = str())
{
    text.resize(4);
    return text;
}

int main()
{
    str a = foo();
    return 0;
}

GCC (version 12.2.1) called with -O1 and C++20 conformity (g++ problem.cpp -Werror -O1 -std=c++20) leads to this error:

In file included from /usr/include/features.h:490,
                 from /usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g++-v12/x86_64-pc-linux-gnu/bits/os_defines.h:39,
                 from /usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g++-v12/x86_64-pc-linux-gnu/bits/c++config.h:655,
                 from /usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g++-v12/string:38,
                 from problem.cpp:1:
In function ‘wchar_t* wmemcpy(wchar_t*, const wchar_t*, size_t)’,
    inlined from ‘static constexpr std::char_traits<wchar_t>::char_type* std::char_traits<wchar_t>::copy(char_type*, const char_type*, std::size_t)’ at /usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g++-v12/bits/char_traits.h:558:16,
    inlined from ‘constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = wchar_t; _Traits = std::char_traits<wchar_t>; _Alloc = std::allocator<wchar_t>]’ at /usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g++-v12/bits/basic_string.h:675:23,
    inlined from ‘str foo(str)’ at problem.cpp:7:9,
    inlined from ‘int main()’ at problem.cpp:12:14:
/usr/include/bits/wchar2.h:39:10: error: call to ‘__wmemcpy_chk_warn’ declared with attribute warning: wmemcpy called with length bigger than size of destination buffer [-Werror=attribute-warning]
   39 |   return __glibc_fortify_n (wmemcpy, __n, sizeof (wchar_t),
      |          ^~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors

Interestingly, I cannot trigger this error, either by using std::string (in contrast to std::wstring), using lower resize values, or anything below C++20 or O1.

To me, this snippet of code does not look suspicious. Unfortunately, I can't reproduce this with Godbolt. Maybe Godbolt uses another and/or not fortified glibc version? I'm using glibc version 2.36 on Gentoo Linux, but I have seen this on Ubuntu as well. However, before I suspect a bug in glibc or the compiler, I'm reaching out here, if this is in fact a false positive.

Any ideas?

EDIT: In the meantime, I could reproduce a similar error using Godbolt: https://godbolt.org/z/joPaYKK11


Solution

  • This is a bug in the libstdc++.

    The developers reacted very quickly and fixed the problem for 12.3.

    Thanks to srohmen, KamilCuk and user17732522 for the helpful discussion in question and comments above!

    The warning came from a branch of code that is never executed in the case that triggered the warning. The fix is to tell the compiler this by inserting __builtin_unreachable().

    C++23 introduces std::unreachable which also has the task to tell the compiler that this branch in the code will never be executed. Note that it is not necessarily equivalent to GCC's __builtin_unreachable(), since std::unreachable only guarantees undefined behavior! In practice you have to test whether std::unreachable solves a concrete problem or whether you have to fall back on a compiler-specific well-defined builtin.