Làm thế nào đến trình biên dịch là rất đáng tin cậy?


63

Chúng tôi sử dụng trình biên dịch hàng ngày như thể tính chính xác của chúng là nhất định, nhưng trình biên dịch cũng là chương trình và có khả năng có thể chứa lỗi. Tôi luôn tự hỏi về sự mạnh mẽ không thể sai lầm này. Bạn đã bao giờ gặp phải một lỗi trong trình biên dịch? Nó là gì và làm thế nào bạn nhận ra vấn đề nằm ở chính trình biên dịch?

... và làm thế nào để họ làm cho trình biên dịch đáng tin cậy như vậy?


16
Chà, họ biên dịch trình biên dịch trong đó ...
Michael K

31
Họ không thể sai lầm. Có lỗi trình biên dịch - chỉ là chúng rất hiếm.
ChrisF

5
Lỗi trở nên hiếm hơn khi bạn xuống ngăn xếp mã: lỗi ứng dụng phổ biến hơn lỗi trình biên dịch. Lỗi trình biên dịch phổ biến hơn lỗi CPU (microcode). Đây thực sự là một tin tốt: bạn có thể tưởng tượng nếu nó là cách khác?
Fixee

Bạn có thể học được điều gì bằng cách quan sát như thế nào một trình biên dịch mà không có rất nhiều lỗi (như SDCC!) Khác với một trình biên dịch như gcc mà là nhiều hơn nữa mạnh mẽ và đáng tin cậy.
Ben Jackson

Câu trả lời:


96

Họ được kiểm tra kỹ lưỡng thông qua việc sử dụng bởi hàng ngàn hoặc thậm chí hàng triệu nhà phát triển theo thời gian.

Ngoài ra, vấn đề cần giải quyết được xác định rõ (bằng một đặc điểm kỹ thuật rất chi tiết). Và bản chất của nhiệm vụ cho vay dễ dàng cho các bài kiểm tra đơn vị / hệ thống. Tức là về cơ bản, nó đang dịch đầu vào văn bản theo một định dạng rất cụ thể sang đầu ra ở một loại định dạng khác được xác định rõ (một số loại mã byte hoặc mã máy). Vì vậy, nó rất dễ dàng để tạo và xác minh các trường hợp thử nghiệm.

Hơn nữa, thông thường các lỗi cũng dễ tái tạo: ngoài thông tin phiên bản nền tảng và trình biên dịch chính xác, thông thường tất cả những gì bạn cần là một đoạn mã đầu vào. Chưa kể rằng người dùng trình biên dịch (là chính nhà phát triển) có xu hướng đưa ra các báo cáo lỗi chính xác và chi tiết hơn nhiều so với bất kỳ người dùng máy tính trung bình nào :-)


32
Cộng với nhiều mã trình biên dịch có thể được chứng minh là đúng.
biziclop

@biziclop, điểm tốt, đây là một hậu quả khác của tính chất đặc biệt của nhiệm vụ.
Péter Török

Trình biên dịch hoàn chỉnh đầu tiên được viết vào năm 1957 cho ngôn ngữ FORTRAN bởi John Backus. Vì vậy, bạn thấy, công nghệ biên dịch đã hơn 50 năm tuổi. Chúng tôi đã có khá nhiều thời gian để làm cho đúng, mặc dù, như những người khác chỉ ra, trình biên dịch có lỗi.
leed25d

@biziclop, trên thực tế, một số thành phần như từ vựng và trình phân tích cú pháp thậm chí có thể được tự động phát sinh từ một ngữ pháp, điều này một lần nữa làm giảm nguy cơ lỗi (với điều kiện trình tạo lexer / trình phân tích cú pháp là mạnh mẽ - vì chúng thường là như vậy, vì nhiều lý do tương tự được liệt kê ở trên) .
Péter Török

2
@ Péter: Trình tạo trình phân tích cú pháp / trình phân tích cú pháp dường như khá hiếm trong các trình biên dịch được sử dụng rộng rãi hơn - hầu hết các trình viết lexer và trình phân tích cú pháp bằng tay vì nhiều lý do, bao gồm tốc độ và thiếu trình tạo trình phân tích cú pháp / trình phân tích thông minh đủ cho ngôn ngữ được đề cập (ví dụ C ).

61

Ngoài tất cả các câu trả lời tuyệt vời cho đến nay:

