การดีบักหน่วยความจำเสียหาย


23

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

เมื่อเดือนที่แล้วฉันได้เขียนรหัสเซิร์ฟเวอร์ (mmorpg) ที่ค่อนข้างเก่าเพื่อให้ทันสมัยและง่ายต่อการขยาย / ดัดแปลง ฉันเริ่มต้นด้วยส่วนเครือข่ายและใช้ห้องสมุดบุคคลที่สาม (libevent) เพื่อจัดการสิ่งต่าง ๆ สำหรับฉัน ด้วยการเปลี่ยนแฟคตอริ่งและการเปลี่ยนรหัสใหม่ฉันได้แนะนำคอร์รัปชั่นหน่วยความจำบางแห่งและฉันพยายามดิ้นรนหาว่ามันเกิดอะไรขึ้น

ฉันดูเหมือนจะไม่สามารถทำซ้ำได้อย่างน่าเชื่อถือบนสภาพแวดล้อมการพัฒนา / การทดสอบของฉันแม้ว่าจะใช้บอตแบบดั้งเดิมเพื่อจำลองการโหลดบางอย่างฉันจะไม่เกิดข้อผิดพลาดอีกต่อไป (ฉันแก้ไขปัญหาเรื่องเสรีภาพซึ่งทำให้บางสิ่ง)

ฉันได้ลองแล้ว:

Valgrinding นรกออกมาจากมัน - ไม่มีการเขียนที่ไม่ถูกต้องจนกว่าสิ่งที่จะเกิดปัญหา (ซึ่งอาจใช้เวลา 1+ วันในการผลิต .. หรือเพียงหนึ่งชั่วโมง) ซึ่งทำให้ฉันงงงันจริง ๆ ในบางครั้งมันจะเข้าถึงหน่วยความจำที่ไม่ถูกต้อง โอกาส? (มีวิธีการ "กระจาย" ช่วงที่อยู่หรือไม่)

เครื่องมือวิเคราะห์รหัส ได้แก่ ความครอบคลุมและ cppcheck ในขณะที่พวกเขาชี้ให้เห็นถึง .. ความร้ายกาจและคดีขอบในรหัสไม่มีอะไรร้ายแรง

บันทึกกระบวนการจนกว่ามันจะล้มเหลวด้วย gdb (ผ่าน undodb) แล้วทำงานย้อนกลับ นี้ / ฟัง / ชอบมันควรจะเป็นไปได้ แต่ฉันท้าย crashing gdb โดยใช้คุณสมบัติ auto-complete หรือฉันท้ายในโครงสร้าง libevent ภายในที่ฉันหลงทางเนื่องจากมีสาขาที่เป็นไปได้มากเกินไป บน). ฉันเดาว่าคงจะดีถ้าฉันเห็นว่าตัวชี้เป็นของ / ตำแหน่งที่จัดสรรไว้ซึ่งจะกำจัดปัญหาการแตกแขนงส่วนใหญ่ออกไป ฉันไม่สามารถเรียกใช้ valgrind ด้วย undodb ได้และฉันบันทึก gdb ปกติช้ามาก (ถ้าใช้งานร่วมกับ valgrind ได้)

ตรวจสอบรหัส! ด้วยตัวเอง (ถี่ถ้วน) และให้เพื่อนบางคนดูรหัสของฉันแม้ว่าฉันจะสงสัยว่ามันละเอียดเพียงพอ ฉันกำลังคิดว่าอาจจ้างนักพัฒนาเพื่อทำการตรวจสอบรหัส / ตรวจแก้จุดบกพร่องกับฉัน แต่ฉันไม่สามารถใส่เงินมากเกินไปและฉันก็ไม่รู้จะหาคนที่ยินดีทำงานน้อย - ไม่มีเงินถ้าเขาไม่พบปัญหาหรือใครมีคุณสมบัติเลย

ฉันควรทราบด้วย: ฉันมักจะได้รับ backtraces ที่สอดคล้องกัน มีบางสถานที่ที่เกิดความผิดพลาดส่วนใหญ่เกี่ยวข้องกับคลาสซ็อกเก็ตเสียหายอย่างใด มันเป็นตัวชี้ที่ไม่ถูกต้องชี้ไปที่สิ่งที่ไม่ใช่ซ็อกเก็ตหรือคลาสซ็อกเก็ตตัวเองกลายเป็นเขียนทับ (บางส่วน?) ด้วยซึ่งพูดพล่อยๆ แม้ว่าฉันจะสงสัยว่ามันทำงานล้มเหลวที่นั่นมากที่สุดเนื่องจากเป็นหนึ่งในชิ้นส่วนที่ใช้บ่อยที่สุดดังนั้นจึงเป็นหน่วยความจำที่เสียหายครั้งแรกที่ถูกนำมาใช้

