“조건부 점프 또는 이동은 초기화되지 않은 값에 따라 다릅니다.”


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 형사 작업에 의존하지 않고 나쁜 가치를 포착하는 가장 좋은 방법은 무엇입니까?

최신 정보:

나는 무엇이 잘못되었는지 알았지 만, 이상한 점은, valgrind는 나쁜 가치가 처음 사용될 때 그것을보고하지 않았다는 것입니다. 곱셈 함수에서 사용되었습니다.

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

speedfac은 단일화 된 플로트였습니다. 그러나 그 당시에는 오류가 발생하여 값이 인쇄 될 때까지보고되지 않았습니다. valgrind가이 동작을 변경하기위한 설정이 있습니까?

답변:


230

valgrind 옵션 --track-origins=yes을 사용하여 초기화되지 않은 값의 원점을 추적하십시오. 이렇게하면 속도가 느려지고 더 많은 메모리가 필요하지만 초기화되지 않은 값의 출처를 추적해야하는 경우 매우 유용 할 수 있습니다.

업데이트 : 초기화되지 않은 값이보고되는 시점과 관련 하여 valgrind 수동 상태는 다음과 같습니다.

프로그램은 정크 데이터 (초기화되지 않은) 데이터를 원하는만큼 복사 할 수 있음을 이해하는 것이 중요합니다. Memcheck는이를 관찰하고 데이터를 추적하지만 불평하지는 않습니다. 불만은 프로그램이 외부에서 볼 수있는 행동에 영향을 줄 수있는 방식으로 초기화되지 않은 데이터를 사용하려고 할 때만 발행됩니다.

로부터 Valgrind의 자주 묻는 질문 :

초기화되지 않은 메모리 값의 복사본을 열망 적으로보고하는 경우 여러 번 제안되었습니다. 불행히도, 거의 모든 프로그램은 초기화되지 않은 메모리 값을 합법적으로 복사하고 (컴파일러는 정렬을 유지하기 위해 구조체를 패드로 묶기 때문에) 수백 가지 오탐을 유발합니다. 따라서 Memcheck는 현재 열성적인 검사를 지원하지 않습니다.


1
이 기능을 사용하기위한 최소 valgrind 버전은 무엇입니까? 3.3.0을 사용하고 있는데 옵션이 마음에 들지 않습니다.
Robert S. Barnes

8
@Robert : --track-origins이
valgrind

20

이것은 적어도 부분적으로 초기화되지 않은 값을 인쇄 / 출력하려고한다는 것을 의미합니다. 정확히 어떤 값인지 알 수 있도록 범위를 좁힐 수 있습니까? 그런 다음 코드를 추적하여 초기화되는 위치를 확인하십시오. 기회가 완전히 초기화되지 않았 음을 알 수 있습니다.

도움이 더 필요한 경우 소스 코드의 관련 섹션을 게시하면 더 많은 지침을 제공 할 수 있습니다.

편집하다

문제를 발견 한 것으로 보입니다. valgrind는 단일화 된 변수를 기준으로 조건부 점프 또는 이동을 감시 합니다. 즉, 초기화되지 않은 값으로 인해 프로그램 실행이 변경되는 경우에만 경고가 표시됩니다 (예 : 프로그램이 if 문에서 다른 분기를 수행함). 실제 산술에는 조건부 점프 나 이동이 포함되지 않았기 때문에 valgrind는 이에 대해 경고하지 않았습니다. 대신, "초기화되지 않은"상태를 사용한 명령문의 결과로 전파했습니다.

즉시 경고하지는 않지만 반 직관적 인 것처럼 보일 수 있지만 mark4o가 지적했듯이 초기화되지 않은 값이 C에서 항상 사용되므로 (예 : 구조의 패딩, realloc()호출 등) 이러한 경고가 표시되지 않습니다 위양성 빈도로 인해 매우 유용합니다.


감사. 나는 단지 무엇이 잘못되었는지 알아 냈지만, 이상한 점은,
valgrind가

그것은 의도적입니다. 초기화되지 않은 값을 복사하거나 전달하면 오류 보고서가 발생하면 구조의 패딩에서 항상 값을 얻을 수 있습니다.
mark4o
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.