Bạn có một "thiên vị quan sát". Bạn không quan sát lỗi và do đó bạn cho rằng không có lỗi nào.

Tôi đã từng nghĩ như bạn. Sau đó, tôi bắt đầu viết trình biên dịch chuyên nghiệp, và để tôi nói với bạn, có rất nhiều lỗi trong đó!

Bạn không thấy các lỗi vì bạn viết mã giống như 99,999% của tất cả các phần còn lại của mã mà mọi người viết. Bạn có thể viết mã hoàn toàn bình thường, đơn giản, chính xác rõ ràng gọi các phương thức và chạy các vòng lặp và không làm bất cứ điều gì lạ mắt hoặc kỳ lạ, bởi vì bạn là một nhà phát triển bình thường giải quyết các vấn đề kinh doanh bình thường.

Bạn không thấy bất kỳ lỗi trình biên dịch nào vì các lỗi trình biên dịch không nằm trong các kịch bản mã thông thường đơn giản dễ phân tích; các lỗi nằm trong phân tích mã lạ mà bạn không viết.

Mặt khác, tôi có sự thiên vị quan sát ngược lại. Tôi thấy mã điên cả ngày mỗi ngày, và vì vậy với tôi các trình biên dịch dường như bị đầy lỗi.

Nếu bạn ngồi xuống với đặc tả ngôn ngữ của bất kỳ ngôn ngữ nào và thực hiện bất kỳ triển khai trình biên dịch nào cho ngôn ngữ đó và thực sự cố gắng xác định xem trình biên dịch có thực hiện chính xác thông số kỹ thuật đó hay không, tập trung vào các trường hợp góc tối, bạn sẽ sớm tìm thấy trình biên dịch lỗi khá thường xuyên. Để tôi cho bạn một ví dụ, đây là lỗi trình biên dịch C # tôi tìm thấy đúng năm phút trước.

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

Trình biên dịch đưa ra ba lỗi.

  • Một đối số ref hoặc out phải là một biến có thể gán.
  • Kết quả phù hợp nhất cho N (ref int x) có đối số không hợp lệ.
  • Thiếu "ref" trong đối số 1.

Rõ ràng thông báo lỗi đầu tiên là chính xác và thông báo lỗi thứ ba là một lỗi. Thuật toán tạo lỗi đang cố gắng tìm ra lý do tại sao đối số đầu tiên không hợp lệ, nó nhìn vào nó, thấy rằng đó là một hằng số và không quay lại mã nguồn để kiểm tra xem nó có được đánh dấu là "ref" hay không; thay vào đó, nó giả định rằng không ai đủ ngu ngốc để đánh dấu một hằng số là ref và quyết định rằng ref phải bị thiếu.

Không rõ thông báo lỗi thứ ba chính xác là gì, nhưng đây không phải là thông báo. Trong thực tế, không rõ liệu thông báo lỗi thứ hai có đúng hay không. Nên giải quyết quá tải không thành công, hay "ref 123" nên được coi là đối số ref của loại đúng? Bây giờ tôi sẽ phải suy nghĩ một chút và nói chuyện với nhóm xử lý để chúng tôi có thể xác định hành vi chính xác là gì.

Bạn chưa bao giờ thấy lỗi này bởi vì có lẽ bạn sẽ không bao giờ làm điều gì ngớ ngẩn đến mức cố gắng vượt qua 123 bằng ref. Và nếu bạn đã làm như vậy, có lẽ bạn sẽ không nhận thấy rằng thông báo lỗi thứ ba là vô nghĩa, vì thông báo đầu tiên là chính xác và đủ để chẩn đoán vấn đề. Nhưng tôi cố gắng làm những thứ như vậy, bởi vì tôi đang cố gắng phá vỡ trình biên dịch. Nếu bạn đã thử, bạn cũng sẽ thấy các lỗi.


4
Thông báo lỗi tốt sau lần đầu tiên là rất khó để làm.

Chắc chắn phải có năng lượng tốt hơn để chi tiêu sau đó làm cho trình biên dịch hoàn toàn "đánh lừa" :)
Homde

2
@MKO: Tất nhiên rồi. Rất nhiều lỗi không được sửa. Đôi khi việc sửa chữa rất tốn kém và kịch bản quá mơ hồ đến mức chi phí không được chứng minh bằng các lợi ích. Và đôi khi đủ người đã tin tưởng vào hành vi "lỗi" mà bạn phải tiếp tục duy trì.
Eric Lippert

