Действительно ли этот код не определен, как указывает Кланг?

Я включил -fsanitize=undefined на моем проекте, который использует Catch, библиотеку модульного тестирования. Одна строка из Catch была сигнализирована как вызывающая неопределенное поведение этого флага. Мне удалось сделать отдельный пример:

#include <iomanip>
#include <sstream>

int main()
{
std::ostringstream os;
os << "0x" << std::setfill('0') << std::hex;
}

Составлено с:

clang++ -fsanitize=undefined main.cpp

Если я запускаю это, выдается следующий отпечаток:

/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/ios_base.h:96:24: runtime error: load of value 4294967221, which is not a valid value for type 'std::_Ios_Fmtflags'
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/ios_base.h:76:67: runtime error: load of value 4294967221, which is not a valid value for type 'std::_Ios_Fmtflags'

Это происходит для меня на лязг 3.6.0 и для друга с лязгом 3.4-1ubuntu3, Это не происходит для меня на версии GCC 4.9.2

Так что здесь? Этот код на самом деле плохой, или что-то подозрительное происходит на конце Clang?

12

Решение

Это ошибка в libstdc ++, от cfe-dev список рассылки с заголовком -fsanitize = неопределенные и общие библиотеки говорит:

Это ошибка в libstdc ++. Вы сможете обойти это с
файл черного списка дезинфицирующего средства, однажды патч Уилла для этой земли, но для
Теперь их фильтрация, вероятно, будет лучшим вариантом.

Вот патч, чтобы это исправить; Я буду смотреть на это
libstdc ++ upstream в ближайшие несколько дней. […]

Как я отмечал в комментариях, это не редкость видеть системы, где clang использования libstdc++ в отличие от libc++ и если мы проверим это на Coliru явно использует libstdc ++ с помощью -stdlib=libstdc++ мы действительно можем воспроизвести проблему.

Следующие libstdc++ сообщение об ошибке: неверные значения перечисления, вычисленные оператором ~ в ios_base.h освещает эту проблему и говорит:

Перегруженный оператор ~ определен для перечислений в ios_base.h
иметь следующую форму:

Enum operator~(Enum e) { return Enum(~static_cast<int>(e)); }

~ Создает значения вне диапазона значений перечисления
тип, поэтому приведение к типу Enum имеет неопределенное значение (см.
[expr.static.cast] p10), и на практике он выдает значение Enum
вне диапазона представимых значений для типа Enum, так
поведение не определено.

Для справки [Expr.static.cast] р10 говорит:

Значение целочисленного типа или типа перечисления может быть явно преобразовано в тип перечисления. Значение
не изменяется, если исходное значение находится в диапазоне значений перечисления (7.2). В противном случае, в результате
значение не указано (и может не входить в этот диапазон). Значение типа с плавающей точкой также может быть преобразовано
к типу перечисления. Полученное значение совпадает с преобразованием исходного значения в базовый
тип перечисления (4.9), а затем и тип перечисления.

и, как говорит Х.В.Д., это формально неуказанное поведение, но Ричард отмечает, что на практике это в конечном итоге неопределенное поведение.

Агар Т.С. указывает, что это было изменено с неопределенного на неопределенное поведение DR 1766: значения вне диапазона значений перечисления:

Хотя в выпуске 1094 поясняется, что значение выражения типа перечисления может не входить в диапазон значений перечисления после преобразования в тип перечисления (см. Пункт 5.2.9 [expr.static.cast], пункт 10), результат это просто неопределенное значение. Это, вероятно, следует усилить, чтобы получить неопределенное поведение, в свете того факта, что неопределенное поведение делает выражение непостоянным. См. Также 9.6 [class.bit] параграф 4.

Новая формулировка появляется в проекте стандарта в N4431.

12

Другие решения


По вопросам рекламы [email protected]