2015-05-08 4 views
12

Я включил -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 и для друга с clang 3.4-1ubuntu3. Это не происходит для меня по версии gcc 4.9.2

Так что же здесь? Действительно ли этот код плохой, или есть что-то подозрительное, продолжающееся на конце clang?

+1

Просто 'os << std :: hex;', похоже, также воспроизводит проблему. – dyp

+0

http://stackoverflow.com/questions/20617788/using-memory-sanitizer-with-libstdc Возможно это? –

+0

Мне понравилось бы более описательное название, но мне трудно найти его. –

ответ

12

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

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

Вот исправление, исправленное; В следующие несколько дней я буду искать это до libstdC++ вверх по течению. [...]

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

Следующий отчет libstdc++ ошибки: bad enum values computed by operator~ in ios_base.h охватывает эту проблему и говорит:

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

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

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

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

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

, а hvd говорит, что это формально неуказанное поведение, но Ричард указывает, что на практике заканчивается неопределенное поведение.

T.C. указывает на то, это было изменено от неопределенного к неопределенному поведению с помощью DR 1766: Values outside the range of the values of an enumeration:

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

Новая редакция представлена ​​в черновике стандарта в N4431.

+0

О, действительно интересно. Слишком плохое их фильтрация вручную удаляет возможность использования gdb для разрыва таких ошибок, чтобы получить стек для их исправления. – Tobias

+0

Тот факт, что литой производит неопределенное значение, означает, что поведение * определено *. Если поведение будет неопределенным, стандарт скажет, что поведение не определено. (Тем не менее, это по-прежнему не полезно, поэтому код все равно должен быть изменен.) – hvd

+0

@hvd хорошо, что говорит Ричард: «на практике он выдает значение Enum за пределами диапазона представляемых значений для типа Enum, поэтому поведение не определено» к тому времени, когда дезинфицирующее средство увидит, что это различие может быть недоступным. –

Смежные вопросы