mmm ... lỗi kết thúc trong thông báo lỗi là "tốt". Luôn luôn có thể sử dụng mã một chút để làm cho nó hoạt động. Điều gì về các lỗi trong đó trình biên dịch chấp nhận mã nguồn và tạo ra đầu ra giả định "sai". Điều đó thật đáng sợ
Gianluca Ghettini

7
@aij: Đúng theo nghĩa "mã C # rõ ràng hợp pháp". Ví dụ, bạn đã bao giờ viết một chương trình có giao diện kế thừa hai giao diện trong đó một giao diện có thuộc tính và giao diện kia có phương thức cùng tên với thuộc tính? Nhanh chóng, mà không cần nhìn vào thông số kỹ thuật: điều đó có hợp pháp không? Bây giờ giả sử bạn có một cuộc gọi đến phương thức đó; Có mơ hồ không ? Và như vậy. Mọi người viết mã mà không làm những gì họ có nghĩa là tất cả các thời gian. Nhưng chỉ hiếm khi họ viết mã trong đó bạn phải là một chuyên gia đặc biệt để nói liệu đó có phải là C # hợp pháp hay không.
Eric Lippert

51

Bạn đang đùa tôi à Trình biên dịch có lỗi quá, tải thực sự.

GCC có lẽ là trình biên dịch mã nguồn mở nổi tiếng nhất hành tinh và hãy xem cơ sở dữ liệu lỗi của nó: http://gcc.gnu.org/ormszilla/ormslist.cgi?product=gcc&component=c%2B%2B&resolution=-- -

Giữa GCC 3.2 và GCC 3.2.3 hãy xem có bao nhiêu lỗi đã được sửa: http://gcc.gnu.org/gcc-3.2/changes.html

Đối với những người khác như Visual C ++, tôi thậm chí không muốn bắt đầu.

Làm thế nào để bạn làm cho trình biên dịch đáng tin cậy? Để bắt đầu, họ có rất nhiều bài kiểm tra đơn vị. Và toàn bộ hành tinh sử dụng chúng để không có người thử nghiệm.

Nghiêm túc mà nói, các nhà phát triển trình biên dịch mà tôi muốn tin là những lập trình viên ưu việt và trong khi họ không thể sai lầm thì họ lại đóng gói rất nhiều.


19

Tôi đã gặp hai hoặc ba trong ngày của tôi. Cách thực sự duy nhất để phát hiện một là nhìn vào mã lắp ráp.

Mặc dù trình biên dịch có độ tin cậy cao vì lý do các áp phích khác đã chỉ ra, tôi nghĩ độ tin cậy của trình biên dịch thường là một đánh giá tự hoàn thành. Các lập trình viên có xu hướng xem trình biên dịch là tiêu chuẩn. Khi có sự cố xảy ra, bạn cho rằng đó là lỗi của mình (vì 99,999% thời gian là như vậy) và thay đổi mã của bạn để khắc phục sự cố trình biên dịch thay vì ngược lại. Ví dụ, mã bị lỗi trong cài đặt tối ưu hóa cao chắc chắn là lỗi trình biên dịch, nhưng hầu hết mọi người chỉ đặt nó thấp hơn một chút và tiếp tục mà không báo cáo lỗi.


6
+1 cho "xem trình biên dịch là tiêu chuẩn." Tôi đã duy trì từ lâu rằng có hai thứ thực sự xác định ngôn ngữ: trình biên dịch và thư viện chuẩn. Một tài liệu tiêu chuẩn chỉ là tài liệu.
Mason Wheeler

8
@Mason: Điều đó hoạt động tốt cho các ngôn ngữ với một triển khai. Đối với các ngôn ngữ có nhiều, tiêu chuẩn là quan trọng. Tác động thực tế là, nếu bạn phàn nàn về điều gì đó, nhà cung cấp sẽ nghiêm túc với bạn nếu đó là vấn đề tiêu chuẩn và loại bỏ bạn nếu đó là hành vi không xác định hoặc đại loại như thế.
David Thornley

2
@Mason - Điều đó chỉ bởi vì rất ít ngôn ngữ có tiêu chuẩn và / mà chúng tuân theo. Điều đó, btw, IMHO, không phải là một điều tốt - đối với bất kỳ loại phát triển nghiêm túc nào, dự kiến ​​sẽ tồn tại nhiều hơn một thế hệ HĐH.
Rook

