โปรแกรมจะขัดข้องเมื่อสร้างรุ่นเท่านั้น - จะแก้ไขข้อบกพร่องได้อย่างไร


98

ฉันมีปัญหาประเภท "Schroedinger's Cat" ที่นี่ - โปรแกรมของฉัน (จริงๆแล้วเป็นชุดทดสอบสำหรับโปรแกรมของฉัน แต่โปรแกรมของฉัน) ขัดข้อง แต่เฉพาะเมื่อสร้างในโหมดรีลีสและเมื่อเรียกใช้จากบรรทัดคำสั่งเท่านั้น . ด้วยการดีบักของมนุษย์ถ้ำ (เช่นข้อความ printf () ที่น่ารังเกียจทั่วทุกที่) ฉันได้กำหนดวิธีการทดสอบที่โค้ดขัดข้องแม้ว่าจะเกิดข้อผิดพลาดจริงในตัวทำลายบางตัวเนื่องจากข้อความติดตามล่าสุดที่ฉันเห็นอยู่ใน ผู้ทำลายล้างอื่น ๆ ที่ดำเนินการอย่างหมดจด

เมื่อฉันพยายามเรียกใช้โปรแกรมนี้ภายใน Visual Studio มันไม่ผิดพลาด เช่นเดียวกันเมื่อเปิดตัวจาก WinDbg.exe ข้อขัดข้องจะเกิดขึ้นเมื่อเรียกใช้งานจากบรรทัดคำสั่งเท่านั้น สิ่งนี้เกิดขึ้นภายใต้ Windows Vista btw และน่าเสียดายที่ฉันไม่สามารถเข้าถึงเครื่อง XP ได้ในขณะนี้เพื่อทดสอบ

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

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


คุณสามารถให้ตัวอย่างวิธีการทดสอบนั้นได้หรือไม่?
Akalenuk

ไม่ต้องขอโทษรหัสซับซ้อนเกินไปที่จะวางที่นี่ได้อย่างง่ายดายและอย่างที่ฉันพูดถึงมันไม่ได้เกิดขึ้นในวิธีการทดสอบ แต่เป็นตัวทำลายในภายหลัง ไม่มีตัวชี้ที่ไม่ได้เริ่มต้นหรืออะไรแบบนั้นในวิธีนี้
Nik Reiman

3
คำตอบส่วนใหญ่เกินคาดเดาเล็กน้อย มีเทคนิคทั่วไปบางประการในการวิเคราะห์รุ่นที่หยุดทำงานโดยไม่ต้องติดดีบักเกอร์: stackoverflow.com/a/18513077/214777?stw=2
Sebastian

คำตอบ:


130

ใน 100% ของกรณีที่ฉันเคยเห็นหรือเคยได้ยินมาโดยที่โปรแกรม C หรือ C ++ ทำงานได้ดีในดีบักเกอร์ แต่ล้มเหลวเมื่อเรียกใช้ภายนอกสาเหตุคือการเขียนเกินจุดสิ้นสุดของอาร์เรย์ภายในของฟังก์ชัน (ดีบักเกอร์ใส่สแต็กได้มากขึ้นดังนั้นคุณจึงมีโอกาสน้อยที่จะเขียนทับสิ่งที่สำคัญ)


32
ใครบางคนให้ซิการ์ชายคนนี้! ในกรณีของฉันฉันกำลังส่ง StringBuilder ที่ไม่มีความสามารถมากพอที่จะฟังก์ชั่น P / Invoke ฉันเดาว่ามันเหมือนมีคนเขียนบนใบหน้าของคุณด้วยเมจิกมาร์กเกอร์ตอนที่คุณหลับ: ภายใต้ดีบั๊กพวกเขาจบลงด้วยการขีดเขียนบนหน้าผากของคุณดังนั้นคุณจึงไม่สังเกตเห็น แต่หากไม่มีดีบั๊กพวกเขาจะแทงคุณใน ตา ... อะไรทำนองนั้น ขอบคุณสำหรับเคล็ดลับนี้!
Nicholas Piasecki

