2012-01-23 30 views
12

Tôi đang viết một thư viện nhỏ có con trỏ FILE * làm đầu vào.Thư viện của tôi có nên xử lý SIGSEGV trên đầu vào con trỏ không?

Nếu tôi ngay lập tức kiểm tra con trỏ FILE * này và tìm thấy nó dẫn đến một segfault, nó là chính xác hơn để xử lý tín hiệu, thiết lập errno, và thoát ra duyên dáng; hoặc không làm gì và sử dụng trình xử lý tín hiệu được cài đặt của người gọi, nếu anh ta có?

Sự khôn ngoan hiện tại có vẻ là "thư viện không bao giờ nên gây ra sự cố". Nhưng suy nghĩ của tôi là, vì tín hiệu đặc biệt này chắc chắn là lỗi của người gọi, nên tôi không nên cố giấu thông tin đó khỏi anh ta. Anh ta có thể có trình xử lý riêng của mình được cài đặt để phản ứng với vấn đề theo cách riêng của mình. Cùng một thông tin có thể được lấy với errno, nhưng việc định vị mặc định cho SIGSEGV được thiết lập vì một lý do chính đáng, và chuyển tín hiệu lên tôn trọng triết lý này bằng cách buộc người gọi phải xử lý lỗi của mình hoặc bằng cách đâm và bảo vệ anh ta khỏi bị hư hại thêm. .

Bạn có đồng ý với phân tích này hay bạn thấy một số lý do thuyết phục để xử lý SIGSEGV trong trường hợp này?

+2

Thư viện chuẩn C AFAIK không xử lý sự cố bên trong, tại sao lib của bạn nên? Tuy nhiên tôi đoán nó phụ thuộc vào những gì bạn đang lập kế hoạch để làm với lib của bạn. (Làm thế nào để kiểm tra trên một FILE * dẫn đến một SIGSEV btw? Chỉ cần tò mò) – BigMike

Trả lời

7

Tiếp quản công cụ xử lý không phải là hoạt động kinh doanh thư viện, tôi cho rằng nó có phần gây khó chịu cho họ trừ khi được yêu cầu rõ ràng. Để giảm thiểu thư viện sự cố có thể xác thực đầu vào của họ ở một mức độ nhất định. Ngoài ra: rác trong - rác ra.

+0

+1 để nói rằng nó gây khó chịu –

5

Sự khôn ngoan hiện tại có vẻ là "thư viện không bao giờ nên gây ra sự cố".

Tôi không biết bạn nhận được từ đâu - nếu họ vượt qua con trỏ không hợp lệ, bạn sẽ gặp sự cố. Bất kỳ thư viện nào cũng được.

+0

Điều thú vị là, trong khi tuyên bố của bạn là đúng cho phần lớn các chức năng, có một số trường hợp ngoại lệ. Ví dụ, viết và getline sẽ bỏ với EBADF và EINVAL, tương ứng. – User123abc

+0

Xin lỗi, đó là EFAULT để viết, mặc dù nó cũng thực hiện kiểm tra EBADF. – User123abc

+0

@ User123abc, bạn có chắc là bạn đang nói về bất kỳ con trỏ không hợp lệ nào, không chỉ là con trỏ null? –

2

Đây là một câu hỏi chủ quan, và có thể không phù hợp cho SO, nhưng tôi sẽ trình bày quan điểm của tôi:

Hãy suy nghĩ về nó theo cách này: Nếu bạn có một chức năng mà phải mất một nul-chấm dứt char * chuỗi và được ghi chép lại như vậy, và người gọi đi qua một chuỗi mà không có terminator nul, bạn nên bắt tín hiệu và tát người gọi trên cổ tay? Hoặc bạn nên để nó sụp đổ và làm cho lập trình viên xấu sử dụng API của bạn sửa mã của họ?

Nếu mã của bạn có con trỏ là FILE * và tài liệu của bạn cho biết "chuyển bất kỳ số mở FILE *" nào và chúng vượt qua một đối tượng đóng hoặc không hợp lệ FILE *, chúng đã phá vỡ hợp đồng. Việc kiểm tra trường hợp này sẽ làm chậm mã của những người sử dụng thư viện của bạn để thích ứng với những người không thích hợp, trong khi để cho nó sụp đổ sẽ giữ mã càng nhanh càng tốt cho những người đọc tài liệu và viết mã tốt.