1
@David: Hay chính xác hơn, một thực hiện vượt trội . Borland định nghĩa Pascal và Microsoft định nghĩa C # bất kể ANSI và ECMA nói gì.
dan04

4
Mã C, C ++ hoặc Fortran bị sập dưới sự tối ưu hóa cao thường là mã đầu vào sai nhiều hơn so với lỗi trình biên dịch. Tôi rất thường xuyên làm việc với các trình biên dịch gần đây và trước khi phát hành, thường là cho phần cứng rất mới và thấy các lỗi liên quan đến tối ưu hóa khá thường xuyên. Vì các ngôn ngữ này có các khái niệm về hành vi không xác định và không chỉ định việc xử lý các chương trình không tuân thủ, nên người ta phải kiểm tra các sự cố khá cẩn thận, cuối cùng chống lại hội đồng. Trong 80-90% trường hợp, mã ứng dụng sai và không phải trình biên dịch.
Phil Miller

14

Trình biên dịch có một số thuộc tính dẫn đến tính chính xác của chúng:

  • Tên miền rất nổi tiếng, và được nghiên cứu. Vấn đề được xác định rõ, và các giải pháp được cung cấp được xác định rõ.
  • Kiểm tra tự động là đủ để chứng minh trình biên dịch hoạt động chính xác
  • Trình biên dịch có các bài kiểm tra đơn vị, công khai, tự động và đơn giản, đã được tích lũy theo thời gian để bao phủ nhiều không gian lỗi hơn so với hầu hết các chương trình khác
  • Trình biên dịch có một số lượng rất lớn nhãn cầu xem kết quả của họ

2
Ngoài ra, trong nhiều trường hợp, mã đã cũ, GCC cũng hơn 20 tuổi, cũng như nhiều người khác, vì vậy rất nhiều lỗi đã được xử lý trong một khung thời gian dài.
Zachary K

13

Chúng tôi sử dụng trình biên dịch hàng ngày

... và làm thế nào để họ làm cho trình biên dịch đáng tin cậy như vậy?

Họ không. Chúng tôi làm. Bởi vì tất cả mọi người sử dụng chúng mọi lúc, lỗi được tìm thấy nhanh chóng.

Đây là một trò chơi số. Bởi vì trình biên dịch được sử dụng rất phổ biến, rất có khả năng bất kỳ lỗi nào sẽ được kích hoạt bởi ai đó, nhưng vì có một số lượng lớn người dùng như vậy, nên rất khókhả năng ai đó sẽ là bạn.

Vì vậy, nó phụ thuộc vào quan điểm của bạn: trên tất cả người dùng, trình biên dịch bị lỗi. Nhưng rất có khả năng người khác sẽ biên dịch một đoạn mã tương tự trước khi bạn thực hiện, vì vậy nếu đó lỗi, thì nó sẽ đánh vào họ chứ không phải bạn, vì vậy theo quan điểm cá nhân của bạn , có vẻ như lỗi đó là không bao giờ có

Tất nhiên, trên hết, bạn có thể thêm tất cả các câu trả lời khác ở đây: trình biên dịch được nghiên cứu kỹ, hiểu rõ. Có một huyền thoại rằng họ rất khó viết, điều đó có nghĩa là chỉ những lập trình viên rất thông minh, rất giỏi mới thực sự cố gắng viết một bài, và hết sức cẩn thận khi họ làm. Chúng thường dễ kiểm tra, và dễ kiểm tra căng thẳng hoặc kiểm tra fuzz. Người dùng trình biên dịch có xu hướng trở thành chuyên gia lập trình, dẫn đến các báo cáo lỗi chất lượng cao. Và theo cách khác: người viết trình biên dịch có xu hướng là người dùng trình biên dịch của riêng họ.


11

Ngoài tất cả các câu trả lời đã có, tôi muốn thêm:

Tôi tin rằng rất nhiều lần, các nhà cung cấp đang ăn thức ăn cho chó của riêng họ. Có nghĩa là, họ đang viết các trình biên dịch trong chính họ.


7

Tôi thường xuyên gặp phải lỗi biên dịch.