1
ในกรณีของฉันมันเป็นปัญหาการจัดตำแหน่งบนโปรเซสเซอร์ ARM โดยใช้ Obj-C
Almo

1
11 ปีต่อมาและสิ่งนี้ยังคงเป็นจริง ... อย่าลืมจองเวกเตอร์ของคุณ
dav

1
ตกลงแล้วเราจะเปลี่ยนพฤติกรรมของโหมดดีบักอย่างไรเพื่อให้สามารถดีบักได้จริง
Paul Childs

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

56

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

int* p;
....
if (p == 0) { // do stuff }

ในโหมดดีบักโค้ดใน if ไม่ได้ถูกเรียกใช้งาน แต่ในโหมดรีลีส p มีค่าที่ไม่ได้กำหนดซึ่งไม่น่าจะเป็น 0 ดังนั้นโค้ดจึงถูกเรียกใช้งานบ่อยครั้งที่ทำให้เกิดปัญหา

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


กรณีทั่วไปลืมใส่ตัวแปรสมาชิกใน (หนึ่งใน) รายการเริ่มต้นสมาชิกคอนสตรัคเตอร์ มีผลเหมือนกัน แต่หายากกว่าถ้าคุณไม่รู้ว่าควรมองหาการเริ่มต้นสมาชิกที่เหมาะสมเช่นกัน
steffenj

1
ในโหมดดีบักตัวแปรมักจะเริ่มต้นเป็น 'ค่าคงที่ที่กำหนดของคอมไพเลอร์' ซึ่งสามารถใช้ในการดีบักเพื่อระบุว่าตัวแปรอยู่ในสถานะใดตัวอย่างเช่นพอยน์เตอร์ NULL หรือ 0xDeadBeef เป็นที่นิยม
Martin York

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

1
ไม่ตัวแปรจะไม่เริ่มต้นเลยและยังคงเป็น UB ที่จะ "ใช้" ได้จนกว่าจะมีการกำหนดให้ อย่างไรก็ตามเนื้อหาหน่วยความจำพื้นฐานมักจะถูกเติมไว้ล่วงหน้าด้วย 0x0000000 หรือ 0xDEADBEEF หรือรูปแบบอื่น ๆ ที่เป็นที่รู้จัก
Lightness Races ใน Orbit

27

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

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

  2. การมีดีบักเกอร์อาจเปลี่ยนลักษณะการทำงานของโปรแกรมได้เช่นกันทั้งสำหรับรุ่นที่วางจำหน่ายและรุ่นดีบัก ดูคำตอบนี้ กล่าวโดยย่ออย่างน้อย Visual Studio Debugger จะใช้ Debug Heap โดยอัตโนมัติเมื่อเชื่อมต่อกับโปรแกรม คุณสามารถปิดฮีปดีบักได้โดยใช้ตัวแปรสภาพแวดล้อม _NO_DEBUG_HEAP คุณสามารถระบุสิ่งนี้ในคุณสมบัติคอมพิวเตอร์ของคุณหรือในการตั้งค่าโครงการใน Visual Studio นั่นอาจทำให้ข้อผิดพลาดสามารถทำซ้ำได้เมื่อติดดีบักเกอร์

    เพิ่มเติมเกี่ยวกับการดีบักความเสียหายของฮีปที่นี่

  3. หากวิธีแก้ปัญหาก่อนหน้านี้ไม่ได้ผลคุณจำเป็นต้องตรวจจับข้อยกเว้นที่ไม่สามารถจัดการได้และแนบตัวแก้ไขข้อบกพร่องหลังการชันสูตรที่อินสแตนซ์ที่เกิดข้อขัดข้อง คุณสามารถใช้เช่น WinDbg สำหรับสิ่งนี้รายละเอียดเกี่ยวกับดีบักเกอร์ชันสูตรพลิกศพที่สามารถใช้ได้และการติดตั้งที่ MSDN

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

    ก. ติดตั้งตัวจัดการการยุติแบบกำหนดเองโดยใช้std::set_terminate

    หากคุณต้องการแก้ไขปัญหานี้ภายในเครื่องคุณสามารถเรียกใช้การวนซ้ำที่ไม่มีที่สิ้นสุดภายในตัวจัดการการยุติและส่งข้อความบางส่วนไปยังคอนโซลเพื่อแจ้งให้คุณทราบว่าstd::terminateมีการเรียก จากนั้นแนบดีบักเกอร์และตรวจสอบกลุ่มการโทร หรือคุณพิมพ์การติดตามสแต็กตามที่อธิบายไว้ในคำตอบนี้

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

    ข. ใช้กลไกการจัดการข้อยกเว้นที่มีโครงสร้างของ Microsoftซึ่งช่วยให้คุณสามารถตรวจจับข้อยกเว้นของฮาร์ดแวร์และซอฟต์แวร์ได้ ดู MSDN คุณสามารถป้องกันบางส่วนของรหัสของคุณโดยใช้ SEH และใช้แนวทางเดียวกับในก) เพื่อแก้ไขปัญหา SEH ให้ข้อมูลเพิ่มเติมเกี่ยวกับข้อยกเว้นที่เกิดขึ้นซึ่งคุณสามารถใช้เมื่อส่งรายงานข้อผิดพลาดจากแอปที่ใช้งานจริง


