Стоит ли беспокоиться о том, что «условный переход или перемещение зависят от неинициализированных значений»? - PullRequest
4 голосов
/ 19 апреля 2009

Если вы использовали Memcheck (от Valgrind), вы, вероятно, знакомы с этим сообщением ...

Условный переход или перемещение зависит от неинициализированных значений

Я читал об этом, и это просто происходит, когда вы используете неинициализированное значение.

MyClass s;
s.DoStuff();

Это будет работать, потому что s автоматически инициализируется ... Так что, если это так, и это работает, почему Memcheck говорит мне, что он не инициализирован? Следует ли игнорировать сообщение?

Возможно, я неправильно понял, куда меня направляла ошибка. Из руководства Valgrind фактический ошибочный фрагмент кода ...

int main()
{
  int x;
  printf ("x = %d\n", x);
}

Однако в моем коде я не вижу ничего подобного. Однако я заметил, что функция в верхней части трассировки стека, которую Memcheck показывает мне, является виртуальной функцией; это может быть как-то связано с этим?

==14446== Conditional jump or move depends on uninitialised value(s)
==14446==    at 0x414164: vimrid::glut::GlutApplication::FinishRender() (GlutApplication.cpp:120)
==14446==    by 0x422434: vimrid::demos::filterdemos::FilterDemo3::Render() (FilterDemo3.cpp:260)
==14446==    by 0x412D3D: vimrid::VimridApplication::UpdateAndRender() (VimridApplication.cpp:93)
==14446==    by 0x4144BA: vimrid::glut::GlutApplication::glutHandleDisplay() (GlutApplication.cpp:201)
==14446==    by 0x41486A: vimrid::glut::GlutApplication::glutCallbackDisplay() (GlutApplication.cpp:277)
==14446==    by 0x54D9FAA: (within /usr/lib64/libglut.so.3.8.0)
==14446==    by 0x54DDA4A: fgEnumWindows (in /usr/lib64/libglut.so.3.8.0)
==14446==    by 0x54DA4A3: glutMainLoopEvent (in /usr/lib64/libglut.so.3.8.0)
==14446==    by 0x54DAEB5: glutMainLoop (in /usr/lib64/libglut.so.3.8.0)
==14446==    by 0x413FF8: vimrid::glut::GlutApplication::Run() (GlutApplication.cpp:112)
==14446==    by 0x41249D: vimrid::Launcher::runDemo(vimrid::VimridSettings&) (Launcher.cpp:150)
==14446==    by 0x412767: vimrid::Launcher::Launch(int, char**) (Launcher.cpp:62)

Обновление 1:

Я взглянул на GlutApplication.cpp: 120, и похоже, что неинициализированная переменная была передана функции в этой строке. Простой!

Ответы [ 6 ]

17 голосов
/ 15 апреля 2011

Вы можете добавить флаг --track-origins=yes в valgrind, и он даст вам информацию об источниках неинициализированных данных. Он работает медленнее, но может быть полезным.

Источник: Руководство пользователя Valgrind

6 голосов
/ 19 апреля 2009

Можете ли вы опубликовать более полный образец? Трудно понять, как возникнет эта конкретная ошибка без какой-либо формы оператора перехода или изменения потока.

Я чаще всего вижу эту ошибку в коде, подобном следующему

MyClass s1;
...
if ( someCondition ) { 
  goto Foo:
}
MyClass s2;
Foo:
cout << s2.GetName();

Этот код в корне неверен. Причина в том, что, хотя s2 имеет конструктор, он не выполняется, если someCondition имеет значение true. Оператор goto перепрыгнет через инициализацию и в последней строке программы s2 будет неинициализирован и по существу будет указывать на мусор.

EDIT

Возможно, вы также захотите проверить эту страницу, которая дает советы о том, как расшифровать эту конкретную ошибку valgrind

https://computing.llnl.gov/code/memcheck/#deciphering4

Добавление

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

Я почти собирался сдаться и просто посчитал, что Вальгринд глуп, тогда я понял, что простое приведение его к длинному исправляет это.

Итак, мой итог: отнеситесь к этим сообщениям серьезно.

3 голосов
/ 20 апреля 2009

Если Valgrind заявляет, что значение не инициализировано, то в 99,5% оно действительно не инициализируется. Обычно, когда компилятор сообщает об использовании неинициализированного значения (-Wuninitialized в GCC), вы проверяете встроенные развертки, поскольку ваше неинициализированное значение может быть объявлено (и не инициализировано), например, для 10 уровней "вызовов" встроенной функции (или развертывания шаблона) выше, чем фактический отчет GCC. Valgrind делает то же самое, но во время выполнения . Таким образом, вы должны проверить весь путь, по которому неинициализированное значение прошло от места объявления (а не инициализации) до места, где оно фактически используется. Путь может быть, например: каскад вызовов функций, где каждая функция передает свои аргументы (и, возможно, неинициализированное значение) следующей функции. Valgrind сообщит в последней функции о фактическом использовании значения.

Как правило, вы не должны игнорировать то, что утверждает Вальгринд. Valgrind - не простая программа трассировки. Это можно увидеть как виртуальную машину:

Valgrind по сути является виртуальным машина, использующая оперативность (JIT) методы составления, в том числе динамическая перекомпиляция. Ничего из оригинальная программа когда-либо запускается прямо на хост-процессоре. Вместо этого Valgrind сначала переводит программа во временную, более простую форму называется промежуточное представительство (IR), который является нейтральным к процессору, Форма на основе SSA. После преобразования инструмент (см. ниже) бесплатен какие бы преобразования он ни хотел на ИК, до того, как Valgrind переводит ИК обратно в машинный код и позволяет хост-процессор запускает его. Даже если он может использовать динамический перевод (что есть, хост и целевые процессоры от разных архитектур), это не делает. Valgrind перекомпилирует двоичный файл код для запуска на хосте и цели (или смоделировано) Процессоры одинаковые архитектура. (Википедия)

1 голос
/ 30 апреля 2012

В 64-битной машине. Обычно int занимает 4 байта в памяти. Но долго будет занимать 8 байт в памяти. Так что просто обратитесь к значению int, так как длинный формат приведет к совершенно неверному результату. В этой ситуации требуется преобразование.

1 голос
/ 19 апреля 2009

Было бы очень полезно, если бы вы могли опубликовать больше кода, особенно из той части, где valgrind считает, что ошибка.

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

И да: вы должны беспокоиться об этой ошибке, эти парни могут вас укусить.

0 голосов
/ 20 апреля 2009

Ошибка, похоже, не в вашем коде, а в используемой вами библиотеке.

Valgrind поставляется с некоторым подавлением ошибок по умолчанию, но это, вероятно, не распространяется на используемую вами библиотеку.

Инструменты проверки ошибок обнаруживают многочисленные проблемы в базовых библиотеках, таких как библиотека GNU C и клиентские библиотеки X11, которые предварительно установлены в вашей системе GNU / Linux. Вы не можете легко исправить это, но вы не хотите видеть эти ошибки (и да, их много!), Поэтому Valgrind читает список ошибок, которые нужно устранить при запуске. Файл подавления по умолчанию создается скриптом ./configure при сборке системы.

Вы можете создать свои собственные средства подавления ошибок , которые, как вы знаете, не имеют отношения к вашему коду.

См. Аналогичный вопрос SO Почему Valgrind не нравится мое использование glutCreateWindow?

...