คอมไพเลอร์มาทำไมจึงเชื่อถือได้?


62

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

... และวิธีการที่จะทำให้พวกเขาคอมไพเลอร์ที่เชื่อถือได้เพื่อ?


16
ดีที่พวกเขารวบรวมเรียบเรียงในนั้น ...
ไมเคิล K

31
พวกเขาไม่ผิดพลาด มีข้อผิดพลาดคอมไพเลอร์เป็นเพียงว่าพวกเขาจะหายากมาก
ChrisF

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

คุณจะได้เรียนรู้บางสิ่งบางอย่างโดยการสังเกตวิธีคอมไพเลอร์ที่จะมีข้อบกพร่องมาก (เช่น SDCC!) จะแตกต่างจากคอมไพเลอร์เช่น GCC ซึ่งมีประสิทธิภาพมากขึ้นและความน่าเชื่อถือ
เบ็คแจ็คสัน

คำตอบ:


96

พวกเขาได้รับการทดสอบอย่างละเอียดผ่านการใช้งานโดยนักพัฒนาหลายพันหรือหลายล้านคนในเวลา

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

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


32
บวกรหัสคอมไพเลอร์ส่วนใหญ่อาจพิสูจน์ได้ถูกต้อง
biziclop

@biziclop จุดดีนี่เป็นอีกผลสืบเนื่องจากลักษณะพิเศษของงาน
PéterTörök

คอมไพเลอร์ตัวแรกเสร็จสมบูรณ์ถูกเขียนในปี 1957 สำหรับภาษา FORTRAN โดย John Backus คุณเห็นไหมว่าเทคโนโลยีคอมไพเลอร์มีอายุมากกว่า 50 ปี เรามีเวลาพอสมควรที่จะทำให้ถูกต้องแม้ว่าในขณะที่คนอื่น ๆ ชี้ว่าคอมไพเลอร์มีข้อบกพร่อง
leed25d

@biziclop ในความเป็นจริงส่วนประกอบบางอย่างเช่น lexers และ parsers สามารถสร้างได้อัตโนมัติจากไวยากรณ์ซึ่งช่วยลดความเสี่ยงของข้อผิดพลาดอีกครั้ง (หากตัวสร้าง lexer / parser มีความแข็งแกร่ง - ซึ่งมักจะเป็นเหตุผลเดียวกันกับที่กล่าวข้างต้น) .
PéterTörök

2
@ Péter: ตัวกำเนิด Lexer / parser ดูเหมือนจะค่อนข้างยากในคอมไพเลอร์ที่ใช้กันอย่างแพร่หลาย - ส่วนใหญ่เขียน lexer และ parser ด้วยมือด้วยเหตุผลหลายประการรวมถึงความเร็วและการขาดตัวแยกวิเคราะห์ / smart lexer ที่เพียงพอสำหรับภาษาที่เป็นปัญหา (เช่น C )

61

นอกจากคำตอบที่ยอดเยี่ยมทั้งหมด:

คุณมี "อคติผู้สังเกตการณ์" คุณไม่ได้สังเกตข้อผิดพลาดและดังนั้นคุณคิดว่าไม่มี

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

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

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

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

หากคุณนั่งลงกับข้อกำหนดภาษาของภาษาใด ๆ และใช้งานคอมไพเลอร์สำหรับภาษานั้นและพยายามอย่างหนักเพื่อตรวจสอบว่าคอมไพเลอร์ใช้ข้อมูลจำเพาะหรือไม่โดยเน้นไปที่กรณีมุมที่คลุมเครือในไม่ช้าคุณจะพบว่า รวบรวมข้อบกพร่องค่อนข้างบ่อย ขอยกตัวอย่างให้หน่อยนี่คือบั๊กคอมไพเลอร์ C # ที่ฉันพบเมื่อห้านาทีก่อน

static void N(ref int x){}
...
N(ref 123);

คอมไพเลอร์ให้สามข้อผิดพลาด

  • อาร์กิวเมนต์ ref หรือ out ต้องเป็นตัวแปรที่กำหนดได้
  • คู่ที่ดีที่สุดสำหรับ N (การอ้างอิง int x) มีอาร์กิวเมนต์ที่ไม่ถูกต้อง
  • ไม่มี "ref" ในอาร์กิวเมนต์ 1

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

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

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


