точне вказівка ​​«умовний стрибок або переміщення залежить від неініціалізованого значення (s)» 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)

Як видно, він стає досить виразним .. тим більше, що коли він говорить за класом :: MethodX, він інколи вказує прямо на ostream тощо. Можливо, це пов'язано з оптимізацією?

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

Ось так. Щось мені не вистачає? Який найкращий спосіб зловити погані цінності, не вдаючись до наддовгих детективних робіт printf?

Оновлення:

Я з’ясував, що не так, але дивно, що valgrind не повідомив про це, коли вперше було використано погане значення. Він використовувався у функції множення:

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

Там, де speedfac був неіціалізованим поплавком. Однак на той час не повідомлялося, і поки не буде надруковано значення, я отримую помилку. Чи є налаштування для valgrind, щоб змінити цю поведінку?

Відповіді:


230

Використовуйте опцію valgrind, --track-origins=yesщоб вона відстежувала походження неініціалізованих значень. Це зробить це повільніше і займе більше пам’яті, але може бути дуже корисним, якщо вам потрібно буде з’ясувати походження неініціалізованого значення.

Оновлення: Що стосується точки, в якій повідомляється про неініціалізовану величину, у посібнику з valgrind зазначено :

Важливо розуміти, що ваша програма може копіювати навколо небажаних (неініціалізованих) даних скільки завгодно. Memcheck це зауважує і відслідковує дані, але не скаржиться. Скарга подається лише тоді, коли ваша програма намагається використати неініціалізовані дані таким чином, що може вплинути на зовнішньо-видиму поведінку вашої програми.

Від FAQ про Valgrind :

Що стосується нетерплячого повідомлення про копії неініціалізованих значень пам'яті, це було запропоновано кілька разів. На жаль, майже всі програми на законних підставах копіюють неініціалізовані значення пам'яті (оскільки компілятор працює на збереження вирівнювання). Тому Memcheck наразі не підтримує прагнення перевірити.


1
Яка мінімальна версія для використання цієї функції? Я використовую 3.3.0, і це, здається, не подобається варіант.
Роберт С. Барнс

8
@Robert: - трек-початок додано у валдрігді 3.4.0
mark4o

20

Це означає, що ви намагаєтесь роздрукувати / вивести значення, яке хоча б частково неініціалізоване. Чи можете ви звузити його, щоб ви точно знали, яке значення? Після цього простежте свій код, щоб побачити, де він ініціалізований. Швидше за все, ви побачите, що вона не повністю ініціалізована.

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

EDIT

Я бачу, ви знайшли проблему. Зверніть увагу, що valgrind спостерігає за умовним стрибком або рухом на основі неітіалізованих змінних. Це означає, що воно видасть попередження лише у тому випадку, якщо виконання програми буде змінено через неініціалізоване значення (наприклад, програма приймає іншу гілку в операторі if, наприклад). Оскільки фактична арифметика не передбачала умовного стрибка чи переміщення, valgrind не попередив вас про це. Натомість він поширював "неініціалізований" статус до результату заяви, яка його використовувала.

Може здатися протиінтуїтивним, що це не попереджає вас одразу, але, як зазначав mark4o , це робить це тому, що неініціалізовані значення звикають у C весь час (приклади: padding в структурах, realloc()виклик тощо), тому цих попереджень не буде дуже корисний через хибнопозитивну частоту.


Дякую. Я щойно з’ясував, що не так, але дивно, що valgrind не повідомив про неідентифіковану цінність, доки її не використали в іншому місці ..
kamziro

Це навмисно. Якщо просто копіювання або передача навколо неініціалізованих значень спричинило звіт про помилку, то ви отримуватимете їх весь час від набивання структур.
mark4o
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.