Bạn có mong đợi ai đó vượt qua con trỏ FILE * không hợp lệ để kiểm tra và xử lý đúng lỗi không? Hoặc là họ có nhiều khả năng để thực hiện một cách mù quáng, gây ra một vụ tai nạn sau này, trong trường hợp xử lý vụ tai nạn này chỉ có thể ngụy trang lỗi?

+1

Hơn nữa không có lý do gì để mong đợi rằng thậm chí có thể bắt được trường hợp của một 'FILE *' không hợp lệ được chuyển. Nó hoàn toàn phụ thuộc vào việc thực hiện của hệ thống và hành vi nội bộ. Một 'FILE *' không hợp lệ có thể dễ dàng "làm việc" nhưng làm điều gì đó hoàn toàn không có thật, thậm chí làm hỏng mã thư viện của bạn và ngăn các kiểm tra của nó hoạt động (trên một hệ thống không có bảo vệ bộ nhớ). –

3

Tôi sẽ xem xét việc kiểm tra trường hợp đặc biệt của con trỏ NULL là hợp lý. Nhưng ngoài ra, nếu họ vượt qua rác, họ đã vi phạm hợp đồng của chức năng và họ gặp tai nạn.

1

Hạt nhân không bị lỗi nếu bạn cho chúng trỏ chuột xấu, nhưng các thư viện có thể nên. Điều đó không có nghĩa là bạn không nên kiểm tra lỗi; một chương trình tốt sẽ chết ngay khi đối mặt với dữ liệu không hợp lý. Tôi muốn nhiều hơn một thư viện gọi bảo lãnh với khẳng định (f! = NULL) hơn là chỉ trundle trên và cuối cùng dereference con trỏ NULL.

0

Xin lỗi, nhưng những người nói thư viện sẽ bị lỗi chỉ là lười biếng (có lẽ trong thời gian xem xét, cũng như nỗ lực phát triển). Thư viện là tập hợp các hàm. Mã thư viện không nên "chỉ sụp đổ" hơn bất kỳ chức năng nào khác trong phần mềm của bạn nên "chỉ bị lỗi". Được cấp, thư viện có thể có một số vấn đề xung quanh cách vượt qua các lỗi trên ranh giới API, nếu nhiều ngôn ngữ hoặc (tương đối) các tính năng ngoại ngữ như ngoại lệ thường được tham gia, nhưng không có gì TOO đặc biệt về điều đó. Thực sự, nó chỉ là một phần của gánh nặng viết thư viện, trái với mã trong ứng dụng. Trừ khi bạn thực sự không thể biện minh cho chi phí, mọi giao diện giữa các hệ thống sẽ thực hiện kiểm tra sanity, hoặc tốt hơn, được thiết kế theo hợp đồng, để ngăn chặn các vấn đề bảo mật cũng như lỗi.

Có một số cách để xử lý việc này, Những gì bạn có lẽ nên làm, trong thứ tự ưu tiên, là một trong số:

  1. Sử dụng một ngôn ngữ hỗ trợ trường hợp ngoại lệ (hoặc tốt hơn, thiết kế theo hợp đồng) trong thư viện, và ném một ngoại lệ hoặc cho phép hợp đồng thất bại.

  2. Cung cấp lỗi xử lý tín hiệu/khe hoặc móc/cơ chế gọi lại và gọi bất kỳ trình xử lý đã đăng ký nào. Yêu cầu, khi thư viện của bạn được khởi tạo, ít nhất một trình xử lý lỗi được đăng ký.

  3. Hỗ trợ trả về một số mã lỗi trong mọi chức năng có thể bị lỗi, vì bất kỳ lý do nào. Nhưng đây là cách cũ, tương đối điên rồ khi làm những việc từ C (trái ngược với C++) ngày.

  4. Đặt một số "lỗi đã xảy ra" trên toàn cầu và cho phép xóa cờ đó trước cuộc gọi. Đây cũng là cũ, và hoàn toàn điên, chủ yếu là vì nó di chuyển gánh nặng duy trì trạng thái lỗi cho người gọi VÀ không an toàn khi nói đến luồng.

Các vấn đề liên quan