Có thể các cấp độ 256 lỗi Bug trong trò chơi Pacman có thể được coi là một segfault chưa được xử lý không?


51

Tôi đang cố gắng giải thích lỗi phân đoạn cho ai đó và tôi đã suy nghĩ về màn hình giết chết cấp 256 ở Pacman và cách nó được kích hoạt bởi tràn số nguyên và hành vi tương tự như "trạng thái không xác định" được mô tả trong phân đoạn lỗi.

Tôi muốn nói rằng đây là một ví dụ tốt về cái mà tôi gọi là "segfault chưa xử lý", nhưng tôi muốn có ý kiến ​​thứ hai trước khi tôi có khả năng truyền bá thông tin sai lệch.

Tôi đã cố gắng tìm kiếm nó, nhưng tất cả những gì tôi nhận được là các tài liệu về chính lỗi, cũng như sự hợp tác giữa Hipster Whale và Namco.

Vì vậy, bạn có coi hành vi ở cấp 256 của Pacman là một ví dụ về vi phạm phân khúc chưa được xử lý không?


3
Đây là một mô tả chính xác về lỗi, cùng với một bản vá để sửa lỗi: donhodges.com/how_high_can_you_get2.htmlm
abligh

26
Lỗi phân đoạn được nâng lên bởi phần cứng, để tránh truy cập bộ nhớ bất hợp pháp. Tôi không phải là chuyên gia về Pacman, nhưng phần cứng mà nó chạy trên gần như chắc chắn không có tính năng an toàn này để bắt đầu.
BlueRaja - Daniel Pflughoeft

3
Theo wikipedia Pacman đã sử dụng Z80. Z80 chắc chắn không có bảo vệ bộ nhớ.
Gort Robot

Đây không phải là một segfault mà hệ thống không có bất kỳ hình thức bảo vệ bộ nhớ nào. Lỗi mà Pac-Man gặp phải ở cấp 256 chỉ đơn giản là lỗi tràn số nguyên không được xử lý chính xác bởi mã của trò chơi.
bwDraco

3
FYI, tôi không nghĩ rằng điều này đủ điều kiện là một lỗi. Lỗi là lỗi hoặc lỗi trong chương trình hoặc hệ thống máy tính khiến nó tạo ra kết quả không chính xác hoặc không mong muốn hoặc hành xử theo những cách không lường trước được. Nó được cố tình lập trình theo cách đó, vì cảm thấy rằng không ai sẽ đạt đến cấp độ đó. Trong thực tế, nó chỉ là thiết kế phần mềm kém.
Keltari

Câu trả lời:


113

Chắc chắn không phải.

Truy cập địa chỉ bộ nhớ bạn không cấp phát luôn là lỗi lập trình. Và hành động dựa trên thông tin bạn nhận được từ nó tạo ra hành vi không xác định, điều đó là chính xác. Tôi không biết Pac-man ban đầu được viết cho nền tảng nào, nhưng tôi khá chắc chắn rằng nó thể hiện hành vi này giống như bất kỳ máy von Neumann nào khác.

Tuy nhiên, "lỗi phân khúc" là một thuật ngữ kỹ thuật cho một điều kiện cụ thể hơn nhiều. Nó xảy ra khi máy tính tự động phát hiện ra rằng điều này đã xảy ra và chấm dứt quá trình thay vì cho phép hành vi không xác định xảy ra. Điều này đòi hỏi một mô hình bộ nhớ (phân đoạn) cụ thể với gắn thẻ sở hữu tinh vi. Tôi không nghĩ các game arcade 1980 có điều đó, và trên thực tế, hành vi của trò chơi cho thấy rằng lỗi không được phát hiện và hành vi không xác định đã xảy ra.


19
@ B1KMusic: Bạn thực sự đang hỏi "mã này có phải là lỗi không, ví dụ về việc gọi hành vi không xác định thông qua truy cập bộ nhớ ngoài giới hạn" và câu trả lời là "có". Bất kỳ sự hợp lý hóa nào về việc bắt, bỏ qua, không nhận được tín hiệu SIGSEGV chỉ là vấn đề khó hiểu.
Cuộc đua nhẹ nhàng với Monica

