xác định chính xác bước nhảy hoặc di chuyển có điều kiện phụ thuộc vào giá trị chưa được khởi tạo (s) thông điệp valgrind


166

Vì vậy, tôi đã nhận được một số thông điệp giá trị chưa được xác định bí ẩn từ valgrind và nó khá bí ẩn về việc giá trị xấu bắt nguồn từ đâu.

Có vẻ như valgrind cho thấy nơi mà giá trị đơn vị cuối cùng được sử dụng, nhưng không phải là nguồn gốc của giá trị chưa được khởi tạo.

==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)

Có thể thấy, nó trở nên khá khó hiểu .. đặc biệt bởi vì khi nó được nói bởi Class :: MethodX, đôi khi nó chỉ thẳng vào việc phát sóng, v.v. Có lẽ điều này là do tối ưu hóa?

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

Chỉ cần như vậy. Có thiếu điều gì không? Cách tốt nhất để bắt các giá trị xấu mà không cần phải dùng đến công việc thám tử printf siêu dài là gì?

Cập nhật:

Tôi đã tìm ra những gì sai, nhưng điều kỳ lạ là, valgrind đã không báo cáo khi giá trị xấu được sử dụng lần đầu tiên. Nó được sử dụng trong hàm nhân:

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

Trong đó speedfac là một float đơn vị. Tuy nhiên, tại thời điểm đó nó không được báo cáo và cho đến khi giá trị được in mà tôi gặp lỗi .. Có cài đặt nào cho valgrind để thay đổi hành vi này không?

Câu trả lời:


230

Sử dụng tùy chọn valgrind --track-origins=yesđể theo dõi nguồn gốc của các giá trị chưa được khởi tạo. Điều này sẽ làm cho nó chậm hơn và chiếm nhiều bộ nhớ hơn, nhưng có thể rất hữu ích nếu bạn cần theo dõi nguồn gốc của một giá trị chưa được khởi tạo.

Cập nhật: Liên quan đến điểm tại đó giá trị chưa được khởi tạo được báo cáo, hướng dẫn sử dụng valgrind nêu rõ :

Điều quan trọng là phải hiểu rằng chương trình của bạn có thể sao chép xung quanh dữ liệu rác (chưa được khởi tạo) bao nhiêu tùy thích. Memcheck quan sát điều này và theo dõi dữ liệu, nhưng không phàn nàn. Khiếu nại chỉ được đưa ra khi chương trình của bạn cố gắng sử dụng dữ liệu chưa được khởi tạo theo cách có thể ảnh hưởng đến hành vi có thể nhìn thấy bên ngoài của chương trình của bạn.

Từ Câu hỏi thường gặp về Valgrind :

Đối với báo cáo háo hức về các bản sao của các giá trị bộ nhớ chưa được khởi tạo, điều này đã được đề xuất nhiều lần. Thật không may, gần như tất cả các chương trình sao chép một cách hợp pháp các giá trị bộ nhớ chưa được khởi tạo xung quanh (vì trình biên dịch pad cấu trúc để duy trì sự liên kết) và háo hức kiểm tra dẫn đến hàng trăm kết quả dương tính giả. Do đó Memcheck không hỗ trợ kiểm tra háo hức tại thời điểm này.


1
Phiên bản valgrind tối thiểu để sử dụng tính năng này là gì? Tôi đang sử dụng 3.3.0 và có vẻ như không thích tùy chọn này.
Robert S. Barnes

8
@Robert: --track-origins đã được thêm vào valgrind 3.4.0
mark4o

20

Điều này có nghĩa là bạn đang cố gắng in ra / xuất ra một giá trị ít nhất là chưa được khởi tạo một phần. Bạn có thể thu hẹp nó xuống để bạn biết chính xác đó là giá trị gì không? Sau đó, theo dõi mã của bạn để xem nó đang được khởi tạo ở đâu. Rất có thể, bạn sẽ thấy rằng nó không được khởi tạo hoàn toàn.

Nếu bạn cần thêm trợ giúp, việc đăng các phần có liên quan của mã nguồn có thể cho phép ai đó cung cấp thêm hướng dẫn.

BIÊN TẬP

Tôi thấy bạn đã tìm thấy vấn đề. Lưu ý rằng đồng hồ valgrind cho nhảy có điều kiện hoặc di chuyển dựa trên các biến đơn vị. Điều đó có nghĩa là nó sẽ chỉ đưa ra cảnh báo nếu việc thực thi chương trình bị thay đổi do giá trị chưa được khởi tạo (ví dụ: chương trình lấy một nhánh khác trong một câu lệnh if chẳng hạn). Vì số học thực tế không liên quan đến bước nhảy hoặc di chuyển có điều kiện, valgrind không cảnh báo bạn về điều đó. Thay vào đó, nó tuyên truyền trạng thái "chưa được khởi tạo" đến kết quả của câu lệnh đã sử dụng nó.

Có vẻ như không trực quan rằng nó không cảnh báo bạn ngay lập tức, nhưng như mark4o đã chỉ ra, nó làm điều này bởi vì các giá trị chưa được khởi tạo được sử dụng trong C mọi lúc (ví dụ: đệm trong cấu trúc, realloc()cuộc gọi, v.v.) vì vậy những cảnh báo đó sẽ không được rất hữu ích do tần số dương sai.


Cảm ơn. Tôi mới phát hiện ra điều gì sai, nhưng điều kỳ lạ là, valgrind đã không báo cáo điều giá trị được đơn vị hóa cho đến khi nó được sử dụng ở nơi khác ..
kamziro

Đó là cố ý. Nếu chỉ sao chép hoặc chuyển xung quanh các giá trị chưa được khởi tạo gây ra báo cáo lỗi thì bạn sẽ nhận được chúng mọi lúc từ việc đệm trong các cấu trúc.
mark4o
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.