โดยรวมแล้วปัญหานี้ทำให้ฉันยุ่งเป็นเวลาเกือบ 2 เดือน (เปิดและปิดโครงการงานอดิเรกมากขึ้น) และทำให้ฉันหงุดหงิดจนถึงจุดที่ฉันกลายเป็นคนไม่พอใจ IRL และคิดจะยอมแพ้ ฉันไม่สามารถคิดเกี่ยวกับสิ่งอื่นที่ฉันควรทำเพื่อค้นหาปัญหา

มีเทคนิคใดที่มีประโยชน์ที่ฉันพลาดไปหรือไม่? คุณจัดการกับสิ่งนั้นได้อย่างไร (มันเป็นเรื่องธรรมดาไม่ได้เพราะไม่มีข้อมูลมากมายเกี่ยวกับเรื่องนี้ .. หรือฉันแค่ตาบอดจริงๆ?)

แก้ไข:

รายละเอียดบางอย่างในกรณีที่มันสำคัญ:

ใช้ c ++ (11) ผ่าน gcc 4.7 (เวอร์ชั่นที่จัดทำโดย debian wheezy)

codebase อยู่ที่ประมาณ 150k บรรทัด

แก้ไขเพื่อตอบสนองต่อ david.pfx โพสต์: (ขออภัยสำหรับการตอบสนองช้า)

คุณเก็บบันทึกข้อผิดพลาดอย่างระมัดระวังเพื่อค้นหารูปแบบหรือไม่

ใช่ฉันยังคงมีความผิดพลาดเกิดขึ้นเมื่อไม่นานมานี้

สถานที่บางแห่งมีความคล้ายคลึงกันจริงหรือ อย่างไหนล่ะ, แบบไหนล่ะ?

ในเวอร์ชั่นล่าสุด (ดูเหมือนว่าจะเปลี่ยนแปลงเมื่อใดก็ตามที่ฉันเพิ่ม / ลบรหัสหรือเปลี่ยนแปลงโครงสร้างที่เกี่ยวข้อง) มันจะติดอยู่ในวิธีจับเวลารายการ โดยทั่วไปรายการมีเวลาเฉพาะหลังจากที่มันหมดอายุและมันจะส่งข้อมูลที่ปรับปรุงให้กับลูกค้า ตัวชี้ซ็อกเก็ตที่ไม่ถูกต้องจะอยู่ใน (ยังคงใช้ได้เท่าที่ฉันสามารถบอกได้) คลาสผู้เล่นซึ่งส่วนใหญ่เกี่ยวข้องกับสิ่งนั้น ฉันยังประสบปัญหาการขัดข้องในช่วงการล้างข้อมูลหลังจากการปิดปกติซึ่งเป็นการทำลายคลาสสแตติกทั้งหมดที่ไม่ได้ถูกทำลายอย่างชัดเจน ( __run_exit_handlersใน backtrace) ส่วนใหญ่เกี่ยวข้องกับstd::mapชั้นเรียนโดยคาดเดาว่าเป็นเพียงสิ่งแรกที่เกิดขึ้น

ข้อมูลที่เสียหายมีลักษณะอย่างไร ศูนย์? ascii? รูปแบบ?

ฉันยังไม่พบรูปแบบใดเลยดูเหมือนว่าจะสุ่มให้ฉันบ้าง มันยากที่จะบอกเพราะฉันไม่รู้ว่าการคอร์รัปชั่นเริ่มต้นที่ไหน

มันเกี่ยวข้องกับกองเหรอ?

มันเกี่ยวข้องกับกองทั้งหมด (ฉันเปิดการใช้งาน stack Guard ของ gcc และนั่นไม่ได้จับอะไรเลย)

ความเสียหายเกิดขึ้นหลังจากfree()?

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

มีสิ่งที่แตกต่างเกี่ยวกับปริมาณการใช้เครือข่าย (ขนาดบัฟเฟอร์รอบการกู้คืน) หรือไม่