4
ข้อความแสดงข้อผิดพลาดที่ดีหลังจากอันแรกยากมากที่จะทำ

แน่นอนว่าจะต้องมีการใช้พลังงานที่ดีขึ้นจากนั้นทำให้คอมไพเลอร์สมบูรณ์ "คนโง่"
Homde

2
@MKO: แน่นอน ข้อบกพร่องมากมายไม่ได้รับการแก้ไข บางครั้งการแก้ไขมีราคาแพงมากและสถานการณ์ก็คลุมเครือจนทำให้ต้นทุนไม่ได้รับการพิสูจน์ด้วยผลประโยชน์ และบางครั้งก็มีคนมากพอที่จะพึ่งพาพฤติกรรม "บั๊กกี้" ที่คุณต้องทำต่อไป
Eric Lippert

mmm ... บั๊กซึ่งจบลงด้วยข้อความผิดพลาดคือ "ดี" มันเป็นไปได้เสมอที่จะทำรหัสเล็กน้อยเพื่อให้มันทำงานได้ สิ่งที่เกี่ยวกับข้อผิดพลาดที่คอมไพเลอร์ยอมรับรหัสต้นฉบับและสร้างผลลัพธ์ assmebly "ผิด" น่ากลัวมาก
Gianluca Ghettini

7
@aij: แก้ไขในแง่ของ "รหัส C # ที่ถูกกฎหมายอย่างชัดเจน" ตัวอย่างเช่นคุณเคยเขียนโปรแกรมที่มีอินเตอร์เฟสที่สืบทอดสองอินเตอร์เฟสโดยที่หนึ่งอินเตอร์เฟสมีคุณสมบัติและอีกอันหนึ่งมีเมธอดชื่อเดียวกันกับคุณสมบัติหรือไม่? เร็วโดยไม่ต้องดูข้อมูลจำเพาะ: ถูกกฎหมายหรือไม่ ทีนี้สมมติว่าคุณมีการเรียกใช้เมธอดนั้น มันคลุมเครือหรือไม่ และอื่น ๆ ผู้คนเขียนโค้ดที่ไม่ได้ทำในสิ่งที่พวกเขาหมายถึงตลอดเวลา แต่พวกเขาไม่ค่อยเขียนโค้ดที่คุณจะต้องเป็นผู้เชี่ยวชาญ spec ที่จะบอกว่ามันเป็นกฎหมาย C #
Eric Lippert

51

คุณล้อเล่นกับฉันไหม คอมไพเลอร์ก็มีบั๊กด้วยเช่นกัน

GCC น่าจะเป็นที่มีชื่อเสียงโด่งดังมากที่สุดของคอมไพเลอร์ที่มาเปิดในโลกและจะดูที่ฐานข้อมูลข้อผิดพลาดของ: http://gcc.gnu.org/bugzilla/buglist.cgi?product=gcc&component=c%2B%2B&resolution=-- -

ระหว่าง GCC 3.2 และ GCC 3.2.3 ดูที่จำนวนข้อบกพร่องที่ได้รับการแก้ไข: http://gcc.gnu.org/gcc-3.2/changes.html

สำหรับคนอื่น ๆ เช่น Visual C ++ ฉันไม่ต้องการแม้แต่จะเริ่ม

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

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


19

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

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


6
+1 สำหรับ "การดูคอมไพเลอร์เป็นมาตรฐาน" ฉันยืนยันมานานแล้วว่ามีสองสิ่งที่กำหนดภาษาได้อย่างแท้จริงนั่นคือคอมไพเลอร์และไลบรารีมาตรฐาน เอกสารมาตรฐานเป็นเพียงเอกสารประกอบ
Mason Wheeler

8
@ Mason: ใช้ได้ดีสำหรับภาษาที่มีการนำไปใช้งาน สำหรับภาษาที่มีจำนวนมากมาตรฐานมีความสำคัญ ผลกระทบในชีวิตจริงคือถ้าคุณบ่นเกี่ยวกับบางสิ่งผู้ขายจะนำคุณอย่างจริงจังหากเป็นปัญหามาตรฐานและปัดคุณออกหากพฤติกรรมที่ไม่ได้กำหนดหรืออะไรทำนองนั้น
David Thornley

