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


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.