2015-12-02 23 views
5

Tôi có ứng dụng OS X đa luồng sử dụng hỗn hợp C++, Objective-C và Swift.Cách theo dõi "libC++ abi.dylib: Hàm ảo thuần túy được gọi!" trong Xcode

Khi ứng dụng của tôi tắt, tôi thấy điều này trong cửa sổ gỡ lỗi Xcode:

libc++abi.dylib: Pure virtual function called! 

Tôi biết rằng lỗi này thường được gây ra bởi một cuộc gọi đến một hàm ảo trong một lớp C++ constructor hoặc destructor.

Có cách nào dễ dàng để tìm vị trí của nó không? Bởi "dễ dàng", tôi có nghĩa là "không phân tích cây gọi cho mỗi dòng của mọi constructor và destructor của mỗi lớp có một chức năng ảo".

Tôi không thấy dấu vết ngăn xếp. Trình gỡ rối không dừng chương trình khi thông báo này được in. Một thông báo được ghi lại từ phương thức applicationDidTerminate của đại biểu ứng dụng của bạn trước thông báo này.

Tôi đã thử thiết lập điểm ngắt trên "Tất cả ngoại lệ" nhưng tiếc là điểm ngắt được nhấn thường bằng mã sử dụng nhiều ngoại lệ. Có biểu tượng nào khác mà tôi có thể đặt điểm ngắt không?

+0

có thể xem bất kỳ lớp nào gọi phương thức ảo trong hàm hủy của nó hoặc thực sự gọi bất kỳ phương thức nào trong hàm hủy - bởi vì các phương thức đó có thể tự gọi phương thức ảo. Trong destructor của một lớp cơ sở, lớp dẫn xuất không còn tồn tại, vì vậy các cuộc gọi hàm ảo sẽ thực hiện phiên bản của lớp cơ sở. –

+0

Thông thường có một báo cáo nhật ký sự cố được tạo ra do lỗi đó là một ngoại lệ 'SIGABRT'. Trong trường hợp không có thì có thể tìm kiếm mã của bạn cho "ảo" và thiết lập các điểm ngắt của bạn trên mỗi; nó chỉ là một vấn đề của quá trình bằng cách loại bỏ. –

+1

Đặt điểm ngắt trên '__cxa_pure_virtual' –

Trả lời

3

Thư viện chuẩn C++ xác định một vài chức năng "ABI" triển khai các tính năng ngôn ngữ/thư viện cấp thấp. libc++ có tài liệu đẹp mô tả chúng here.

Một trong số đó là __cxa_pure_virtual, được gọi khi chương trình bằng cách nào đó gọi hàm thuần ảo. Vì vậy, nếu bạn thiết lập một điểm dừng ở đó, bạn sẽ có thể tìm ra nơi đang xảy ra.

Thông thường, các cuộc gọi hàm ảo thuần túy xảy ra khi bạn gọi hàm ảo từ bên trong một hàm tạo hoặc hàm hủy trong khi vtable ở trạng thái trung gian.Xem this answer để biết thêm chi tiết.

1

Đầu tiên, phần lớn có khả năng là một hàm hủy trong đó cuộc gọi đến một chức năng ảo thuần túy đang được thực hiện thay vì một hàm tạo (không được bảo đảm, nhưng có thể).

Nếu trình biên dịch của bạn tạo ra ngoại lệ khi có chức năng ảo thuần túy, bạn có thể nắm bắt nó bằng cách thiết lập trình xử lý chấm dứt của riêng bạn với set_terminate() (ví dụ: here). Sau đó, bạn có thể đặt một điểm ngắt trong trình xử lý chấm dứt của mình để xem chính xác cách mã của bạn nhận được đến thời điểm đó.

Nếu ngoại lệ không được trình biên dịch tạo ra khi chức năng ảo thuần túy được gọi (tình huống có nhiều khả năng hơn), bạn có thể thử thêm các lớp giả của riêng mình để thu hẹp vị trí xảy ra cuộc gọi vi phạm. Đơn giản chỉ cần có các lớp giả này in một cái gì đó trong destructors của họ và đảm bảo họ bị xóa vào những thời điểm giúp thu hẹp khi mọi thứ xảy ra. Ví dụ, đặt một ở đầu của hàm main() và nếu bạn thấy thông điệp của nó được in thì cuộc gọi vi phạm đang xảy ra khi các đối tượng tĩnh đang bị xóa vì đối tượng giả đó sẽ là đối tượng cuối cùng bị xóa trước khi trả về main(). Bạn có thể làm những việc tương tự bằng cách thêm các lớp giả như là thành viên dữ liệu đầu tiên của các lớp khác mà bạn có thể sửa đổi, nhưng bạn cần một số ý tưởng về các đối tượng bị xóa dẫn đến cuộc gọi hàm ảo tinh vi.

Cuối cùng, trong trường hợp nó hữu ích, bạn thực sự có thể cung cấp một triển khai cho các hàm ảo thuần túy và thực tế có thể được gọi (có, đây là C++ hợp pháp). Nếu bạn biết chính xác chức năng ảo thuần khiết đang được gọi, thì bạn có thể cung cấp một thực hiện cho nó và đặt một điểm ngắt trong đó để bắt theo dõi ngăn xếp. Điều này phụ thuộc vào bạn biết chính xác hàm ảo thuần khiết đang được gọi mặc dù câu hỏi của bạn cho thấy điều này có thể không được biết.

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