2
@ Mason - นั่นเป็นเพราะมีเพียงไม่กี่ภาษาที่มีมาตรฐานในการและ / หรือที่พวกเขาปฏิบัติตาม นั่นคือ btw, IMHO ไม่ใช่สิ่งที่ดี - สำหรับการพัฒนาอย่างจริงจังทุกประเภทที่คาดว่าจะมีอายุมากกว่าหนึ่งระบบปฏิบัติการ
โกง

1
@David: หรือถูกต้องมากกว่าหนึ่งการดำเนินการที่โดดเด่น Borland กำหนด Pascal และ Microsoft กำหนด C # โดยไม่คำนึงถึงสิ่งที่ ANSI และ ECMA พูด
dan04

4
รหัส C, C ++ หรือ Fortran ที่ทำงานล้มเหลวภายใต้การปรับให้เหมาะสมสูงมักจะใส่รหัสผิดมากกว่า compiler บั๊ก ฉันมักจะทำงานร่วมกับคอมไพเลอร์เมื่อเร็ว ๆ นี้และคอมไพเลอร์ก่อนวางจำหน่ายบ่อยครั้งสำหรับฮาร์ดแวร์ใหม่และดูความล้มเหลวที่เกี่ยวข้องกับการปรับให้เหมาะสมเป็นประจำ เนื่องจากภาษาเหล่านี้มีความคิดเกี่ยวกับพฤติกรรมที่ไม่ได้กำหนดและไม่ได้ระบุการจัดการของโปรแกรมที่ไม่เป็นไปตามข้อกำหนดจึงต้องตรวจสอบข้อขัดข้องอย่างระมัดระวังในที่สุดเทียบกับชุดประกอบ ใน 80-90% ของกรณีรหัสแอปพลิเคชันผิดและไม่ใช่คอมไพเลอร์
Phil Miller

14

คอมไพเลอร์มีคุณสมบัติหลายอย่างที่นำไปสู่ความถูกต้อง:

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

2
นอกจากนี้ในหลายกรณีรหัสเก่า GCC มีอายุมากกว่า 20 ปีเช่นเดียวกับรุ่นอื่น ๆ ดังนั้นข้อบกพร่องจำนวนมากได้ถูกนำมาใช้ในกรอบเวลาที่ยาวนาน
Zachary K

13

เราใช้คอมไพเลอร์เป็นประจำทุกวัน

... และพวกเขาทำให้คอมไพเลอร์เชื่อถือได้อย่างไร

พวกเขาทำไม่ได้ พวกเราทำ. เพราะทุกคนใช้พวกมันตลอดเวลาจึงพบข้อบกพร่องได้อย่างรวดเร็ว

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

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

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


11

นอกจากคำตอบทั้งหมดแล้วฉันต้องการเพิ่ม:

ฉันเชื่อว่าหลายครั้งผู้ขายกำลังกินอาหารสุนัขของตัวเอง ความหมายพวกเขากำลังเขียนคอมไพเลอร์ในตัวเอง


7

ฉันพบข้อบกพร่องของคอมไพเลอร์บ่อยครั้ง

คุณสามารถค้นหาพวกมันในมุมที่มืดกว่าซึ่งมีผู้ทดสอบน้อยกว่า ตัวอย่างเช่นในการค้นหาข้อบกพร่องใน GCC คุณควรลอง:

  • สร้าง cross-compiler คุณจะพบข้อบกพร่องหลายสิบตัวใน GCC สคริปต์กำหนดค่าและสร้าง ผลลัพธ์บางอย่างในการสร้างความล้มเหลวในระหว่างการคอมไพล์ GCC และอื่น ๆ จะทำให้ความล้มเหลวของ cross-compiler เพื่อสร้าง executables ทำงาน
  • สร้าง GCC เวอร์ชัน Itanium โดยใช้ profile-bootstrap สองสามครั้งสุดท้ายที่ฉันลองใช้ GCC 4.4 และ 4.5 ​​มันล้มเหลวในการสร้างตัวจัดการข้อยกเว้น C ++ ที่ใช้งานได้ บิลด์ที่ไม่ได้รับการปรับปรุงให้ทำงานได้ดี ดูเหมือนว่าไม่มีใครสนใจที่จะแก้ไขข้อผิดพลาดที่ฉันรายงานและฉันก็เลิกแก้ไขด้วยตัวเองหลังจากพยายามที่จะขุดสิ่งที่แตกหักในข้อกำหนดหน่วยความจำ asm ของ GCC
  • ลองสร้าง GCJ ที่ใช้งานได้ของคุณเองจากสิ่งล่าสุดโดยไม่ต้องติดตามสคริปต์สร้าง distro ฉันท้าคุณ.

