Thí dụ
int *ptr;
*ptr = 1000;
Tôi có thể bắt ngoại lệ vi phạm quyền truy cập bộ nhớ bằng cách sử dụng C ++ tiêu chuẩn mà không sử dụng bất kỳ phần mềm microsoft cụ thể nào không.
Câu trả lời:
Không. C ++ không đưa ra một ngoại lệ khi bạn làm điều gì đó tồi tệ, điều đó sẽ dẫn đến một cú đánh hiệu suất. Những thứ như vi phạm quyền truy cập hoặc lỗi chia cho 0 giống như ngoại lệ "máy" hơn là những thứ ở cấp độ ngôn ngữ mà bạn có thể bắt gặp.
Đọc nó và khóc!
Tôi đã hiểu rồi. Nếu bạn không ném từ trình xử lý, trình xử lý sẽ tiếp tục và ngoại lệ cũng vậy.
Điều kỳ diệu xảy ra khi bạn ném ngoại lệ của mình và xử lý điều đó.
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>
void SignalHandler(int signal)
{
printf("Signal %d",signal);
throw "!Access Violation!";
}
int main()
{
typedef void (*SignalHandlerPointer)(int);
SignalHandlerPointer previousHandler;
previousHandler = signal(SIGSEGV , SignalHandler);
try{
*(int *) 0 = 0;// Baaaaaaad thing that should never be caught. You should write good code in the first place.
}
catch(char *e)
{
printf("Exception Caught: %s\n",e);
}
printf("Now we continue, unhindered, like the abomination never happened. (I am an EVIL genius)\n");
printf("But please kids, DONT TRY THIS AT HOME ;)\n");
}
sigaltstack
cài đặt bất kỳ ngăn xếp tín hiệu thay thế nào ( ) (trừ khi việc triển khai xử lý ngoại lệ C ++ cho phép nó) và mọi hàm thời gian chạy xử lý chính cơ chế tháo cuộn phải an toàn về tín hiệu.
signal(SIGSEGV, SIG_DFL);
Có một cách rất dễ dàng để bắt bất kỳ loại ngoại lệ nào (chia cho không, vi phạm quyền truy cập, v.v.) trong Visual Studio bằng cách sử dụng khối try -> catch (...). Một điều chỉnh cài đặt dự án nhỏ là đủ. Chỉ cần bật tùy chọn / EHa trong cài đặt dự án. Xem Thuộc tính dự án -> C / C ++ -> Tạo mã -> Sửa đổi Kích hoạt ngoại lệ C ++ thành "Có với ngoại lệ SEH" . Đó là nó!
Xem chi tiết tại đây: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx
Ít nhất đối với tôi, signal(SIGSEGV ...)
cách tiếp cận được đề cập trong một câu trả lời khác không hoạt động trên Win32 với Visual C ++ 2015 . Những gì đã làm việc cho tôi là sử dụng _set_se_translator()
tìm thấy trong eh.h
. Nó hoạt động như thế này:
Bước 1 ) Đảm bảo bạn bật Có với Ngoại lệ SEH (/ EHa) trong Thuộc tính dự án / C ++ / Tạo mã / Kích hoạt ngoại lệ C ++ , như đã đề cập trong câu trả lời của Volodymyr Frytskyy .
Bước 2 ) Gọi _set_se_translator()
, truyền con trỏ hàm (hoặc lambda) cho trình dịch ngoại lệ mới . Nó được gọi là trình dịch vì về cơ bản nó chỉ lấy ngoại lệ cấp thấp và ném lại nó như một thứ dễ bắt hơn, chẳng hạn như std::exception
:
#include <string>
#include <eh.h>
// Be sure to enable "Yes with SEH Exceptions (/EHa)" in C++ / Code Generation;
_set_se_translator([](unsigned int u, EXCEPTION_POINTERS *pExp) {
std::string error = "SE Exception: ";
switch (u) {
case 0xC0000005:
error += "Access Violation";
break;
default:
char result[11];
sprintf_s(result, 11, "0x%08X", u);
error += result;
};
throw std::exception(error.c_str());
});
Bước 3 ) Bắt ngoại lệ như bạn thường làm:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
Loại tình huống này phụ thuộc vào việc triển khai và do đó nó sẽ yêu cầu một cơ chế cụ thể của nhà cung cấp để mắc bẫy. Với Microsoft, điều này sẽ liên quan đến SEH và * nix sẽ liên quan đến một tín hiệu
Nói chung, mặc dù bắt một ngoại lệ Vi phạm quyền truy cập là một ý tưởng rất tồi. Hầu như không có cách nào để khôi phục từ một ngoại lệ AV và cố gắng làm như vậy sẽ chỉ dẫn đến việc khó tìm thấy lỗi hơn trong chương trình của bạn.
Như đã nêu, không có cách nào không phải của Microsoft / nhà cung cấp trình biên dịch để thực hiện việc này trên nền tảng windows. Tuy nhiên, rõ ràng là hữu ích khi bắt các loại ngoại lệ này theo cách thông thường, hãy thử {} catch (exception ex) {} để báo lỗi và hơn thế nữa là thoát ứng dụng của bạn một cách dễ dàng (như JaredPar nói, ứng dụng hiện có thể đang gặp sự cố) . Chúng tôi sử dụng _se_translator_ Chức năng trong một trình bao bọc lớp đơn giản cho phép chúng tôi nắm bắt các ngoại lệ sau trong trình xử lý thử aa:
DECLARE_EXCEPTION_CLASS(datatype_misalignment)
DECLARE_EXCEPTION_CLASS(breakpoint)
DECLARE_EXCEPTION_CLASS(single_step)
DECLARE_EXCEPTION_CLASS(array_bounds_exceeded)
DECLARE_EXCEPTION_CLASS(flt_denormal_operand)
DECLARE_EXCEPTION_CLASS(flt_divide_by_zero)
DECLARE_EXCEPTION_CLASS(flt_inexact_result)
DECLARE_EXCEPTION_CLASS(flt_invalid_operation)
DECLARE_EXCEPTION_CLASS(flt_overflow)
DECLARE_EXCEPTION_CLASS(flt_stack_check)
DECLARE_EXCEPTION_CLASS(flt_underflow)
DECLARE_EXCEPTION_CLASS(int_divide_by_zero)
DECLARE_EXCEPTION_CLASS(int_overflow)
DECLARE_EXCEPTION_CLASS(priv_instruction)
DECLARE_EXCEPTION_CLASS(in_page_error)
DECLARE_EXCEPTION_CLASS(illegal_instruction)
DECLARE_EXCEPTION_CLASS(noncontinuable_exception)
DECLARE_EXCEPTION_CLASS(stack_overflow)
DECLARE_EXCEPTION_CLASS(invalid_disposition)
DECLARE_EXCEPTION_CLASS(guard_page)
DECLARE_EXCEPTION_CLASS(invalid_handle)
DECLARE_EXCEPTION_CLASS(microsoft_cpp)
Lớp học ban đầu đến từ bài viết rất hữu ích này:
Không phải là cơ chế xử lý ngoại lệ, nhưng bạn có thể sử dụng cơ chế signal () được cung cấp bởi C.
> man signal
11 SIGSEGV create core image segmentation violation
Ghi vào con trỏ NULL có thể gây ra tín hiệu SIGSEGV
signal()
là một phần của tiêu chuẩn posix. Cửa sổ cụ tiêu chuẩn POSIX (cũng như Linux và Unix)
Một vi phạm như vậy có nghĩa là có điều gì đó sai nghiêm trọng với mã và nó không đáng tin cậy. Tôi có thể thấy rằng một chương trình có thể muốn cố gắng lưu dữ liệu của người dùng theo cách mà người ta hy vọng sẽ không ghi đè lên dữ liệu trước đó, với hy vọng rằng dữ liệu của người dùng chưa bị hỏng, nhưng theo định nghĩa thì không có phương pháp chuẩn đối phó với hành vi không xác định.