Bạn có thể tìm thấy chúng ở các góc tối hơn, nơi có ít người thử nghiệm hơn. Ví dụ: để tìm lỗi trong GCC, bạn nên thử:

  • Xây dựng một trình biên dịch chéo. Bạn sẽ tìm thấy hàng tá lỗi trong cấu hình và xây dựng tập lệnh của GCC. Một số kết quả trong các lỗi xây dựng trong quá trình biên dịch GCC và các kết quả khác sẽ dẫn đến thất bại của trình biên dịch chéo để xây dựng các tệp thực thi làm việc.
  • Xây dựng phiên bản Itanium của GCC bằng cách sử dụng profile-bootstrap. Vài lần cuối cùng tôi đã thử điều này trên GCC 4.4 và 4.5, nó đã thất bại trong việc tạo ra một trình xử lý ngoại lệ C ++ hoạt động. Bản dựng không được tối ưu hóa hoạt động tốt. Không ai có vẻ quan tâm đến việc sửa lỗi tôi đã báo cáo và tôi đã từ bỏ việc tự sửa nó sau khi cố gắng tìm hiểu những gì đã phá vỡ thông số kỹ thuật bộ nhớ asm GCC.
  • Hãy thử xây dựng GCJ làm việc của riêng bạn từ những thứ mới nhất mà không theo một kịch bản xây dựng phân phối. Tao thách mày.

Chúng tôi tìm thấy rất nhiều vấn đề với IA64 (Itanium). Chúng tôi không có nhiều khách hàng cho nền tảng đó, vì vậy việc cắt giảm mức tối ưu hóa là lỗi thường gặp của chúng tôi. Điều này trở lại với các câu trả lời khác, trình biên dịch cho các ngôn ngữ phổ biến cho các kiến ​​trúc phổ biến thường có đủ sự tiếp xúc của người dùng và đủ hỗ trợ để trở nên khá tốt, nhưng khi bạn đi đến các kiến ​​trúc và / hoặc ngôn ngữ ít phổ biến hơn bạn sẽ phải chịu sự tin cậy.
Omega Centauri

@Omega: Cắt giảm tối ưu hóa dường như là điều mọi người làm. Thật không may, Itanium yêu cầu trình biên dịch tối ưu hóa cao để thực hiện tốt. Ôi chà ...
Zan Lynx

Tôi nghe bạn. Thành thật mà nói, kiến ​​trúc đã lỗi thời khi nó xuất hiện, may mắn thay, AMD đã buộc Intels bắt tay với x86-64 (điều này coi thường nhiều mụn cóc của nó không quá tệ). Nếu bạn có thể chia nhỏ các tệp nguồn của mình, bạn có thể tách biệt được vấn đề là và tìm cách giải quyết. Đó là những gì chúng tôi làm nếu nó là một nền tảng quan trọng, nhưng đối với IA64 thì không.
Omega Centauri

@Omega: Thật không may, tôi thực sự thích Itanium. Đó là một kiến ​​trúc tuyệt vời. Tôi coi x86 và x86-64 là lỗi thời nhưng tất nhiên chúng sẽ không bao giờ chết.
Zan Lynx

X86 hơi lạ. Họ tiếp tục thêm những thứ mới vào nó, để nó phát triển từng mụn một. Tuy nhiên, công cụ thực thi không theo thứ tự hoạt động khá tốt và SSE => công cụ AVX mới cung cấp một số khả năng thực sự cho những người sẵn sàng viết mã cho nó. Phải thừa nhận rằng có rất nhiều bóng bán dẫn dành cho việc thực hiện các công cụ bán lỗi thời, nhưng đó là một cái giá phải trả cho sự tương thích di sản.
Omega Centauri

5

Nhiều lý do:

  • Nhà văn biên dịch " ăn thức ăn cho chó của họ ".
  • Trình biên dịch dựa trên các nguyên tắc hiểu rõ về CS.
  • Trình biên dịch được xây dựng để một spec rất rõ ràng .
  • Trình biên dịch được kiểm tra .
  • Trình biên dịch không phải lúc nào cũng rất đáng tin cậy .

4

Họ thường rất giỏi ở mức -O0. Trong thực tế nếu chúng tôi nghi ngờ một lỗi trình biên dịch, chúng tôi so sánh -O0 với bất kỳ mức nào chúng tôi đang cố gắng sử dụng. Mức tối ưu hóa cao hơn đi với rủi ro lớn hơn. Một số thậm chí còn cố tình như vậy, và được dán nhãn như vậy trong tài liệu. Tôi đã gặp rất nhiều (ít nhất là một trăm trong thời gian của tôi), nhưng gần đây chúng đang trở nên hiếm hơn. Tuy nhiên, trong việc theo đuổi các con số cụ thể tốt (hoặc các tiêu chuẩn khác quan trọng đối với tiếp thị), sự cám dỗ để đẩy các giới hạn là rất lớn. Chúng tôi đã gặp vấn đề vài năm trước khi một nhà cung cấp (không được đặt tên) quyết định vi phạm mặc định dấu ngoặc đơn - tập hợp hơn một số tùy chọn biên dịch được dán nhãn rõ ràng đặc biệt.