การรับส่งข้อมูลเครือข่ายประกอบด้วยข้อมูลดิบ ดังนั้นอาร์เรย์ char (u) intX_t หรือโครงสร้างแพ็กเกจ (เพื่อลบการขยาย) สำหรับสิ่งที่ซับซ้อนยิ่งขึ้นแต่ละแพ็กเก็ตมีส่วนหัวที่ประกอบด้วย id และขนาดแพ็คเก็ตของตัวเองซึ่งถูกตรวจสอบกับขนาดที่คาดหวัง พวกมันมีขนาดประมาณ 10-60bytes พร้อมแพ็กเก็ตที่ใหญ่ที่สุด ('บูทอัพ' ภายในซึ่งถูกเปิดใช้ครั้งเดียวเมื่อเริ่มต้น) มีขนาดไม่กี่ Mb

การผลิตจำนวนมากและยืนยัน ชนเร็วและคาดการณ์ได้ก่อนที่ความเสียหายจะแพร่กระจาย

ฉันเคยมีปัญหาเกี่ยวกับการstd::mapทุจริตแต่ละเอนทิตีมีแผนที่ว่า "ดู" แต่ละเอนทิตีที่สามารถดูได้และในทางกลับกันก็อยู่ในนั้น ฉันเพิ่มบัฟเฟอร์ 200byte ทั้งด้านหน้าและหลังเติมด้วย 0x33 และตรวจสอบก่อนการเข้าถึงแต่ละครั้ง การคอร์รัปชั่นหายไปอย่างน่าอัศจรรย์ฉันต้องย้ายบางสิ่งไปรอบ ๆ ซึ่งทำให้สิ่งอื่นเสียหาย

การบันทึกเชิงกลยุทธ์เพื่อให้คุณทราบอย่างถูกต้องว่าเกิดอะไรขึ้นก่อนหน้านี้ เพิ่มการบันทึกเมื่อคุณเข้าใกล้คำตอบมากขึ้น

มันทำงาน .. เพื่อขยาย

คุณสามารถบันทึกสถานะและรีสตาร์ทอัตโนมัติได้หรือไม่? ฉันสามารถนึกถึงซอฟต์แวร์การผลิตสองสามชิ้นที่ทำเช่นนั้น

ฉันค่อนข้างทำอย่างนั้น ซอฟต์แวร์ประกอบด้วยกระบวนการ "แคช" หลักและบางส่วนของผู้ปฏิบัติงานอื่น ๆ ที่เข้าถึงแคชเพื่อรับและบันทึกข้อมูล ดังนั้นต่อความผิดพลาดฉันไม่สูญเสียความคืบหน้ามากนัก แต่ก็ยังตัดการเชื่อมต่อผู้ใช้ทั้งหมดและอื่น ๆ มันไม่ใช่ทางออกแน่นอน

ภาวะพร้อมกัน: เกลียว, สภาพการแข่งขัน, ฯลฯ

มีเธรด mysql ที่จะทำแบบสอบถาม "async" นั่นคือทั้งหมดที่มิได้ถูกแตะต้องและเพียงแบ่งปันข้อมูลไปยังชั้นฐานข้อมูลผ่านฟังก์ชั่นที่มีการล็อคทั้งหมด

ขัดจังหวะ

มีตัวจับเวลาขัดจังหวะเพื่อป้องกันไม่ให้ล็อคที่เพียงแค่ยกเลิกถ้ามันไม่ครบรอบ 30 วินาทีรหัสที่ควรจะปลอดภัยแม้ว่า:

if (!tics) {
    abort();
} else
    tics = 0;

สำบัดสำนวนvolatile int tics = 0;ซึ่งเพิ่มขึ้นในแต่ละครั้งที่รอบเสร็จสมบูรณ์ รหัสเก่าเกินไป

events / callbacks / exception: ทำให้เกิดคอร์รัปต์หรือสแต็กอย่างคาดไม่ถึง

มีการใช้การโทรกลับจำนวนมาก (I / O เครือข่าย async, ตัวจับเวลา) แต่พวกเขาไม่ควรทำอะไรที่ไม่ดี

ข้อมูลที่ผิดปกติ: ข้อมูล / เวลา / สถานะที่ผิดปกติ

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

การพึ่งพากระบวนการภายนอกแบบอะซิงโครนัส

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