16

สิ่งที่ต้องระวัง:

Array overruns - โปรแกรมแก้ไขจุดบกพร่อง Visual Studio แทรกช่องว่างภายในซึ่งอาจหยุดการขัดข้อง

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

การเชื่อมโยง - เป็นรุ่นของคุณที่ดึงไลบรารีที่ถูกต้อง

สิ่งที่ต้องลอง:

Minidump - ใช้งานง่ายมาก (เพียงแค่ค้นหาใน msdn) จะให้การถ่ายโอนข้อมูลความผิดพลาดทั้งหมดสำหรับแต่ละเธรด คุณเพียงแค่โหลดเอาต์พุตลงใน Visual Studio และเหมือนกับว่าคุณกำลังดีบักในขณะที่เกิดข้อผิดพลาด


1
สวัสดี - ฉันได้โหวตโดยไม่ระบุชื่อสำหรับคำตอบนี้ ฉันอยากเข้าใจว่าทำไม?
morechilli

12

คุณสามารถตั้งค่า WinDbg เป็นโปรแกรมดีบักหลังการตายของคุณ การดำเนินการนี้จะเปิดตัวดีบักเกอร์และแนบเข้ากับกระบวนการเมื่อเกิดข้อขัดข้อง ในการติดตั้ง WinDbg สำหรับการดีบักหลังการตายให้ใช้ตัวเลือก / I (โปรดทราบว่าเป็นตัวพิมพ์ใหญ่ ):

windbg /I

รายละเอียดเพิ่มเติมที่นี่

สาเหตุส่วนใหญ่น่าจะเป็นตัวแปรที่เป็นหน่วยตามคำตอบอื่น ๆ แนะนำ


2
และอย่าลืมว่าคุณสามารถให้คอมไพลเลอร์สร้างไฟล์ PDB ได้แม้ว่าจะไม่ใช่ค่าเริ่มต้นก็ตาม
Michael Burr

คำตอบที่แท้จริงเท่านั้นสำหรับคำถามจริงๆ
Sebastian

10

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

char *end = static_cast<char*>(attr->data) + attr->dataSize;

นี่เป็นข้อผิดพลาดของ Fencepost (ข้อผิดพลาดแบบ off-by-one) และได้รับการแก้ไขโดย:

char *end = static_cast<char*>(attr->data) + attr->dataSize - 1;

สิ่งที่แปลกคือฉันโทรไปที่ _CrtCheckMemory () หลายครั้งรอบ ๆ ส่วนต่างๆของโค้ดของฉันและพวกเขาก็ส่งคืน 1 เสมอฉันสามารถหาที่มาของปัญหาได้โดยการใส่ "return false;" เรียกในกรณีทดสอบและจากนั้นในที่สุดก็พิจารณาผ่านการลองผิดลองถูกว่าข้อผิดพลาดอยู่ที่ไหน

ขอบคุณทุกคนสำหรับความคิดเห็นของคุณ - วันนี้ฉันได้เรียนรู้มากมายเกี่ยวกับ windbg.exe! :)