5
@ B1KMusic không phải tất cả các lỗi tràn bộ đệm đều dẫn đến một segfault. Nó phụ thuộc vào cách bộ nhớ được phân bổ. Nếu bộ nhớ được cấp phát tĩnh (một bộ đệm lớn được phân chia thủ công ở các vùng khác nhau) và khu vực ngay sau mức cuối cùng được sử dụng cho một cái gì đó (như đồ họa sprite) thì nó sẽ không bị lỗi.
quái vật ratchet

6
Những hệ thống arcade cũ này đã sử dụng các hệ điều hành nguyên thủy giúp cho trò chơi kiểm soát hoàn toàn phần cứng, tương tự như các phiên bản đầu tiên của DOS. Ý tưởng về một segfault trong kiểu kiến ​​trúc đó là không bắt đầu, bởi vì nó giả định rằng một quá trình đang chạy (Pac-Man) không sở hữu tất cả bộ nhớ. Để biết thêm thông tin, người ta có thể đọc lên dự án MAME và lịch sử của nó.

20
Hành vi không xác định không phải là tài sản của máy von Neumann, nó là tài sản của C, ngôn ngữ lập trình. Các chương trình được viết bằng ngôn ngữ lắp ráp không thể thể hiện hành vi không xác định, bởi vì hành vi của các hướng dẫn ngôn ngữ lắp ráp luôn được xác định rõ (ngay cả khi kết quả đôi khi không được chỉ định).
Dietrich Epp

8
@Snowman không có lớp nào như vậy trên máy Pac-Man. Không có trình tải - trò chơi nằm trong ROM thực thi tại chỗ. Không có quản lý bộ nhớ - mọi thứ đều tĩnh. Không có "dịch vụ"; Trò chơi truy cập trực tiếp vào phần cứng và không có một byte mã nào trên hệ thống không phải là một phần của trò chơi và được viết cho trò chơi.
hobbs

38

Có vẻ như bạn đang nhầm lẫn "hành vi không xác định" và "lỗi phân khúc".

Không có thứ gọi là segfault chưa được xử lý. Một lỗi phân khúc xử lý lỗi, theo định nghĩa.

Nếu bạn không có HĐH phát hiện truy cập bộ nhớ xấu và chấm dứt quá trình để đảm bảo an toàn, thì bạn không có lỗi phân đoạn.

Nếu bất cứ điều gì, thì đây là một ví dụ khá hay về cách UB không luôn dẫn đến một segfault.


2
Nói chính xác, HĐH có thể quyết định giết (tức là không thể phục hồi) quá trình. Thay vào đó, các HĐH hiện đại thích chấm dứt nó, có thể bị bắt và xử lý, FWIW.
edmz

@black: Không phải đó là những gì tôi nói sao?
Cuộc đua nhẹ nhàng với Monica

15
Nó thậm chí có thể không phải là "hành vi không xác định". Nếu Pacman được viết trong hội đồng thuần túy, thì mã đã làm chính xác những gì nó được bảo phải làm theo cách hoàn toàn xác định. Không phải hành vi không xác định, mà chỉ là một lỗi. Như vậy, mã sẽ chạy chính xác theo cách chạy trên bất kỳ hệ thống nào có cổng hoàn hảo của chipset bên dưới.
Gort Robot

@StevenBurnap: Đó là sự thật.
Cuộc đua nhẹ nhàng với Monica

@black Sự khác biệt giữa 'giết' và 'chấm dứt' là gì? Khác với thực tế là 'kill' thường là từ vựng UNIX và 'chấm dứt' là Windows-y hơn?
Brandin

24

Cả hai thuật ngữ này đều không phù hợp với một lỗi trong trò chơi arcade được lập trình bằng ngôn ngữ lắp ráp và chạy mà không có lợi cho phần cứng hoặc hệ điều hành bảo vệ bộ nhớ.