7
น่าเศร้านี่เป็นเรื่องธรรมดาในแอป C ++ ที่ไม่สำคัญ หากคุณใช้การควบคุมซอร์สการทดสอบชุดการเปลี่ยนแปลงต่าง ๆ เพื่อ จำกัด การเปลี่ยนแปลงรหัสที่ทำให้เกิดปัญหาสามารถช่วยได้ แต่อาจไม่เป็นไปได้ในกรณีนี้
Telastyn

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

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

เริ่มต้นด้วยการแสดงความคิดเห็นส่วนของรหัสจนกว่าคุณจะไม่ได้รับความผิดพลาดอีกต่อไป
cpp81

1
นอกจาก Valgrind, Coverity และ cppcheck แล้วคุณควรเพิ่ม Asan และ UBsan ในระบอบการทดสอบของคุณ หากรหัสของคุณคือ corss-platofrm ให้เพิ่ม Enterprise Analysis ( /analyze) และMicrosoft Malloc และ Scribble guards ของ Apple เช่นกัน คุณควรใช้คอมไพเลอร์ให้ได้มากที่สุดโดยใช้มาตรฐานให้มากที่สุดเท่าที่จะทำได้เนื่องจากคำเตือนของคอมไพเลอร์เป็นการวินิจฉัยและจะดีขึ้นเมื่อเวลาผ่านไป ไม่มีกระสุนเงินและขนาดเดียวไม่พอดีทั้งหมด ยิ่งคุณใช้เครื่องมือและคอมไพเลอร์มากเท่าไหร่ความครอบคลุมที่สมบูรณ์ยิ่งขึ้นเนื่องจากแต่ละเครื่องมือมีจุดแข็งและจุดอ่อน

คำตอบ:


21

มันเป็นปัญหาที่ท้าทาย แต่ฉันคิดว่าจะมีเงื่อนงำมากมายที่จะพบได้ในการล่มที่คุณได้เห็นแล้ว

  • คุณเก็บบันทึกข้อผิดพลาดอย่างระมัดระวังเพื่อค้นหารูปแบบหรือไม่
  • สถานที่บางแห่งมีความคล้ายคลึงกันจริงหรือ อย่างไหนล่ะ, แบบไหนล่ะ?
  • ข้อมูลที่เสียหายมีลักษณะอย่างไร ศูนย์? ascii? รูปแบบ?
  • มีหลายเธรดที่เกี่ยวข้องหรือไม่ มันอาจเป็นสภาพการแข่งขันหรือไม่?
  • มันเกี่ยวข้องกับกองเหรอ? ความเสียหายเกิดขึ้นหลังจากฟรี ()?
  • มันเกี่ยวข้องกับสแต็กหรือไม่ สแต็กเกิดความเสียหายหรือไม่
  • การอ้างอิงที่เป็นไปได้นั้นเป็นไปได้หรือไม่? ค่าข้อมูลที่เปลี่ยนแปลงอย่างลึกลับ?
  • มีสิ่งที่แตกต่างเกี่ยวกับปริมาณการใช้เครือข่าย (ขนาดบัฟเฟอร์รอบการกู้คืน) หรือไม่

สิ่งที่เราใช้ในสถานการณ์ที่คล้ายคลึงกัน

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

คุณสามารถบันทึกสถานะและรีสตาร์ทอัตโนมัติได้หรือไม่? ฉันสามารถนึกถึงซอฟต์แวร์การผลิตสองสามชิ้นที่ทำเช่นนั้น

อย่าลังเลที่จะเพิ่มรายละเอียดถ้าเราสามารถช่วยเหลือได้ทั้งหมด


ฉันสามารถเพิ่มข้อบกพร่องที่ไม่สามารถระบุได้อย่างจริงจังเช่นนี้ไม่ใช่สิ่งที่พบได้ทั่วไปและมีหลายสิ่งที่สามารถทำให้พวกเขาไม่ได้ พวกเขารวมถึง:

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

นี่คือส่วนของรหัสที่จะมุ่งเน้น


+1 คำแนะนำที่ดีทั้งหมดโดยเฉพาะอย่างยิ่งการยืนยันผู้คุมและการบันทึก
andy256

ฉันแก้ไขข้อมูลเพิ่มเติมในคำถามเพื่อตอบคำตอบของคุณ นั่นทำให้ฉันนึกถึงความผิดพลาดเมื่อปิดตัวลงซึ่งฉันยังไม่ได้ดูอย่างกว้างขวางดังนั้นฉันจะไปที่ตอนนี้ฉันเดา
Robin