8
วันนี้ฉันได้ทำการดีบักปัญหาที่คล้ายกันและ _CrtCheckMemory () กลับมา 1 เสมอ แต่แล้วฉันก็รู้ว่าทำไม: ในโหมดรีลีส _CrtCheckMemory เป็น # ที่กำหนดไว้เป็น ((int) 1)
Brian Morearty

7

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

  1. เรียกใช้ EXE และก่อนที่จะหยุดทำงานให้ทำ Attach To Process (เมนู Tools บน Visual Studio)
  2. หลังจากเกิดข้อขัดข้องให้เลือกตัวเลือกเพื่อเปิดตัวดีบักเกอร์

เมื่อระบบขอให้ชี้ไปที่ไฟล์ PDB ให้เรียกดูเพื่อค้นหา หาก PDB ถูกใส่ไว้ในโฟลเดอร์ผลลัพธ์เดียวกันกับ EXE หรือ DLL ของคุณอาจมีการหยิบขึ้นมาโดยอัตโนมัติ

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

หมายเหตุ: ฉันสมมติว่ามีสภาพแวดล้อม Windows / Visual Studio ที่นี่


3

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

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


3

เพื่อให้มีการถ่ายโอนข้อมูลข้อขัดข้องที่คุณสามารถวิเคราะห์ได้:

  1. สร้างไฟล์ pdb สำหรับโค้ดของคุณ
  2. คุณ rebase เพื่อให้ exe และ dlls ของคุณโหลดในที่อยู่เดียวกัน
  3. เปิดใช้งานดีบักเกอร์ชันสูตรเช่นดร. วัตสัน
  4. ตรวจสอบที่อยู่ความล้มเหลวผิดพลาดโดยใช้เครื่องมือเช่นการค้นหาความผิดพลาด

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

หวังว่ามันจะช่วย ...


3

วิธีที่ยอดเยี่ยมในการแก้ไขข้อผิดพลาดเช่นนี้คือการเปิดใช้งานการเพิ่มประสิทธิภาพสำหรับบิวด์ดีบัก


2

เมื่อฉันมีปัญหาเมื่อแอปทำงานคล้ายกับของคุณ มันกลายเป็นบัฟเฟอร์ที่น่ารังเกียจใน sprintf โดยปกติแล้วจะทำงานเมื่อเรียกใช้โดยมีการติดดีบักเกอร์ สิ่งที่ฉันทำคือการติดตั้งตัวกรองข้อยกเว้นที่ไม่สามารถจัดการได้ ( SetUnhandledExceptionFilter ) ซึ่งฉันบล็อกแบบไม่สิ้นสุด (โดยใช้ WaitForSingleObject บนหมายเลขอ้างอิงปลอมที่มีค่าการหมดเวลาของ INFINITE)

คุณสามารถทำอะไรบางอย่างตามแนวของ:

ยาว __stdcall MyFilter (EXCEPTION_POINTERS *)
{
    จัดการ hEvt = :: CreateEventW (0,1,0,0);
    ถ้า (hEvt)
    {
        ถ้า (WAIT_FAILED == :: WaitForSingleObject (hEvt, INFINITE))
        {
            // บันทึกล้มเหลว
        }
    }

}
// บางแห่งใน wmain ของคุณ / WinMain:
SetUnhandledExceptionFilter (MyFilter);

จากนั้นฉันก็แนบดีบักเกอร์หลังจากที่ข้อผิดพลาดปรากฏขึ้น (โปรแกรม gui หยุดตอบสนอง)

จากนั้นคุณสามารถถ่ายโอนข้อมูลและดำเนินการได้ในภายหลัง:

.dump / ma path_to_dump_file

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

sd esp ช่วง 1003f