"Hành vi không xác định" là một thuật ngữ nghệ thuật trong C và các ngôn ngữ liên quan, được đưa ra bởi ủy ban tiêu chuẩn C vào năm 1989. Mã có hành vi không xác định khi đặc tả ngôn ngữ không xác định những gì nó sẽ làm. Không có điều đó trong ngôn ngữ lắp ráp Z80: hiệu ứng của mọi opcode với mọi đầu vào có thể được xác định rõ. Có thể đọc nghĩa tiếng Anh thông thường của "hành vi không xác định" - màn hình giết người là hành vi không được xác định bởi những người đã viết trò chơi - nhưng tôi sẽ không sử dụng nó trong ngữ cảnh này vì nó quá có khả năng đưa ra sai ấn tượng.

"Lỗi phân đoạn" là một thuật ngữ nghệ thuật trong POSIX, cuối cùng xuất phát từ thuật ngữ lập trình hệ thống PDP. Lỗi phân đoạn xảy ra khi chương trình cố gắng truy cập địa chỉ bộ nhớ không được "ánh xạ" vào bất cứ thứ gì: phần cứng và hệ điều hành phát hiện điều này và tắt chương trình bị hỏng, theo cách được xác định cẩn thận cho phép chương trình có cơ hội phục hồi . Một cái gì đó nhưđiều này có thể xảy ra do lỗi trong chương trình trò chơi Pac-Man, bởi vì bảng mạch Pac-Man chỉ chiếm ít hơn một nửa không gian địa chỉ 64kB của Z80 với ROM, RAM và các thiết bị ngoại vi, nhưng tôi không biết Không thể tìm ra phần cứng thực sự sẽ làm gì nếu phần mềm cố truy cập vào bộ nhớ chưa được khai thác. Dù vậy, dù làm gì đi nữa, sẽ không phù hợp khi mô tả là "lỗi phân khúc", bởi vì "hệ điều hành" cho Pac-Man (đến mức nó thậm chí còn ) không phải là một triển khai của Unix và, một lần nữa, nó sẽ cho ấn tượng sai.

Lỗi cấp 256, trong khi đó, không truy cập vào bộ nhớ chưa được xử lý, vì vậy nó không còn nữa.

Thật chính xác khi nói rằng trò chơi có một lỗi xuất hiện khi tiến lên cấp 256. Cũng chính xác khi nói rằng nguyên nhân gốc của lỗi là do tràn số nguyên và hậu quả của nó là hỏng bộ nhớ (hoặc, tương đương, vi phạm của bộ nhớ và loại an toàn ). Đây là tất cả các thuật ngữ CS có mục đích chung được xác định mà không cần tham chiếu đến bất kỳ ngôn ngữ hoặc môi trường HĐH cụ thể nào.

Cũng chính xác khi quan sát rằng các tác động của lỗi tương tự như các hiệu ứng, trong một môi trường hiện đại, các lỗi tham nhũng bộ nhớ không gây ra lỗi phân đoạn. Nếu bạn đọc bất kỳ bài viết khai thác Project Zero nào, bạn sẽ thấy sự tương đồng đáng chú ý với phân tích của Don Hodges về màn hình tiêu diệt Pac-Man .

Lưu ý rằng trình giả lập không tái tạo một cách trung thực màn hình kill khi được cung cấp ROM Pac-Man không mô phỏng chính xác phần cứng trò chơi.


Cụm từ "hành vi không xác định" có thể không được sử dụng trong in ấn theo cách chính xác đó trước năm 1989, nhưng ý tưởng mà cụm từ đó mô tả cũng cũ như chính lập trình. Lisp thông thường: Ngôn ngữ (Báo chí kỹ thuật số, 1984; ISBN 0-932376-41-X) đã sử dụng các từ "đó là một lỗi" để có nghĩa chính xác cùng một điều. Ví dụ: "Lỗi khi gọi hàm này với x <0" có nghĩa là lập trình viên không nên cho phép hàm được gọi với x <0 và, việc triển khai được phép thực hiện bất cứ điều gì theo nghĩa đen mà người triển khai muốn nó làm nếu lập trình viên ứng dụng đã không tuân thủ.
Solomon chậm