เราพบปัญหามากมายกับ IA64 (Itanium) เราไม่มีลูกค้าจำนวนมากสำหรับแพลตฟอร์มนั้นดังนั้นการลดระดับการเพิ่มประสิทธิภาพจึงเป็นข้อผิดพลาดตามปกติของเรา สิ่งนี้กลับไปที่คำตอบอื่น ๆ คอมไพเลอร์สำหรับภาษายอดนิยมสำหรับสถาปัตยกรรมยอดนิยมมักจะมีผู้ใช้เพียงพอและมีการสนับสนุนที่ดีพอสมควร แต่เมื่อคุณไปที่สถาปัตยกรรมและ / หรือภาษาที่ได้รับความนิยมน้อยกว่า
Omega Centauri

@Omega: การลดการเพิ่มประสิทธิภาพดูเหมือนจะเป็นสิ่งที่ทุกคนทำ น่าเสียดายที่ Itanium ต้องการคอมไพเลอร์ที่มีประสิทธิภาพสูงสุดเพื่อให้ทำงานได้ดี โอ้ดี ...
Zan Lynx

ฉันได้ยินคุณ. สถาปัตยกรรมตรงไปตรงมาล้าสมัยไปแล้วเมื่อมันออกมาโชคดีที่ AMD บังคับให้ Intels จับมือกับ x86-64 (ซึ่งดูหมิ่นหูดที่เป็นจำนวนมากก็ไม่ได้เลวร้าย) หากคุณสามารถแยกไฟล์ต้นฉบับของคุณได้คุณอาจแยกได้ว่าปัญหาคืออะไรและหาวิธีแก้ปัญหา นั่นคือสิ่งที่เราทำหากเป็นแพลตฟอร์มที่สำคัญ แต่สำหรับ IA64 ไม่ใช่
Omega Centauri

@Omega: น่าเสียดายที่ฉันชอบ Itanium จริงๆ มันเป็นสถาปัตยกรรมที่ยอดเยี่ยม ฉันคิดว่า x86 และ x86-64 ล้าสมัย แต่แน่นอนว่าพวกเขาจะไม่มีวันตาย
Zan Lynx

x86 นั้นค่อนข้างแปลก พวกมันเพิ่มสิ่งใหม่ ๆ ลงไปเรื่อย ๆ ดังนั้นมันจะโตขึ้นทีละหูด แต่เอ็นจิ้นการดำเนินการตามคำสั่งทำงานได้ค่อนข้างดีและ SSE => AVX ใหม่นั้นมอบความสามารถที่แท้จริงสำหรับผู้ที่ต้องการโค้ดสำหรับมัน เป็นที่ยอมรับว่ามีทรานซิสเตอร์จำนวนมากที่อุทิศให้กับการทำสิ่งกึ่งล้าสมัย แต่นั่นเป็นราคาที่จ่ายสำหรับความเข้ากันได้แบบดั้งเดิม
Omega Centauri

5

เหตุผลหลายประการ:

  • ผู้เขียนคอมไพเลอร์ " กินอาหารสุนัขของตัวเอง "
  • คอมไพเลอร์ขึ้นอยู่กับหลักการที่เข้าใจกันดีของ CS
  • คอมไพเลอร์ถูกสร้างขึ้นเพื่อมากสเปคที่ชัดเจน
  • คอมไพเลอร์ได้รับการทดสอบ
  • คอมไพเลอร์ไม่น่าเชื่อถือเสมอไป

4