คำสั่งจะค้นหาพื้นที่ที่อยู่สแต็กสำหรับระเบียน CONTEXT ที่ระบุความยาวของการค้นหา ฉันมักจะใช้สิ่งที่ต้องการ'l? 10000' หมายเหตุอย่าใช้ตัวเลขขนาดใหญ่โดยปกติเป็นระเบียนที่คุณอยู่ใกล้กับกรอบตัวกรองข้อยกเว้นที่ไม่ได้จัดการ 1003f คือการรวมกันของแฟล็ก (ฉันเชื่อว่ามันสอดคล้องกับ CONTEXT_FULL) ที่ใช้เพื่อจับภาพสถานะโปรเซสเซอร์ การค้นหาของคุณจะคล้ายกับสิ่งนี้:

0: 000> sd esp l1000 1003f
0012c160 0001003f 00000000 00000000 00000000? ...............

เมื่อคุณได้รับผลลัพธ์กลับมาให้ใช้ที่อยู่ในคำสั่ง cxr:

.cxr 0012c160

สิ่งนี้จะนำคุณไปสู่ ​​CONTEXT ใหม่นี้ในเวลาที่เกิดข้อขัดข้อง (คุณจะได้รับการติดตามสแต็กเมื่อแอปของคุณขัดข้อง) นอกจากนี้ให้ใช้:

.exr -1

เพื่อดูว่ามีข้อยกเว้นใดเกิดขึ้น

หวังว่าจะช่วยได้


2

บางครั้งสิ่งนี้เกิดขึ้นเนื่องจากคุณได้รวมการดำเนินการที่สำคัญไว้ในมาโคร "ยืนยัน" อย่างที่คุณทราบ "assert" จะประเมินนิพจน์เฉพาะในโหมดดีบักเท่านั้น


1

เกี่ยวกับปัญหาของคุณในการรับข้อมูลการวินิจฉัยคุณได้ลองใช้ adplus.vbs แทน WinDbg.exe หรือไม่ หากต้องการแนบไปกับกระบวนการที่กำลังทำงานอยู่ให้ใช้

adplus.vbs -crash -p <process_id>

หรือเพื่อเริ่มแอปพลิเคชันในกรณีที่ข้อขัดข้องเกิดขึ้นอย่างรวดเร็ว:

adplus.vbs -crash -sc your_app.exe

ดูข้อมูลทั้งหมดเกี่ยวกับ adplus.vbs ได้ที่: http://support.microsoft.com/kb/286350


1

Ntdll.dll พร้อมกับดีบักเกอร์ที่แนบมา

ข้อแตกต่างเล็กน้อยที่ทราบระหว่างการเรียกใช้โปรแกรมจาก IDE หรือ WinDbg เมื่อเทียบกับการเปิดใช้งานจากบรรทัดคำสั่ง / เดสก์ท็อปคือเมื่อเปิดตัวพร้อมกับดีบักเกอร์ที่แนบมา (เช่น IDE หรือ WinDbg) ntdll.dll ใช้การใช้งานฮีปที่แตกต่างกันซึ่งทำการตรวจสอบความถูกต้องเล็กน้อย เกี่ยวกับการจัดสรรหน่วยความจำ / การว่าง

คุณสามารถอ่านข้อมูลที่เกี่ยวข้องบางอย่างในการเบรกพอยต์ของผู้ใช้ที่ไม่คาดคิดใน ntdll.dll เครื่องมืออย่างหนึ่งที่อาจจะสามารถช่วยให้คุณระบุปัญหาคือPageHeap.exe

การวิเคราะห์ข้อขัดข้อง

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


1

Vista SP1 มีตัวสร้างการถ่ายโอนข้อมูลขัดข้องที่ดีจริงๆในระบบ น่าเสียดายที่ไม่ได้เปิดโดยค่าเริ่มต้น!

ดูบทความนี้: http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx

ประโยชน์ของแนวทางนี้คือไม่จำเป็นต้องติดตั้งซอฟต์แวร์เพิ่มเติมในระบบที่ได้รับผลกระทบ จับมันแล้วฉีกที่รัก!


1

จากประสบการณ์ของฉันที่ส่วนใหญ่เป็นปัญหาหน่วยความจำเสียหาย

ตัวอย่างเช่น :

char a[8];
memset(&a[0], 0, 16);

: /*use array a doing some thing */

เป็นไปได้มากที่จะเป็นปกติในโหมดดีบักเมื่อรันโค้ด

