Итак, я столкнулся со странной ошибкой на работе, когда пытался уменьшить размер структуры с помощью битовых полей.Мне удалось изолировать проблему и создать минимальную версию, которая повторяет проблему.Это имело дополнительное преимущество: MSVC теперь даже предупреждает о том, что собирается делать: Ссылка на Compiler Explorer .Однако у Clang и GCC нет проблем с этим кодом.
#include <new>
enum foo : unsigned char { zero, one };
struct S
{
int a{ 42 }; //Intentionally not trivial
foo b : 1;
foo c : 1;
};
auto test()
{
constexpr auto size = sizeof (S);
constexpr auto alignment = alignof(S);
struct {
alignas(alignment) unsigned char bytes[size];
} data;
//Buffer overrun on this line
::new(static_cast<void*>(&data)) S{};
//Just to avoid optimizing away the offending instructions
return data;
}
Используемый мной буфер должен подходить для хранения объекта, поскольку он имитирует std::aligned_storage
, а я вызываю TrueРазмещение Новое для хранения в нем моего объекта.Я считаю, что так работает f.ex std::vector
.Несмотря на это, я получаю это предупреждение:
предупреждение C4789: буфер «data» размером 8 байт будет переполнен;5 байтов будут записаны, начиная со смещения 4
Странно то, что проблема исчезает, если скобки заменены круглыми скобками (хотя все равно следует инициализировать значение, верно?) Или просто удалить полностью (по умолчанию)инициализировано).
Проблема также исчезнет, если S
тривиально.Кроме того, проблема возникает только с включенными оптимизациями (из-за этого вы получили удовольствие от отладки).
Я не верю, что я вызываю здесь неопределенное поведение, но альтернатива заключается в том, что в VS 2017 и 2019 есть ошибка. В настоящее время я работаю над этой проблемой, просто не используя фигурную инициализацию и придерживаясь скобок, гдеЯ подозреваю, что могут быть проблемы, но это кажется неправильным.
Почему это происходит, и что я могу сделать, чтобы не беспокоиться о бомбах замедленного действия в моем коде?Переключение на другой компилятор не вариант.
Обновление: Итак, глядя на сборку, я вижу, что она все еще генерирует подозрительный код при использовании скобок дляинициализация значения триггера.Только при инициализации по умолчанию получается ожидаемая сборка.Кажется довольно странным, и я определенно подозреваю, что ошибка компилятора, но я бы предпочел больше информации об этом.