5

ใช้เวอร์ชันการดีบักของ malloc / free ห่อและเขียนของคุณเองหากจำเป็น ความสนุกสนานมากมาย!

รุ่นที่ฉันใช้เพิ่มไบต์ยามก่อนและหลังการจัดสรรทุกครั้งและรักษารายการ "จัดสรร" ที่จะตรวจสอบชิ้นอิสระที่ว่าง สิ่งนี้จะจับบัฟเฟอร์ที่มากเกินไปและข้อผิดพลาด "ฟรี" หลายอัน

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


1
Valgrind ควรตรวจจับข้อมูลอิสระสองเท่า / ใช้ข้อมูล free'd อย่างนั้นใช่ไหม?
Robin

การเขียน overloads ชนิดนี้สำหรับใหม่ / ลบได้ช่วยฉันค้นหาปัญหาหน่วยความจำเสียหายมากมาย โดยเฉพาะอย่างยิ่งไบต์ยามที่ได้รับการตรวจสอบในการลบและทำให้โปรแกรมจุดพักซึ่งทำให้ฉันโดยอัตโนมัติในการดีบัก
Emily L.

3

ในการถอดความสิ่งที่คุณพูดในคำถามคุณไม่สามารถให้คำตอบที่ชัดเจนได้ สิ่งที่ดีที่สุดที่เราสามารถทำได้คือให้คำแนะนำในสิ่งต่าง ๆ เพื่อค้นหาและเครื่องมือและเทคนิค

ข้อเสนอแนะบางอย่างจะดูไร้เดียงสาส่วนข้อเสนออื่น ๆ อาจใช้งานได้ดีกว่า แต่หวังว่าจะมีข้อเสนอแนะหนึ่งข้อสำหรับคุณ ฉันต้องบอกว่าคำตอบโดย david.pfxมีคำแนะนำและข้อเสนอแนะที่ถูกต้อง

จากอาการ

  • สำหรับฉันมันฟังดูเหมือนบัฟเฟอร์ล้น

  • ปัญหาที่เกี่ยวข้องคือการใช้ข้อมูลซ็อกเก็ต unvalidated เป็นตัวห้อยหรือคีย์ ฯลฯ

  • เป็นไปได้หรือไม่ว่าคุณกำลังใช้ตัวแปรโกลบอลบางแห่งหรือมีโกลบอลและโลคัลที่มีชื่อเดียวกันหรืออย่างใดอย่างหนึ่งข้อมูลของผู้เล่นคนหนึ่งรบกวนกับอีก?

เช่นเดียวกับข้อบกพร่องมากมายคุณอาจจะทำให้สมมติฐานไม่ถูกต้อง หรืออาจมากกว่าหนึ่ง ข้อผิดพลาดในการติดต่อหลายครั้งยากที่จะตรวจจับ

  • ตัวแปรทุกตัวมีคำอธิบายหรือไม่? และคุณสามารถกำหนดการยืนยันความถูกต้องได้หรือไม่?
    หากไม่เพิ่มให้สแกนรหัสเพื่อดูว่าแต่ละตัวแปรใช้งานได้อย่างถูกต้องหรือไม่ เพิ่มการยืนยันที่ใดก็ตามที่เหมาะสม

  • ข้อเสนอแนะในการเพิ่มการยืนยันล็อตเป็นสิ่งที่ดี: สถานที่แรกที่ใส่ไว้ในทุกจุดเข้าใช้งาน ตรวจสอบข้อโต้แย้งและสถานะโกลบอลที่เกี่ยวข้อง

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

หลายคนมีรหัสการเข้าสู่ระบบของตนเอง ฉันมีระบบบันทึกแมโคร C เก่าและอาจเป็นรุ่น C ++ ...


3

ทุกสิ่งที่ถูกกล่าวถึงในคำตอบอื่น ๆ นั้นมีความเกี่ยวข้องมาก สิ่งหนึ่งที่สำคัญที่กล่าวถึงบางส่วนโดย ddyer คือการห่อ malloc / ฟรีมีประโยชน์ เขากล่าวถึงบางอย่าง แต่ฉันต้องการเพิ่มเครื่องมือแก้ไขข้อบกพร่องที่สำคัญมากไปที่: คุณสามารถบันทึก malloc / ฟรีลงในไฟล์ภายนอกพร้อมกับ callstack สองสามบรรทัด (หรือ callstack เต็มถ้าคุณสนใจ) ถ้าคุณระวังคุณสามารถทำให้มันเร็วและใช้งานได้ง่ายถ้าพูดถึงมัน