แต่ในการเปิดตัวนั่นอาจจะผิดพลาด

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

ใช้เครื่องมือบางอย่างเช่นVisual Leak Detector (windows) หรือvalgrind (linux) จะดีกว่า


1

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

ตัวอย่าง:

โครงการรวมถึงmathfuและใช้เรียนด้วย STL เวกเตอร์: มาตรฐาน :: เวกเตอร์ <mathfu :: vec2> การใช้งานดังกล่าวอาจทำให้เกิดข้อขัดข้องในขณะที่สร้างรายการmathfu :: vec2เนื่องจากตัวจัดสรรเริ่มต้นของ STL ไม่รับประกันการจัดตำแหน่ง 16 ไบต์ที่ต้องการ ในกรณีนี้เพื่อพิสูจน์ความคิดเราสามารถกำหนด#define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT 1ก่อนที่จะรวมmathfuคอมไพล์ใหม่ใน Release configuration และตรวจสอบอีกครั้ง

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

ฉันพบสถานการณ์ในสภาพแวดล้อม Visual Studio 2015 และ 2017


0

สิ่งที่คล้ายกันเกิดขึ้นกับฉันครั้งหนึ่งกับ GCC มันกลายเป็นการเพิ่มประสิทธิภาพที่ก้าวร้าวเกินไปซึ่งเปิดใช้งานเมื่อสร้างรุ่นสุดท้ายเท่านั้นไม่ใช่ในระหว่างกระบวนการพัฒนา

เพื่อบอกความจริงว่ามันเป็นความผิดของฉันไม่ใช่ของ gcc เนื่องจากฉันไม่ได้สังเกตว่ารหัสของฉันอาศัยข้อเท็จจริงที่ว่าการเพิ่มประสิทธิภาพนั้นจะไม่ได้ทำ

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


0

ฉันพบว่าบทความนี้มีประโยชน์สำหรับสถานการณ์ของคุณ ISTR ตัวเลือกคอมไพเลอร์ล้าสมัยเล็กน้อย ดูตัวเลือกโครงการ Visual Studio ของคุณเพื่อดูวิธีสร้างไฟล์ pdb สำหรับรุ่นของคุณ ฯลฯ


0

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


0

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

เทคนิคหนึ่งในการ จำกัด ปัญหาให้แคบลงอย่างน้อยที่สุดคือการใช้ MessageBox () เพื่อแสดงข้อความด่วนที่ระบุว่าโค้ดของคุณมีส่วนใดในโปรแกรม ("เริ่มต้น Foo ()", "เริ่ม Foo2 ()"); เริ่มวางไว้ที่ด้านบนสุดของฟังก์ชั่นในส่วนของโค้ดที่คุณสงสัย (คุณกำลังทำอะไรอยู่ตอนที่มันพัง) เมื่อคุณสามารถบอกได้ว่าฟังก์ชันใดให้เปลี่ยนกล่องข้อความเป็นบล็อกของรหัสหรือแม้แต่บรรทัดแต่ละบรรทัดภายในฟังก์ชันนั้นจนกว่าคุณจะ จำกัด ให้แคบลงเหลือไม่กี่บรรทัด จากนั้นคุณสามารถเริ่มพิมพ์ค่าของตัวแปรเพื่อดูว่าอยู่ในสถานะใด ณ จุดที่เกิดปัญหา


เขาได้ลองใช้ printfs แล้วดังนั้นกล่องข้อความจึงไม่ได้นำเสนออะไรใหม่ ๆ ในงานปาร์ตี้
Greg Whitfield

0

ลองใช้_CrtCheckMemory ()เพื่อดูว่าหน่วยความจำที่จัดสรรอยู่ในสถานะใด หากทุกอย่างเป็นไปด้วยดี_CrtCheckMemoryส่งกลับTRUEอื่นFALSE


0

คุณอาจเรียกใช้ซอฟต์แวร์ของคุณโดยเปิดใช้ Global Flags (ดูใน Debugging Tools for Windows) มันมักจะช่วยในการแก้ปัญหา


0

