การระบุ“ การกระโดดหรือย้ายตามเงื่อนไขขึ้นอยู่กับข้อความที่ไม่ได้เตรียมค่า” valgrind


166

ดังนั้นฉันจึงได้รับข้อความที่ไม่ได้กำหนดค่าเริ่มต้นจาก valgrind และมันค่อนข้างลึกลับซึ่งเป็นที่มาของค่าที่ไม่ดี

ดูเหมือนว่า valgrind แสดงให้เห็นถึงสถานที่ที่มีการใช้ค่า unitialised แต่ไม่ใช่ที่มาของค่าเริ่มต้น

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

สำหรับการรายงานสำเนาของค่าหน่วยความจำที่ไม่ได้เตรียมไว้ก็มีการแนะนำหลาย ๆ ครั้ง น่าเสียดายที่เกือบทุกโปรแกรมถูกต้องตามกฎหมายคัดลอกค่าหน่วยความจำที่ไม่ได้กำหนดค่าเริ่มต้นรอบ ๆ (เพราะคอมไพเลอร์ pad structs เพื่อรักษาการจัดตำแหน่ง) และการตรวจสอบความกระตือรือร้นนำไปสู่การบวกปลอมหลายร้อยรายการ ดังนั้น Memcheck ไม่สนับสนุนการตรวจสอบความกระตือรือร้นในเวลานี้


1
รุ่น valgrind ขั้นต่ำสุดที่ใช้คุณลักษณะนี้คืออะไร ฉันใช้ 3.3.0 และดูเหมือนจะไม่ชอบตัวเลือก
Robert S. Barnes

8
@ Robert: - track-origins ถูกเพิ่มใน valgrind 3.4.0
mark4o

20

สิ่งนี้หมายความว่าคุณกำลังพยายามที่จะพิมพ์ / ส่งออกค่าซึ่งเป็นอย่างน้อยบางส่วนเริ่มต้น คุณสามารถ จำกัด ให้แคบลงเพื่อที่คุณจะได้รู้ว่ามูลค่านั้นคืออะไร? หลังจากนั้นติดตามรหัสของคุณเพื่อดูว่ามันถูกเริ่มต้น โอกาสที่คุณจะเห็นว่ามันไม่ได้เริ่มต้นอย่างเต็มที่

หากคุณต้องการความช่วยเหลือเพิ่มเติมการโพสต์ส่วนที่เกี่ยวข้องของซอร์สโค้ดอาจอนุญาตให้บางคนเสนอคำแนะนำเพิ่มเติม

แก้ไข

ฉันเห็นว่าคุณพบปัญหาแล้ว โปรดทราบว่า valgrind เฝ้าดูการกระโดดหรือย้ายแบบมีเงื่อนไขตามตัวแปรหน่วย สิ่งที่หมายถึงคือมันจะให้คำเตือนเฉพาะถ้าการดำเนินการของโปรแกรมมีการเปลี่ยนแปลงเนื่องจากค่าเริ่มต้น (เช่นโปรแกรมใช้สาขาที่แตกต่างกันในคำสั่ง if ตัวอย่าง) เนื่องจากเลขคณิตจริงไม่เกี่ยวข้องกับการกระโดดหรือการย้ายตามเงื่อนไข valgrind จึงไม่เตือนคุณ แต่จะเผยแพร่สถานะ "ไม่กำหนดค่าเริ่มต้น" แทนผลลัพธ์ของคำสั่งที่ใช้

อาจดูเหมือนเป็นเรื่องธรรมดาที่จะไม่เตือนคุณทันที แต่ในขณะที่mark4oชี้ให้เห็นมันเป็นเช่นนี้เพราะค่าที่ไม่ได้ถูกกำหนดให้ใช้ใน C ตลอดเวลา (ตัวอย่าง: การขยายในโครงสร้างการrealloc()โทร ฯลฯ ) ดังนั้นคำเตือนเหล่านั้นจะไม่ มีประโยชน์มากเนื่องจากมีความถี่บวกที่ผิดพลาด


ขอบคุณ ฉันเพิ่งค้นพบสิ่งที่ผิด แต่สิ่งที่แปลกคือ valgrind ไม่ได้รายงานสิ่งที่เป็นค่าจนกว่าจะถูกนำไปใช้ที่อื่น ..
kamziro

นั่นคือเจตนา หากเพียงแค่การคัดลอกหรือส่งผ่านค่าที่ไม่ได้กำหนดค่าเริ่มต้นก่อให้เกิดรายงานข้อผิดพลาดคุณจะได้รับพวกเขาตลอดเวลาจากการใส่ในโครงสร้าง
mark4o
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.