จากสิ่งที่คุณอธิบายการคาดเดาส่วนตัวของฉันคือคุณอาจใช้การอ้างอิงไปยังตัวชี้ที่ไหนสักแห่งเพื่อปลดปล่อยความจำ หากคุณสามารถสรุปช่วงขนาดที่จะตรวจสอบด้วยเทคนิคด้านบนคุณควรจะสามารถ จำกัด การบันทึกได้อย่างมาก มิฉะนั้นเมื่อคุณพบว่าหน่วยความจำใดเสียหายคุณสามารถเข้าใจรูปแบบ malloc / free ที่นำไปสู่ความง่ายดายจากบันทึก

สิ่งสำคัญคือเมื่อคุณพูดถึงการเปลี่ยนเค้าโครงหน่วยความจำอาจซ่อนปัญหา ดังนั้นจึงเป็นเรื่องสำคัญมากที่การบันทึกของคุณจะไม่มีการจัดสรร (ถ้าคุณทำได้!) หรือน้อยที่สุดเท่าที่จะทำได้ สิ่งนี้จะช่วยในการทำซ้ำหากเกี่ยวข้องกับหน่วยความจำ นอกจากนี้ยังจะช่วยในกรณีที่เร็วที่สุดหากปัญหาเกี่ยวข้องกับการทำเกลียว

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

เป็นทางเลือกสุดท้ายคุณยังสามารถสร้างตัวจัดสรรแบบกำหนดเองที่คุณจัดสรรอย่างน้อย 2 หน้าสำหรับการจัดสรรทุกครั้งและยกเลิกการทำแผนที่เมื่อคุณว่าง (จัดตำแหน่งการจัดสรรให้กับขอบเขตหน้าจัดสรรหน้าก่อนและทำเครื่องหมายว่าไม่สามารถเข้าถึงหรือจัดตำแหน่ง จัดสรรที่ส่วนท้ายของหน้าและจัดสรรหน้าหลังและทำเครื่องหมายว่าไม่สามารถเข้าถึงได้) ตรวจสอบให้แน่ใจว่าไม่ได้ใช้ที่อยู่หน่วยความจำเสมือนเหล่านั้นซ้ำเพื่อการจัดสรรใหม่อย่างน้อยในบางครั้ง สิ่งนี้บอกเป็นนัยว่าคุณจะต้องจัดการหน่วยความจำเสมือนด้วยตัวคุณเอง (จองและใช้งานได้ตามที่คุณต้องการ) โปรดทราบว่านี่จะลดประสิทธิภาพของคุณและอาจใช้หน่วยความจำเสมือนจำนวนมากขึ้นอยู่กับจำนวนการจัดสรรที่คุณป้อน เพื่อลดสิ่งนี้จะช่วยถ้าคุณสามารถรันใน 64 บิตและ / หรือลดช่วงของการจัดสรรที่ต้องการสิ่งนี้ (ขึ้นอยู่กับขนาด) Valgrind อาจทำสิ่งนี้ได้เป็นอย่างดี แต่อาจช้าเกินไปสำหรับคุณในการตรวจสอบปัญหา การทำเช่นนี้เพียงไม่กี่ขนาดหรือวัตถุ (ถ้าคุณรู้ว่าคุณสามารถใช้ตัวจัดสรรพิเศษเฉพาะสำหรับวัตถุเหล่านั้น) จะช่วยให้มั่นใจได้ว่าประสิทธิภาพจะได้รับผลกระทบน้อยที่สุด


0

ลองตั้งค่าจุดเฝ้าดูที่อยู่หน่วยความจำที่เกิดปัญหา GDB จะแตกที่คำสั่งที่ทำให้เกิดหน่วยความจำที่ไม่ถูกต้อง จากนั้นด้วยการติดตามย้อนกลับคุณจะเห็นรหัสของคุณที่ทำให้เกิดความเสียหาย สิ่งนี้อาจไม่ใช่แหล่งที่มาของความเสียหาย แต่การทำซ้ำจุดเฝ้าดูการทุจริตแต่ละครั้งอาจนำไปสู่สาเหตุของปัญหา

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

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