ทำให้โปรแกรมของคุณสร้างมินิดัมพ์เมื่อเกิดข้อยกเว้นจากนั้นเปิดขึ้นในดีบักเกอร์ (ตัวอย่างเช่นใน WinDbg) ฟังก์ชั่นสำคัญที่ต้องดู: MiniDumpWriteDump, SetUnhandledExceptionFilter


0

นี่เป็นกรณีที่ฉันมีบางคนอาจพบว่ามีคำแนะนำ มันเกิดข้อผิดพลาดเฉพาะในการเปิดตัวใน Qt Creator - ไม่ใช่ในการดีบัก ฉันใช้ไฟล์. ini (เนื่องจากฉันชอบแอพที่สามารถคัดลอกไปยังไดรฟ์อื่นเทียบกับแอพที่สูญเสียการตั้งค่าหาก Registry เสียหาย) สิ่งนี้ใช้กับแอพใด ๆ ที่จัดเก็บการตั้งค่าไว้ภายใต้โครงสร้างไดเรกทอรีของแอพ หากบิวด์ดีบักและรีลีสอยู่ภายใต้ไดเร็กทอรีที่ต่างกันคุณสามารถตั้งค่าที่แตกต่างกันได้เช่นกัน ฉันชอบเช็คอินที่ไม่ได้เช็คอินที่อื่น มันกลายเป็นที่มาของความผิดพลาดของฉัน สิ่งที่ดีที่ฉันพบ

ฉันเกลียดที่จะพูดมัน แต่ฉันวินิจฉัยเฉพาะความผิดพลาดใน MS Visual Studio Community Edition; หลังจากติดตั้ง VS แล้วปล่อยให้แอปของฉันขัดข้องใน Qt Creator และเลือกที่จะเปิดในดีบักเกอร์ของ Visual Studio ในขณะที่แอป Qt ของฉันไม่มีข้อมูลสัญลักษณ์ปรากฎว่าห้องสมุด Qt มีบางส่วน มันพาฉันไปสู่แนวรุก เนื่องจากฉันสามารถเห็นได้ว่ามีการเรียกวิธีการใด (ฉันคิดว่า Qt เป็นเฟรมเวิร์ก LGPL ที่สะดวกมีประสิทธิภาพและข้ามแพลตฟอร์ม)


0

ฉันก็มีปัญหานี้เหมือนกัน ในกรณีของฉันโหมด RELEASE มี msvscrtd.dll ในนิยามตัวเชื่อมโยง เราลบออกและปัญหาได้รับการแก้ไข

หรืออีกวิธีหนึ่งคือการเพิ่ม / NODEFAULTLIB ไปยังอาร์กิวเมนต์บรรทัดรับคำสั่งตัวเชื่อมโยงก็ช่วยแก้ปัญหาได้เช่นกัน


-3

ฉันมีข้อผิดพลาดนี้และเกิดข้อผิดพลาดแม้ว่าจะพยายาม! clean! โครงการของฉัน. ดังนั้นฉันจึงลบไฟล์ obj ด้วยตนเองจากไดเร็กทอรี Release และหลังจากนั้นก็สร้างได้ดี


-6

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


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

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

IMHO เป็นความคิดที่ไม่ดี ไฟล์ปฏิบัติการมีขนาดใหญ่ขึ้นไม่ได้รับการปรับให้เหมาะสมและทำงานช้าลงมาก กรณีเหล่านี้ค่อนข้างหายาก ถึงแม้จะทำให้เสียขวัญเป็นพิเศษเมื่อเกิดขึ้น คุณไม่ควรส่งมอบผลิตภัณฑ์ที่ด้อยคุณภาพอย่างต่อเนื่องโดยกังวลเกี่ยวกับการดีบักกรณีที่เลวร้ายที่สุดที่หายากมาก (ของฉันไม่ใช่หนึ่งในการโหวตลดจำนวนมาก) ฉันเขียนโปรแกรมให้ NASA; และเราได้กล่าวว่าอย่างน้อยที่สุดโค้ดทุกบรรทัดควรได้รับการทดสอบเพียงครั้งเดียว การทดสอบหน่วยยังสามารถช่วยได้
CodeLurker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.