2016-05-25 17 views
8

Trong mã được hiển thị bên dưới, tôi đã sử dụng tất cả các cách được tài liệu để phát hiện một ngoại lệ và đưa ra chẩn đoán. Nó sử dụng các từ khóa cố gắng/bắt C++, bắt một ngoại lệ SEH với các từ khóa mở rộng __try/__catch, sử dụng các hàm winapi AddVectoredExceptionHandler() và SetUnhandledExceptionFilter() của Windows để cài đặt các bộ lọc VEH/SEH.Làm thế nào để báo cáo tràn bộ đệm ngăn xếp trên Windows?

Chạy ứng dụng này bằng Visual C++ 2003:
/GS: kết quả đầu ra "hello, world!" và chấm dứt bằng mã thoát 0.
/GS-: kết quả đầu ra "hello, world!" và kết thúc với mã thoát 0.

Chạy này với Visual C++ 2013:
/GS: không có đầu ra, chấm dứt với mã thoát -1073740791
/GS-: "hello, world" đầu ra và chấm dứt với lối ra với 0.

Làm cách nào để tạo chẩn đoán trong chương trình biên soạn VS2013 với/GS có hiệu lực?

#include "stdafx.h" 
#include <Windows.h> 

#define CALL_FIRST 1 
#define CALL_LAST 0 

LONG WINAPI MyVectoredHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) 
{ 
    UNREFERENCED_PARAMETER(ExceptionInfo); 

    printf("MyVectoredHandler\n"); 
    return EXCEPTION_CONTINUE_SEARCH; 
} 

LONG WINAPI MyUnhandledExceptionFilter(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo) 
{ 
    printf("SetUnhandledExceptionFilter\n"); 

    return EXCEPTION_CONTINUE_SEARCH; 
} 

void f() 
{ 
    __try 
    { 
     char p[20] = "hello,world!"; 
     p[24] = '!'; 
     printf("%s\n", p); 
    } 
    __except (EXCEPTION_EXECUTE_HANDLER) 
    { 
     printf("f() exception\n"); 
    } 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    AddVectoredExceptionHandler(CALL_FIRST, MyVectoredHandler); 
    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); 

    try{ 
     f(); 
    } 
    catch (...){ 
     printf("catched f exception\n"); 
    } 
    return 0; 
} 
+0

Mã của bạn gây ra hành vi không xác định. Cách đáng tin cậy duy nhất để "phát hiện" là kiểm tra giới hạn trước khi thực hiện truy cập ngoài giới hạn –

+1

... chẳng hạn như những gì sẽ được thực hiện nếu bạn đã sử dụng loại vùng chứa phát hiện. ví dụ. sử dụng 'std :: string' cho chuỗi và lập chỉ mục nó bằng hàm thành viên' at'. – Hurkyl

+0

Vượt quá mức ngăn xếp khó phát hiện. Chúng chỉ kích hoạt khi bạn ghi đè lên khung ngăn xếp. Thử chuyển sang ngoại lệ thời gian chạy * Vượt quá giới hạn mảng *. Nó có thể hoạt động. – cup

Trả lời

4

Chức năng CRT xử lý phát hiện tràn bộ đệm ngăn xếp, __report_gsfailure(), giả định rằng tham nhũng khung ngăn xếp đã được gây ra bởi một cuộc tấn công phần mềm độc hại. Phần mềm độc hại theo truyền thống đã bị rối loạn với fs: [0] Bộ lọc ngoại lệ SEH (được lưu trữ trên khung ngăn xếp) để có được trình xử lý ngoại lệ để kích hoạt tải trọng phần mềm độc hại. Một trong những cách để lấy dữ liệu để biến thành mã thực thi.

