точное указание «условный переход или перемещение зависит от неинициализированных значений» сообщение valgrind

166

Так что я получил какое-то загадочное сообщение с неинициализированными значениями от valgrind, и было довольно загадочно, откуда взялась плохая ценность.

Похоже, что valgrind показывает место, где в конечном итоге используется унифицированное значение, а не источник неинициализированного значения.

==11366== Conditional jump or move depends on uninitialised value(s)
==11366==    at 0x43CAE4F: __printf_fp (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43C6563: vfprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43EAC03: vsnprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x42D475B: (within /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E2C9B: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E31B4: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42EE56F: std::ostream& std::ostream::_M_insert<double>(double) (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)
==11366==    by 0x810B9F1: Snake::Snake::update() (snake.cpp:257)
==11366==    by 0x81113C1: SnakeApp::updateState() (snakeapp.cpp:224)
==11366==    by 0x8120351: RoenGL::updateState() (roengl.cpp:1180)
==11366==    by 0x81E87D9: Roensachs::update() (rs.cpp:321)

Как можно видеть, он становится довольно загадочным, особенно потому, что когда он говорит Class :: MethodX, он иногда указывает прямо на ostream и т. Д. Возможно, это связано с оптимизацией?

==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)

Просто так. Я что-то упускаю? Каков наилучший способ поймать плохие ценности, не прибегая к сверхдлинной работе детектива printf?

Обновить:

Я узнал, что было не так, но странно то, что Вальгринд не сообщал об этом, когда плохое значение было впервые использовано. Он был использован в функции умножения:

movespeed = stat.speedfactor * speedfac * currentbendfactor.val;

Где Speedfac был унитарным поплавком. Однако в то время об этом не сообщалось, и только когда должно быть напечатано значение, я получаю сообщение об ошибке. Существует ли параметр для valgrind, чтобы изменить это поведение?

kamziro
источник

Ответы:

230

Используйте параметр valgrind, --track-origins=yesчтобы он отслеживал происхождение неинициализированных значений. Это замедлит работу и займет больше памяти, но может быть очень полезно, если вам нужно отследить происхождение неинициализированного значения.

Обновление: Что касается точки, в которой сообщается неинициализированное значение, руководство valgrind заявляет :

Важно понимать, что ваша программа может копировать ненужные (неинициализированные) данные сколько угодно. Memcheck наблюдает за этим и отслеживает данные, но не жалуется. Жалоба выдается только тогда, когда ваша программа пытается использовать неинициализированные данные таким образом, чтобы это могло повлиять на внешне видимое поведение вашей программы.

Из Valgrind FAQ :

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

mark4o
источник
1
Какая минимальная версия valgrind для использования этой функции? Я использую 3.3.0, и мне не нравится этот вариант.
Роберт С. Барнс
8
@Robert: --track-originins был добавлен в valgrind
3.4.0
20

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

Если вам нужна дополнительная помощь, публикация соответствующих разделов исходного кода может позволить кому-то предложить больше рекомендаций.

РЕДАКТИРОВАТЬ

Я вижу, вы нашли проблему. Обратите внимание, что valgrind следит за условным переходом или перемещением на основе унифицированных переменных. Это означает, что он выдаст предупреждение только в том случае, если выполнение программы будет изменено из-за неинициализированного значения (т. Е. Программа принимает другую ветвь в операторе if, например). Поскольку действительная арифметика не подразумевала условного прыжка или движения, valgrind не предупредил вас об этом. Вместо этого он распространял статус «неинициализированный» на результат оператора, который его использовал.

Может показаться нелогичным, что он не предупреждает вас немедленно, но, как отметил mark4o , он делает это, потому что неинициализированные значения используются в C все время (примеры: заполнение в структурах, realloc()вызов и т. Д.), Поэтому эти предупреждения не будут очень полезно из-за ложной положительной частоты.

RarrRarrRarr
источник
Спасибо. Я только что узнал, что было не так, но странно то, что Вальгринд не сообщал об унифицированном значении, пока оно не использовалось где-то еще ...
Камзиро
Это намеренно. Если простое копирование или передача неинициализированных значений вызвало сообщение об ошибке, вы бы все время получали их от заполнения в структурах.
mark4o