Thật khó để chẩn đoán lỗi trình biên dịch so với tham chiếu bộ nhớ đi lạc, biên dịch lại với các tùy chọn khác nhau có thể chỉ đơn giản là xáo trộn vị trí tương đối của các đối tượng dữ liệu trong bộ nhớ, vì vậy bạn không biết đó là Heisenorms của mã nguồn hay lỗi của bạn trình biên dịch. Ngoài ra, nhiều tối ưu hóa thực hiện các thay đổi hợp pháp theo thứ tự các thao tác hoặc thậm chí đơn giản hóa đại số cho đại số của bạn và chúng sẽ có các thuộc tính khác nhau đối với làm tròn điểm nổi và dưới / tràn. Thật khó để giải quyết các hiệu ứng này từ các lỗi THỰC SỰ. Lý do điểm nổi lõi cứng là khó khăn vì lý do này, bởi vì lỗi và độ nhạy số thường không dễ dàng để giải quyết.


4

Lỗi trình biên dịch không phải là hiếm. Trường hợp phổ biến nhất là trình biên dịch báo lỗi về mã cần được chấp nhận hoặc để trình biên dịch chấp nhận mã cần bị từ chối.


thật không may, chúng ta không thể thấy lớp lỗi thứ hai: mã biên dịch = mọi thứ đều ổn. Vì vậy, có lẽ một nửa lỗi (giả sử tỷ lệ phân chia 50-50 giữa hai lớp lỗi) không được tìm thấy bởi mọi người mà bằng các thử nghiệm đơn vị trình biên dịch
Gianluca Ghettini

3

Đúng, tôi đã gặp một lỗi trong trình biên dịch ASP.NET chỉ ngày hôm qua:

Khi bạn sử dụng các mô hình được gõ mạnh trong các khung nhìn, sẽ có giới hạn về số lượng mẫu tham số có thể chứa. Rõ ràng là nó không thể lấy nhiều hơn 4 tham số mẫu, do đó cả hai ví dụ dưới đây làm cho trình biên dịch xử lý quá nhiều:

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

Sẽ không biên dịch như là nhưng sẽ được nếu type5bị loại bỏ.

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

Sẽ biên dịch nếu type4được gỡ bỏ.

Lưu ý rằng System.Tuplecó nhiều quá tải và có thể mất tới 16 tham số (tôi biết là điên rồ).


3

Bạn đã bao giờ gặp phải một lỗi trong trình biên dịch? Nó là gì và làm thế nào bạn nhận ra vấn đề nằm ở chính trình biên dịch?

Vâng

Hai kỷ niệm đáng nhớ nhất là hai lần đầu tiên tôi từng chạy qua. Cả hai đều nằm trong trình biên dịch Lightspeed C cho máy Mac có kích thước 680x0 vào khoảng 1985-7.

Cái đầu tiên là trong trường hợp nào đó, toán tử postrrement số nguyên không làm gì cả - nói cách khác, trong một đoạn mã cụ thể, "i ++" đơn giản là không làm gì với "i". Tôi đang kéo tóc ra cho đến khi tôi nhìn vào một sự tháo gỡ. Sau đó, tôi chỉ thực hiện tăng theo một cách khác và gửi báo cáo lỗi.

Thứ hai là một chút phức tạp hơn, và thực sự là một "tính năng" bị coi là sai lầm. Những máy Mac đời đầu có một hệ thống phức tạp để thực hiện các hoạt động đĩa cấp thấp. Vì một số lý do mà tôi không bao giờ hiểu - có lẽ phải làm với việc tạo các tệp thực thi nhỏ hơn - thay vì trình biên dịch chỉ tạo các hướng dẫn hoạt động của đĩa tại chỗ trong mã đối tượng, trình biên dịch Lightspeed sẽ gọi một hàm bên trong, khi chạy tạo ra hoạt động của đĩa hướng dẫn trên ngăn xếp và nhảy ở đó.