Vì vậy, chức năng CRT không thể giả định rằng việc ném một ngoại lệ là an toàn để thực hiện. Và không còn trong CRT đi kèm với VS2013, quay trở lại ~ VS2005. Nó sẽ thất bại nếu hệ điều hành hỗ trợ nó và, nếu không, đảm bảo rằng một trình xử lý ngoại lệ VEH/SEH đã đăng ký cũng không thể thấy ngoại lệ. Kaboom, gặp sự cố với máy tính để bàn không có chẩn đoán trừ khi bạn đã đính kèm trình gỡ rối.

Tùy chọn/SAFESEH đánh bại loại tấn công phần mềm độc hại này để nó không nghiêm trọng như trước đây. Nếu bạn vẫn còn ở giai đoạn mà mã của bạn bị ngăn xếp lỗi tham nhũng và ứng dụng của bạn không đủ phổ biến để trở thành mục tiêu của phần mềm độc hại thì việc thay thế hàm CRT là điều bạn có thể cân nhắc.

Hãy nói chuyện này với người giám sát của bạn, bạn không bao giờ muốn chịu trách nhiệm cá nhân về điều này do trách nhiệm rất lớn cho khách hàng của bạn. Lịch sử hiếm khi kể câu chuyện về những gì đã xảy ra với một lập trình viên có mã đặt toàn bộ công ty ra khỏi doanh nghiệp trong một tháng. Nhưng chắc chắn không phải là thứ đẹp đẽ.

Dán mã này ở đâu đó gần() chức năng chính của bạn:

__declspec(noreturn) extern "C" 
void __cdecl __report_gsfailure() { 
    RaiseException(STATUS_STACK_BUFFER_OVERRUN, EXCEPTION_NONCONTINUABLE, 0, nullptr); 
} 

Và kế hoạch để loại bỏ nó một lần nữa sớm.

+0

Liên kết không thành công khi thêm __report_gsfailure tùy chỉnh: lỗi LNK2005: ___report_gsfailure 已经 在 LIBCMT.lib (gs_report.obj) 中 定义 – liuaifu

+1

Hmm, đây là mã được kiểm tra, đã xác minh nó hoạt động trên VS2015. Không biết văn bản Trung Quốc nói gì, có mùi như gs_report.obj đã được một thư viện khác kéo vào để bây giờ có hai. Sử dụng tùy chọn của liên kết/VERBOSE để tìm hiểu lý do tại sao gs_report.obj được sử dụng. Và mạnh mẽ, * mạnh mẽ * ủng hộ xây dựng với/MD thay vì/MT. –

+0

Cảm ơn giải pháp này. Theo những phát hiện của tôi, msvcrtd cũng kéo trong một __report_gsfailure khác vì vậy điều này chỉ hoạt động trong bản dựng. –

3

Không có giải pháp cho câu hỏi được hỏi.

Làm tràn một mảng gây ra hành vi không xác định trong tiêu chuẩn C++, do đó không có kết quả cụ thể nào được đảm bảo. Thất bại trong việc đưa ra một kết quả đáng tin cậy không phải là một vấn đề với trình biên dịch - đó là hành vi được phép.

Tôi biết không có triển khai nào đảm bảo bất kỳ hành vi cụ thể nào để đáp ứng với sự tràn ngập - VS chắc chắn không. Đó là hầu như không đáng ngạc nhiên như trình biên dịch không bắt buộc phải làm điều đó (đó là, về cơ bản, ý nghĩa của hành vi không xác định). Lý do là vì thường khó phát hiện các sự cố như vậy một cách đáng tin cậy hoặc nhất quán. Điều này có nghĩa là cách nhất quán duy nhất để phát hiện lỗi tràn bộ là kiểm tra chỉ mục mảng hợp lệ TRƯỚC KHI sử dụng chúng để truy cập phần tử mảng và thực hiện hành động thích hợp (vd: ném ngoại lệ có thể bị bắt thay vì thực hiện thao tác xấu).). Nhược điểm là nó không cung cấp một cách đơn giản hoặc đáng tin cậy để bắt lỗi trong mã tùy ý - thiếu sửa đổi tất cả mã để thực hiện các kiểm tra bắt buộc.

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