พวกเขามักจะดีมากที่ -O0 ในความเป็นจริงถ้าเราสงสัยข้อผิดพลาดของคอมไพเลอร์เราเปรียบเทียบ -O0 กับระดับใดก็ตามที่เราพยายามใช้ ระดับการเพิ่มประสิทธิภาพที่สูงขึ้นนั้นมีความเสี่ยงสูงกว่า บางคนจงใจทำเช่นนั้นและติดป้ายกำกับไว้ในเอกสารประกอบ ฉันได้พบกับผู้คนจำนวนมาก (อย่างน้อยหนึ่งร้อยคนในช่วงเวลาของฉัน) แต่พวกเขากำลังหายากขึ้นมาก อย่างไรก็ตามในการค้นหาหมายเลขพิเศษที่ดี (หรือมาตรฐานอื่น ๆ ที่มีความสำคัญต่อการตลาด) สิ่งล่อใจที่จะผลักดันขีด จำกัด นั้นยอดเยี่ยม เรามีปัญหาเมื่อไม่กี่ปีก่อนที่ผู้ขาย (ไม่มีชื่อ) ตัดสินใจที่จะละเมิดการเริ่มต้นของวงเล็บ - แทนที่จะเป็นตัวเลือกการคอมไพล์ที่มีป้ายกำกับพิเศษอย่างชัดเจน

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


4

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


น่าเสียดายที่เราไม่สามารถดูข้อบกพร่องระดับที่สองได้: คอมไพล์โค้ด = ทุกอย่างเรียบร้อยดี ดังนั้นอาจครึ่งข้อบกพร่อง (สมมติว่าอัตราการแยกระหว่าง 50-50 ระหว่างสองชั้นเรียนข้อผิดพลาด) ไม่พบโดยคน แต่โดยเฉลี่ยของการทดสอบหน่วยคอมไพเลอร์
เกียนลูก้า Ghettini

3

ใช่ฉันพบข้อผิดพลาดในคอมไพเลอร์ ASP.NET เมื่อวานนี้:

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

ViewUserControl<System.Tuple<type1, type2, type3, type4, type5>>

จะไม่รวบรวมเหมือน แต่จะtype5ลบออก

ViewUserControl<System.Tuple<MyModel, System.Func<type1, type2, type3, type4>>>

จะรวบรวมหากtype4ถูกลบออก

โปรดทราบว่าSystem.Tupleมีการโอเวอร์โหลดจำนวนมากและสามารถรับพารามิเตอร์ได้มากถึง 16 พารามิเตอร์ (มันบ้ามากที่ฉันรู้)


3

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

ได้!

สองสิ่งที่น่าจดจำที่สุดคือสองสิ่งแรกที่ฉันเคยเจอ พวกเขาทั้งคู่อยู่ในคอมไพเลอร์ Lightspeed C สำหรับ Mac ขนาด 680x0 แผ่นกลับมาประมาณปี 1985-7

สิ่งแรกคือที่ไหนในบางสถานการณ์ตัวดำเนินการ postincrement จำนวนเต็มไม่ได้ทำอะไรเลย - กล่าวอีกนัยหนึ่งในรหัสเฉพาะ "i ++" ไม่ได้ทำอะไรกับ "i" ฉันดึงผมออกมาจนมองชิ้นส่วน จากนั้นฉันก็เพิ่มส่วนต่างไปจากเดิมและส่งรายงานข้อผิดพลาด

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

มันใช้งานได้ดีกับซีพียู 68000 ตัว แต่เมื่อคุณรันโค้ดเดียวกันบนซีพียู 68020 มันมักจะทำสิ่งแปลก ๆ ปรากฎว่าคุณสมบัติใหม่ของ 68020 เป็นแคชคำสั่งดั้งเดิม 256 ไบต์ นี่เป็นวันแรกที่มีแคชของ CPU มันไม่มีความคิดว่าแคชนั้น "สกปรก" และจำเป็นต้องเติมใหม่ ฉันเดาว่านักออกแบบซีพียูของ Motorola ไม่คิดว่าจะแก้ไขรหัสด้วยตนเอง ดังนั้นหากคุณทำดิสก์สองอย่างใกล้เคียงกันมากในลำดับการดำเนินการของคุณและรันไทม์ Lightspeed ได้สร้างคำแนะนำจริงที่ตำแหน่งเดียวกันบนสแต็ก CPU จะคิดผิดพลาดว่ามีคำแนะนำในการเข้าถึงแคชและเรียกใช้การทำงานดิสก์ครั้งแรกสองครั้ง

อีกครั้งการหาว่าเอาออกขุดรอบ ๆ ด้วย disassembler และก้าวเดียวมากในดีบักเกอร์ระดับต่ำ วิธีแก้ปัญหาของฉันคือนำหน้าการทำงานของดิสก์ทุกครั้งด้วยการเรียกใช้ฟังก์ชันที่ทำตามคำสั่ง 256 "NOP" ซึ่งทำให้คำสั่งแคชท่วม (และล้างออก)