Điều đó đã làm việc rất tốt trên 68000 CPU, nhưng khi bạn chạy cùng một mã trên CPU 68020, nó thường sẽ làm những điều kỳ lạ. Hóa ra, một tính năng mới của 68020 là bộ đệm lệnh lệnh 256 byte nguyên thủy. Đây là những ngày đầu với bộ nhớ CPU, nó không có khái niệm bộ đệm bị "bẩn" và cần phải được nạp lại; Tôi đoán các nhà thiết kế CPU tại Motorola đã không nghĩ về mã tự sửa đổi. Vì vậy, nếu bạn đã thực hiện hai thao tác đĩa gần nhau trong chuỗi thực thi của mình và thời gian chạy Lightspeed đã xây dựng các hướng dẫn thực tế tại cùng một vị trí trên ngăn xếp, CPU sẽ nhầm tưởng rằng nó có bộ đệm bộ đệm hướng dẫn và chạy hoạt động đĩa đầu tiên hai lần.

Một lần nữa, nhận ra rằng đã có một số hoạt động đào bới xung quanh với một trình dịch ngược và rất nhiều bước đơn trong một trình gỡ lỗi cấp thấp. Cách giải quyết của tôi là tiền tố mọi hoạt động của đĩa với một lệnh gọi đến một hàm đã thực hiện 256 lệnh "NOP", làm ngập (và do đó xóa) bộ đệm hướng dẫn.

Trong 25 năm kể từ đó, tôi đã thấy ngày càng ít lỗi trình biên dịch hơn theo thời gian. Tôi nghĩ rằng có một vài lý do cho việc đó:

  • Có một bộ kiểm tra xác nhận ngày càng tăng cho trình biên dịch.
  • Các trình biên dịch hiện đại thường được chia thành hai hoặc nhiều phần, một trong số đó tạo mã độc lập với nền tảng (ví dụ: nhắm mục tiêu của LLVM mà bạn có thể xem là CPU tưởng tượng) và phần khác chuyển nó thành hướng dẫn cho phần cứng đích thực tế của bạn. Trong các trình biên dịch đa nền tảng, phần đầu tiên được sử dụng ở mọi nơi, do đó, nó nhận được rất nhiều thử nghiệm trong thế giới thực.

Một trong những lý do để tránh mã tự sửa đổi.
Technophile

3

Tìm thấy một lỗi rõ ràng trong Turbo Pascal 5,5 năm trước. Một lỗi xuất hiện trong cả phiên bản (5.0) trước đó và phiên bản (6.0) tiếp theo của trình biên dịch. Và một thứ đáng lẽ phải dễ kiểm tra, vì nó hoàn toàn không phải là một cornercase (chỉ là một cuộc gọi không được sử dụng phổ biến).

Nói chung, chắc chắn các nhà xây dựng trình biên dịch thương mại (chứ không phải các dự án sở thích) sẽ có QA và quy trình thử nghiệm rất rộng rãi. Họ biết trình biên dịch của họ là các dự án hàng đầu của họ và các lỗ hổng đó sẽ trông rất tệ đối với họ, tệ hơn là họ nhìn vào các công ty khác sản xuất hầu hết các sản phẩm khác. Các nhà phát triển phần mềm là một nhóm không thể tha thứ, các nhà cung cấp công cụ của chúng tôi làm chúng tôi thất vọng, chúng tôi sẽ tìm kiếm các giải pháp thay thế thay vì chờ đợi sửa chữa từ nhà cung cấp và chúng tôi rất có thể truyền đạt thực tế đó cho các đồng nghiệp của mình, những người có thể theo dõi chúng tôi thí dụ. Trong nhiều ngành công nghiệp khác không phải như vậy, do đó, tổn thất tiềm tàng đối với nhà sản xuất trình biên dịch do lỗi nghiêm trọng lớn hơn nhiều so với nhà sản xuất phần mềm chỉnh sửa video.


2

Khi hành vi của phần mềm của bạn khác khi được biên dịch với -O0 và với -O2, thì bạn đã tìm thấy lỗi trình biên dịch.

Khi hành vi của phần mềm của bạn chỉ khác với những gì bạn mong đợi, thì rất có thể lỗi đó nằm trong mã của bạn.


