Переполнение буфера с помощью битовых полей и инициализация значения - ошибка компилятора или неопределенное поведение? - PullRequest
14 голосов
/ 20 сентября 2019

Итак, я столкнулся со странной ошибкой на работе, когда пытался уменьшить размер структуры с помощью битовых полей.Мне удалось изолировать проблему и создать минимальную версию, которая повторяет проблему.Это имело дополнительное преимущество: 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 есть ошибка. В настоящее время я работаю над этой проблемой, просто не используя фигурную инициализацию и придерживаясь скобок, гдеЯ подозреваю, что могут быть проблемы, но это кажется неправильным.

Почему это происходит, и что я могу сделать, чтобы не беспокоиться о бомбах замедленного действия в моем коде?Переключение на другой компилятор не вариант.

Обновление: Итак, глядя на сборку, я вижу, что она все еще генерирует подозрительный код при использовании скобок дляинициализация значения триггера.Только при инициализации по умолчанию получается ожидаемая сборка.Кажется довольно странным, и я определенно подозреваю, что ошибка компилятора, но я бы предпочел больше информации об этом.

1 Ответ

2 голосов
/ 25 сентября 2019

Эта ошибка компилятора исправлена ​​в VS 2019 16.5 .

В качестве обходного пути для тех, кто не может выполнить обновление, рассмотрите возможность замены скобок с обычными скобками, например, замените S{...}; на * 1006.*.Если в конструктор не переданы аргументы, рассмотрите возможность простого удаления фигурных скобок, поскольку объект по-прежнему создается по умолчанию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...