ตลอดเวลา 25 ปีที่ผ่านมาฉันได้เห็นข้อบกพร่องของคอมไพเลอร์น้อยลงเรื่อย ๆ ฉันคิดว่ามีเหตุผลสองสามข้อที่:

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

หนึ่งในเหตุผลที่ควรหลีกเลี่ยงการแก้ไขโค้ดด้วยตนเอง
Technophile

3

พบข้อผิดพลาดที่จ้องมองใน Turbo Pascal 5.5 ปีที่ผ่านมา มีข้อผิดพลาดทั้งในรุ่นก่อนหน้า (5.0) และรุ่นต่อไป (6.0) ของคอมไพเลอร์ และสิ่งหนึ่งที่ควรทดสอบได้ง่ายเพราะไม่ใช่ cornercase เลย (แค่การโทรที่ไม่ได้ใช้กันทั่วไป)

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


2

เมื่อพฤติกรรมของซอฟต์แวร์ของคุณแตกต่างเมื่อคอมไพล์ด้วย -O0 และ -O2 คุณจะพบข้อผิดพลาดคอมไพเลอร์

เมื่อพฤติกรรมของซอฟต์แวร์ของคุณแตกต่างจากที่คุณคาดไว้โอกาสที่จะเกิดข้อผิดพลาดนั้นก็คือรหัสของคุณ


8
ไม่จำเป็น. ใน C และ C ++ มีพฤติกรรมที่ไม่ระบุและไม่ได้กำหนดจำนวนที่น่ารำคาญซึ่งอาจแตกต่างกันอย่างถูกต้องตามระดับการเพิ่มประสิทธิภาพหรือระยะของดวงจันทร์หรือการเคลื่อนไหวของดัชนี Dow Jones การทดสอบนั้นทำงานในภาษาที่กำหนดไว้อย่างเข้มงวดยิ่งขึ้น
David Thornley

2

คอมไพเลอร์บั๊กเกิดขึ้น แต่คุณมักจะพบพวกมันในมุมแปลก ๆ ...

มีข้อผิดพลาดแปลก ๆ ในคอมไพเลอร์ VAX VMS C ของ Digital Equipment Corporation ในปี 1990

(ฉันใส่หัวหอมบนเข็มขัดของฉันเช่นเดียวกับแฟชั่นในเวลานั้น)

เซมิโคลอนภายนอกที่ใด ๆ ก่อนหน้า for for loop จะถูกรวบรวมเป็นเนื้อความของ for loop

f(){...}
;
g(){...}

void test(){
  int i;
  for ( i=0; i < 10; i++){
     puts("hello");
  }
}

ในคอมไพเลอร์ที่มีปัญหาลูปจะดำเนินการเพียงครั้งเดียว

มันเห็น

f(){...}
g(){...}

void test(){
  int i;
  for ( i=0; i < 10; i++) ;  /* empty statement for fun */

  {
     puts("hello");
  }
}

นั่นทำให้ฉันเสียเวลามากมาย

คอมไพเลอร์ PIC C รุ่นเก่ากว่าที่เราเคยใช้สร้างประสบการณ์การทำงานนักเรียนไม่สามารถสร้างรหัสที่ใช้อินเตอร์รัปต์ลำดับความสำคัญสูงได้อย่างถูกต้อง คุณต้องรอ 2-3 ปีและอัปเกรด

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


2

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


1

ฉันเห็นข้อบกพร่องของคอมไพเลอร์หลายตัวรายงานว่าตัวเอง (โดยเฉพาะใน F #)

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

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

นอกจากนี้มักจะมีการทำแผนที่ค่อนข้างตรงไปตรงมาจากอินพุตไปยังเอาต์พุตในคอมไพเลอร์ดังนั้นการดีบักภาษาการเขียนโปรแกรมอาจจะง่ายกว่าการดีบั๊กเช่นเอนจิ้นบล็อก


1

ฉันพบข้อผิดพลาดในคอมไพเลอร์ C # เมื่อไม่นานมานี้คุณสามารถดูว่า Eric Lippert (ผู้อยู่ในทีมออกแบบ C #) คิดได้อย่างไรว่าข้อผิดพลาดอยู่ที่นี่ที่ใด

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

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

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