5
@jameslarge Tôi hiểu ý của bạn, nhưng tôi vẫn nghĩ rằng việc áp dụng khái niệm này cho Pac-Man là một sai lầm. Chúng ta có thể nói rằng màn hình kill là một lỗi vì trò chơi rõ ràng không hoạt động như nhà thiết kế dự định. Chúng tôi không thể nói rằng trò chơi đã kích động hành vi không xác định , bởi vì không có thông số ngôn ngữ nào để nói "trong mọi trường hợp, lập trình viên có thể làm X" cho bất kỳ giá trị nào của X. (Tôi cho rằng việc sử dụng các mã opp không có giấy tờ Z80 có thể đủ điều kiện, ngoại trừ rất nhiều game arcade đã sử dụng chúng và AFAIK tất cả chúng đều có hiệu ứng có thể dự đoán được.)
zwol

1
Đây là câu trả lời tốt nhất. "Hành vi không xác định" có nghĩa là người viết mã đã viết mã mà kết quả không thể được báo trước dựa trên tiêu chuẩn. Nếu Pacman được viết trong hội đồng Z80 (và tôi tin là vậy) thì mã được viết có ý nghĩa hoàn toàn được xác định bất kể chương trình có làm điều gì đó mà người viết mã không có ý định hay không.
Gort Robot

8

Lỗi cấp độ 256 trong Pac Man dẫn đến dữ liệu đọc chương trình nằm ngoài cuối bảng dự định, nhưng vẫnbộ nhớ có thể đọc được và ghi vào các phần của màn hình nằm ngoài những phần mà chương trình dự định viết, nhưng vẫn còn trong các khu vực của màn hình mà chương trình được phép viết . Không có khu vực khác của bộ nhớ bị ảnh hưởng.

Lý do lỗi khiến trò chơi không thể chơi được là do máy xác định khi nào người chơi đang ăn chấm bằng cách kiểm tra những gì trên màn hình và quyết định rằng một cấp độ đã hoàn thành khi người chơi đã ăn 244 chấm. Bằng cách ghi đè lên một phần của màn hình, lỗi khiến người chơi không thể ăn được 244 chấm; do đó, trò chơi sẽ không bao giờ ghi có cho người chơi hoàn thành cấp độ và tải lại màn hình bằng dấu chấm.


1
Khi bạn tự sát ở cấp 256, dấu chấm hồi sinh, nhưng bạn không mất gì cả.
Ave

@ardaozkal: Thói quen vẽ cấp độ xóa hơn 100 dấu chấm và vẽ một vài điểm. Nếu một người chơi có đủ sinh mạng, cuối cùng có thể ăn đủ số chấm để tăng cấp, nhưng điều đó sẽ cần hơn 30 mạng.
supercat

Tôi nhớ đã xem một video mà người chơi có đủ cuộc sống và anh ta đã quản lý nó ... và tôi chỉ tìm thấy nó .
Ave

@ardaozkal: Cần bao nhiêu sinh mạng để xóa cấp độ và bao nhiêu sinh mạng người chơi có thể có được trên một cỗ máy không được sửa đổi ?
supercat

Bạn thậm chí không thể đạt cấp 256 trên một máy chưa sửa đổi.
Ave

1

Như đã nói trước đây không phải là lỗi seg. Tôi sẽ thêm lý do tại sao vấn đề xảy ra: đó là một tràn .

Số cấp được lưu trữ trên một byte nên phạm vi là 0-255. Mỗi khi bạn hoàn thành một cấp độ, bộ đếm được tăng lên. Ở cấp 256, bộ đếm thực tế là 0 do tràn.

Tuy nhiên, trò chơi cố gắng hiển thị một số trái cây ở dưới cùng của cấp độ. Số lượng / loại trái cây phụ thuộc vào cấp độ. Công thức hiển thị một quả cho mỗi cấp độ đã hoàn thành dưới cấp 8. Theo bộ đếm bạn đang ở cấp 0 nên dưới 8. Thử nghiệm là đúng sau đó và bạn phải in 255 trái cây (giá trị cấp độ cũ). Điều này là không thể và cho màn hình bị rối này.

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.