8
Không cần thiết. Trong C và C ++, có một lượng khó chịu về hành vi không xác định và không xác định, và điều đó có thể thay đổi một cách hợp pháp dựa trên mức độ tối ưu hóa hoặc pha của mặt trăng hoặc chuyển động của các chỉ số Dow Jones. Bài kiểm tra đó hoạt động trong các ngôn ngữ được xác định chặt chẽ hơn.
David Thornley

2

Lỗi trình biên dịch xảy ra, nhưng bạn có xu hướng tìm thấy chúng ở các góc lẻ ...

Có một lỗi kỳ lạ trong trình biên dịch VAX VMS C của Tập đoàn Thiết bị Kỹ thuật số vào những năm 1990

(Tôi đang đeo hành tây trên thắt lưng, cũng như thời trang lúc đó)

Dấu chấm phẩy ngoại lai ở bất cứ đâu trước vòng lặp for sẽ được biên dịch thành phần thân của vòng lặp for.

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

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

Trên trình biên dịch trong câu hỏi, vòng lặp chỉ thực hiện một lần.

nó thấy

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

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

  {
     puts("hello");
  }
}

Điều đó làm tôi mất rất nhiều thời gian.

Phiên bản cũ hơn của trình biên dịch PIC C mà chúng tôi (đã từng) tạo ra cho sinh viên có kinh nghiệm làm việc không thể tạo mã sử dụng ngắt ưu tiên cao một cách chính xác. Bạn đã phải chờ 2-3 năm và nâng cấp.

Trình biên dịch MSVC 6 có một lỗi tiện lợi trong trình liên kết, nó sẽ bị lỗi phân đoạn và chết theo thời gian mà không có lý do. Một bản dựng sạch thường cố định nó (nhưng không phải lúc nào cũng thở dài ).


2

Trong một số miền, chẳng hạn như phần mềm điện tử hàng không, có các yêu cầu chứng nhận cực kỳ cao, về mã và phần cứng, cũng như trên trình biên dịch. Về phần cuối cùng này, có một dự án nhằm tạo ra một trình biên dịch C được xác minh chính thức, được gọi là Compcert . Về lý thuyết, loại trình biên dịch này đáng tin cậy như chúng đến.


1

Tôi đã thấy một số lỗi trình biên dịch, đã báo cáo một vài lỗi (cụ thể là trong F #).

Điều đó nói rằng, tôi nghĩ lỗi trình biên dịch rất hiếm vì những người viết trình biên dịch nói chung rất thoải mái với các khái niệm khắt khe của khoa học máy tính khiến họ thực sự ý thức về ý nghĩa toán học của mã.

Hầu hết trong số họ có lẽ rất quen thuộc với những thứ như tính toán lambda, xác minh chính thức, ngữ nghĩa biểu thị, v.v. - những thứ mà một lập trình viên trung bình như tôi chỉ có thể hiểu được.

Ngoài ra, thường có một ánh xạ khá đơn giản từ đầu vào đến đầu ra trong trình biên dịch, vì vậy việc gỡ lỗi một ngôn ngữ lập trình có lẽ dễ dàng hơn nhiều so với gỡ lỗi, giả sử, một công cụ blog.


1

Tôi đã tìm thấy một lỗi trong trình biên dịch C # cách đây không lâu, bạn có thể thấy Eric Lippert (người trong nhóm thiết kế C #) đã tìm ra lỗi gì ở đây .

Ngoài các câu trả lời đã được đưa ra, tôi muốn thêm một vài điều nữa. Trình thiết kế trình biên dịch thường là những lập trình viên cực kỳ giỏi. Trình biên dịch rất quan trọng: hầu hết các chương trình được thực hiện bằng trình biên dịch, do đó, trình biên dịch bắt buộc phải có chất lượng cao. Do đó, vì lợi ích tốt nhất của các công ty sản xuất trình biên dịch để đặt những người giỏi nhất của họ vào đó (hoặc ít nhất, những người rất giỏi: những người giỏi nhất có thể không thích thiết kế trình biên dịch). Microsoft rất muốn trình biên dịch C và C ++ của họ hoạt động bình thường hoặc phần còn lại của công ty không thể thực hiện công việc của họ.

Ngoài ra, nếu bạn đang xây dựng một trình biên dịch thực sự phức tạp, bạn không thể hack nó cùng nhau. Logic đằng sau trình biên dịch rất phức tạp và dễ chính thức hóa. Do đó, các chương trình này thường sẽ được xây dựng theo cách rất 'mạnh mẽ' và chung chung, có xu hướng dẫn đến ít lỗi hơn.

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.