Cách dễ nhất để làm cho một chương trình C ++ sụp đổ là gì?


318

Tôi đang cố gắng tạo một chương trình Python có giao diện với một quy trình khác nhau (điều đó nằm ngoài tầm tay của tôi). Thật không may, chương trình tôi đang can thiệp thậm chí không sụp đổ đáng tin cậy! Vì vậy, tôi muốn tạo một chương trình C ++ nhanh chóng gặp sự cố nhưng tôi thực sự không biết cách tốt nhất và ngắn nhất để làm điều đó, có ai biết phải đặt gì giữa tôi không:

int main() {
    crashyCodeGoesHere();
}

để làm cho chương trình C ++ của tôi bị sập một cách đáng tin cậy


4
bạn có thể sử dụng lắp ráp nội tuyến để cố gắng thực hiện các hướng dẫn được asm { cli; };
ủy quyền

@aitchnyu Tôi nghĩ có sự khác biệt về khả năng sử dụng câu trả lời cho mỗi câu hỏi. (FYI: Tôi đã không bỏ phiếu bất cứ điều gì cho một trong hai câu hỏi)
Andrew Barber

bất kỳ bình luận về ném ngoại lệ trong khi một người đã ủng hộ ?? Xin vui lòng trả lời của tôi dưới bình luận anc
Abhinav

4
Redis sử dụng *((char*)-1) = 'x';đoạn mã sau để gây ra sự cố để gỡ lỗi đọc thêm trong câu trả lời
Shafik Yaghmour

Tôi tìm thấy câu hỏi này để tìm kiếm một trường hợp thử nghiệm cho một hệ thống báo cáo sự cố. Tôi cần phải thực hiện một sự cố trong thời gian chạy bình thường để gọi trình báo cáo sự cố và gửi kết xuất. Cảm ơn!
Cory Trese 7/10/2016

Câu trả lời:


264

Các abort()chức năng có lẽ là đặt cược tốt nhất của bạn. Đây là một phần của thư viện chuẩn C và được định nghĩa là "gây ra sự chấm dứt chương trình bất thường" (ví dụ: lỗi nghiêm trọng hoặc sự cố).


14
Lưu ý rằng một sự cố thông qua abort()không gọi bất kỳ atexithàm hủy hoặc hàm nào, mặc dù điều đó có thể sẽ không quan trọng ở đây.
Xèo

139
@Xeo: Nếu nó đã gọi tàu khu trục và atexits, bây giờ nó sẽ không phải là một vụ tai nạn phải không?
Donal Fellows

abort()là câu trả lời đúng, nên 'exit (-1); `có được chấp nhận không?
asir6

9
Không, vì nó không gây ra sự cố, chỉ đơn thuần là báo cáo một cái gì đó không thể được thực hiện.
thuyền viên

Các cửa sổ. GCC-5.4.0. Mã thoát: 3. Không có hộp thông báo lỗi. Thông báo trên bảng điều khiển: "Ứng dụng này đã yêu cầu Runtime chấm dứt nó theo cách khác thường. Vui lòng liên hệ với nhóm hỗ trợ của ứng dụng để biết thêm thông tin."
Vadzim

113

Thử:

raise(SIGSEGV);  // simulates a standard crash when access invalid memory
                 // ie anything that can go wrong with pointers.

Tìm thấy trong:

#include <signal.h>

3
Đó không chỉ là định nghĩa thực hiện - tín hiệu có thể được bắt với signal(). Hầu hết các ứng dụng lành mạnh không, mặc dù.
duskwuff -inactive-

12
Nó sẽ sập theo cách chính xác giống như một SIGSEGV bình thường trong ứng dụng (đó là cách mà hầu hết các ứng dụng gặp sự cố). Nó được xác định rõ những gì nó làm (theo mặc định, nó thoát khỏi ứng dụng và tạo một tệp lõi). Có, bạn có thể thiết lập trình xử lý, nhưng nếu bạn không muốn kiểm tra điều đó theo cùng một cách !!
Martin York

1
+1 cho raise(). Điều này cho phép bạn kiểm tra hàng tấn các loại ngoại lệ khác nhau bằng cách chỉ thay đổi đối số.

3
giải pháp yêu thích, tuy nhiên nó phụ thuộc vào nền tảng.
Nadim Farhat

@NadimFarhat: Theo cách nào. Một tín hiệu là một tín hiệu trên tất cả các nền tảng.
Martin York

74

Chia cho số 0 sẽ làm hỏng ứng dụng:

int main()
{
    return 1 / 0;
}

29
Tùy thuộc vào mức độ thông minh của trình biên dịch của bạn, điều này sẽ được bắt tại thời gian biên dịch. Tôi biết rằng visual studio 2008 sẽ không biên dịch cái này cho c ++ hoặc c #.
AidanO

2
Tôi đã biên dịch và chạy nó, bạn có muốn tôi gửi cho bạn .exe không?
Roee Gavirel

1
Trong cấu hình phát hành trong Visual Studio các phiên bản gần đây như 2010, nó sẽ chạy mà không gặp vấn đề gì. Tôi đoán đó là một số tối ưu hóa.
tedyyu

2
iirc nó không gặp sự cố trên cánh tay
sherpya 30/03/2015

2
Đây là hành vi không xác định và không được bảo đảm để sụp đổ. Trình biên dịch thường cho rằng hành vi không xác định là không thể truy cập được. Điều này có thể dẫn đến cơ thể mainbị xóa hoàn toàn bao gồm cả rethướng dẫn. Thực thi có thể chỉ rơi vào chức năng sau đây.
usr

64
*((unsigned int*)0) = 0xDEAD;

54
Điều này không được đảm bảo để sụp đổ.
Lập trình viên Windows

8
@Windowsprogrammer: không, nó không được bảo đảm . Nhưng hệ điều hành lành mạnh nào không dừng ứng dụng cố gắng truy cập bộ nhớ tại địa chỉ 0?
Joachim Sauer

29
"Nhưng hệ điều hành lành mạnh nào không dừng ứng dụng cố truy cập bộ nhớ ở địa chỉ 0?" - Đó không thực sự là những gì bạn muốn hỏi, nhưng dù sao tôi cũng sẽ trả lời. Trong một số máy tính có RAM ở địa chỉ 0 và việc chương trình lưu trữ giá trị ở đó là hoàn toàn có ý nghĩa. Một câu hỏi có ý nghĩa hơn sẽ là "Hệ điều hành nào không dừng ứng dụng truy cập bộ nhớ tại địa chỉ triển khai C ++ dành cho con trỏ null?" Trong trường hợp đó tôi không biết gì cả. Nhưng chương trình ban đầu là về ngôn ngữ C ++ chứ không phải về hệ điều hành.
Lập trình viên Windows

6
Hành vi không xác định của nó. Nó là hoàn toàn OK cho điều này để không làm gì. Một máy sẽ không gặp sự cố: Bất cứ điều gì chạy bộ xử lý dòng Z80 (tôi giả sử (Z80a của tôi không làm gì cả)).
Martin York

28
Mặc dù điều này không được đảm bảo để sụp đổ, nhưng đây là một trong những loại sự cố phổ biến nhất trong C ++. Vì vậy, nếu bạn muốn mô phỏng sự cố, đây là cách "xác thực" để thực hiện :)
Chris Burt-Brown

53

Vâng, chúng ta có đang tràn stack hay không?

for (long long int i = 0; ++i; (&i)[i] = i);

(Không được đảm bảo để sụp đổ theo bất kỳ tiêu chuẩn nào, nhưng không có bất kỳ câu trả lời được đề xuất nào kể cả câu trả lời được chấp nhận vì SIGABRTdù sao cũng có thể bị bắt. Trong thực tế, điều này sẽ sụp đổ ở mọi nơi.)


4
Tôi có thể thấy rằng buồn cười trên một hệ thống với các trang mã không được bảo vệ và bạn ghi đè lên chương trình của mình bằng một số mã vô tình là một vòng lặp vô hạn không có gì. Rất cao rất cao rất khó xảy ra nhưng có khả năng.
Martin York

@Loki: Nếu nó chỉ đọc từ mỗi byte thứ 4000 thì sao? Điều đó sẽ ít có khả năng sụp đổ? Chắc chắn ít nguy hiểm hơn.
Vịt Mooing

70
Thuật toán bị lỗi đó không phải là O (1)!
Anton Barkovsky

@MooingDuck: Tôi chỉ đang bình luận hài hước. Đừng coi trọng điều đó :-) Nhưng sẽ rất thú vị nếu ai đó tìm thấy một chuỗi các hướng dẫn đã làm điều gì đó buồn cười.
Martin York

1
@LokiAstari: bạn hoàn toàn đúng. Tôi đã suy nghĩ về (&i)[i] += !ithay vào đó, nhưng tôi sợ trình biên dịch có thể đủ thông minh và muốn tối ưu hóa điều đó. :-)
sam hocevar

35
 throw 42;

Chỉ cần câu trả lời ... :)


1
Các cửa sổ. GCC-5.4.0. Mã thoát: 3. Không có hộp thông báo lỗi. Thông báo trên bảng điều khiển: "chấm dứt được gọi sau khi ném phiên bản 'int' Ứng dụng này đã yêu cầu Runtime chấm dứt theo cách khác thường. Vui lòng liên hệ với nhóm hỗ trợ của ứng dụng để biết thêm thông tin."
Vadzim

15

assert(false); cũng khá tốt

Theo ISO / IEC 9899: 1999, nó được bảo đảm sự cố khi không xác định được NDEBUG:

Nếu NDEBUG được xác định [...] thì macro xác nhận được định nghĩa đơn giản là

#define assert(ignore) ((void)0)

Macro xác nhận được xác định lại theo trạng thái hiện tại của NDEBUG mỗi lần được đưa vào.

[...]

Macro khẳng định đưa các xét nghiệm chẩn đoán vào các chương trình; [...] nếu biểu thức (sẽ có kiểu vô hướng) là sai [...]. Sau đó, nó gọi hàm hủy bỏ.


Tôi mơ hồ nhớ VC 2005 hành xử khác nhau giữa gỡ lỗi và phát hành với các xác nhận?
Tom Kerr

8
@Tom assertđược thực hiện tương đương với ((void)0)trong chế độ Phát hành.
Seth Carnegie

2
@SethCarnegie Bạn không thấy có gì sai với điều này - chỉ khi định nghĩa NDEBUG được xác định sẽ không bị sập? Câu trả lời của Dans khá công bằng IMHO.
Adrian Cornish

@AdrianCornish Tôi chỉ trả lời câu hỏi của Tom Kerr, không nói câu trả lời này là sai. Tôi đã không đánh giá thấp câu trả lời này.
Seth Carnegie

3
Tôi không biết tại sao anh ta lại thực hiện bản dựng "phát hành" mã kiểm tra này.
Joel B

11

Vì sự cố là một triệu chứng của việc gọi hành vi không xác định và vì việc gọi hành vi không xác định có thể dẫn đến bất cứ điều gì, kể cả sự cố, tôi không nghĩ rằng bạn muốn thực sự làm hỏng chương trình của mình, nhưng chỉ cần thả nó vào trình gỡ lỗi. Cách di động nhất để làm như vậy có lẽ là abort().

Trong khi raise(SIGABRT)có tác dụng tương tự, nó chắc chắn là nhiều hơn để viết. Tuy nhiên, cả hai cách đều có thể bị chặn bằng cách cài đặt bộ xử lý tín hiệu cho SIGABRT. Vì vậy, tùy thuộc vào tình huống của bạn, bạn có thể muốn / cần tăng tín hiệu khác. SIGFPE, SIGILL, SIGINT, SIGTERMHoặc SIGSEGVcó thể là cách để đi, nhưng tất cả đều có thể bị chặn.

Khi bạn có thể không thể truy cập được, các lựa chọn của bạn có thể còn rộng hơn, như sử dụng SIGBUStrên linux.


1
Tôi thực sự nghi ngờ rằng anh ta muốn một trình sửa lỗi liên quan. Anh ta dường như muốn kiểm tra những gì xảy ra khi người gọi chương trình gặp sự cố gặp sự cố được gửi theo cách của anh ta. Mà rất hợp lý.
Donal Fellows

9

Đèn flash duy nhất tôi có là hàm abort () :

Nó hủy bỏ quá trình với một chấm dứt chương trình bất thường. Nó tạo ra tín hiệu SIGABRT , theo mặc định khiến chương trình chấm dứt trả lại mã lỗi kết thúc không thành công cho môi trường máy chủ. Chương trình bị chấm dứt mà không thực hiện các hàm hủy cho các đối tượng có thời gian lưu trữ tự động hoặc tĩnh và không gọi bất kỳ atexit nào (được gọi bởi exit () trước khi hàm kết thúc chương trình). Nó không bao giờ trở lại với người gọi của nó.


9

Câu trả lời là nền tảng cụ thể và phụ thuộc vào mục tiêu của bạn. Nhưng đây là chức năng sự cố Mozilla Javascript, mà tôi nghĩ minh họa rất nhiều thách thức để thực hiện công việc này:

static JS_NEVER_INLINE void
CrashInJS()
{
    /*
     * We write 123 here so that the machine code for this function is
     * unique. Otherwise the linker, trying to be smart, might use the
     * same code for CrashInJS and for some other function. That
     * messes up the signature in minidumps.
     */

#if defined(WIN32)
    /*
     * We used to call DebugBreak() on Windows, but amazingly, it causes
     * the MSVS 2010 debugger not to be able to recover a call stack.
     */
    *((int *) NULL) = 123;
    exit(3);
#elif defined(__APPLE__)
    /*
     * On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are
     * trapped.
     */
    *((int *) NULL) = 123;  /* To continue from here in GDB: "return" then "continue". */
    raise(SIGABRT);  /* In case above statement gets nixed by the optimizer. */
#else
    raise(SIGABRT);  /* To continue from here in GDB: "signal 0". */
#endif
}

2
Bạn nên bỏ hoàn toàn điều đó và sử dụng jQuery thay thế.
Thomas Weller

1
Đây là hành vi không xác định và không được bảo đảm để sụp đổ. Trình biên dịch thường cho rằng hành vi không xác định là không thể truy cập được. Trong trường hợp đó, ít nhất dòng sự cố sẽ bị xóa và các mã khác cũng có thể như vậy.
usr

8

Tôi thấy có nhiều câu trả lời được đăng ở đây sẽ rơi vào những trường hợp may mắn để hoàn thành công việc, nhưng không có câu trả lời nào trong số đó là 100% xác định để sụp đổ. Một số sẽ sụp đổ trên một phần cứng và hệ điều hành, những cái khác thì không. Tuy nhiên, có một cách tiêu chuẩn theo tiêu chuẩn C ++ chính thức để làm cho nó sụp đổ.

Trích dẫn từ tiêu chuẩn ISO / IEC 14882 §15.1-7 của C ++ :

Nếu cơ chế xử lý ngoại lệ, sau khi hoàn thành việc khởi tạo đối tượng ngoại lệ nhưng trước khi kích hoạt trình xử lý ngoại lệ, hãy gọi một hàm thoát qua một ngoại lệ, std :: terminating được gọi là (15.5.1).

struct C {
    C() { }
    C(const C&) {
        if (std::uncaught_exceptions()) {
            throw 0; // throw during copy to handler’s exception-declaration object (15.3)
        }
    }
};
int main() {
    try {
    throw C(); // calls std::terminate() if construction of the handler’s
    // exception-declaration object is not elided (12.8)
    } catch(C) { }
}

Tôi đã viết một mã nhỏ để chứng minh điều này và có thể được tìm thấy và thử trên Ideone tại đây .

class MyClass{
    public:
    ~MyClass() throw(int) { throw 0;}
};

int main() {
  try {
    MyClass myobj; // its destructor will cause an exception

    // This is another exception along with exception due to destructor of myobj and will cause app to terminate
     throw 1;      // It could be some function call which can result in exception.
  }
  catch(...)
  {
    std::cout<<"Exception catched"<<endl;
  }
  return 0;
}

ISO / IEC 14882 §15.1 / 9 đề cập đến việc ném mà không thử khối dẫn đến lệnh hủy bỏ ngầm định:

Nếu hiện tại không có ngoại lệ nào được xử lý, thực thi biểu thức ném mà không có lệnh gọi toán hạng std :: terminating ()

Những thứ khác bao gồm: ném từ hàm hủy: ISO / IEC 14882 §15.2 / 3


7
*( ( char* ) NULL ) = 0;

Điều này sẽ tạo ra một lỗi phân khúc.


10
Điều này không được đảm bảo để sụp đổ.
Lập trình viên Windows

23
"Điều gì sẽ xảy ra thay thế?" - Bất cứ điều gì có thể xảy ra thay thế. Hành vi không được xác định, do đó, việc triển khai có thể gán 0 cho một trong các biến của chương trình của bạn hoặc nó có thể gán 42 cho một trong các biến của chương trình hoặc nó có thể định dạng ổ cứng của bạn và tiếp tục thực hiện chương trình của bạn.
Lập trình viên Windows

7
(tiếp tục tập hợp "lập trình viên Windows") Nó có thể khiến máy tính của bạn phát nổ, hoặc nó có thể khiến nó xuất hiện và chiếm lĩnh nhân loại. hoặc ... nó sẽ sụp đổ 99,9% và được xác định là "hành vi không xác định" vì không ai muốn chịu trách nhiệm về việc đó.
Roee Gavirel

1
Trên thực tế, điều đó không được đảm bảo thậm chí thực hiện hành vi không xác định - nó hoàn toàn có thể được xác định và hoạt động đúng. Hãy xem xét mã này: pastebin.com/WXCtTiDD (Đã thử nghiệm trên Linux với quyền root, bạn cũng có thể làm điều này với tư cách là người dùng không root nếu bạn thực hiện một số thay đổi cấu hình wiki.debian.org/mmap_min_addr )
cha0site

2
@ cha0site: Tiêu chuẩn được đảm bảo là hành vi không xác định bởi vì đó là sự hủy bỏ một con trỏ rỗng. Bất kỳ hành vi nào bạn quan sát thấy trên Linux đều được phép dưới cái ô "hành vi không xác định"
Ben Voigt

6

Cái này bị thiếu:

int main = 42;

1
Có nó làm; nhưng nó làm một cái gì đó ngoạn mục khi bạn chạy nó.
Joshua

5

Điều gì về tràn ngăn xếp bởi một cuộc gọi phương thức đệ quy vòng lặp chết?

#include <windows.h>
#include <stdio.h>

void main()
{
    StackOverflow(0);
}

void StackOverflow(int depth)
{
    char blockdata[10000];
    printf("Overflow: %d\n", depth);
    StackOverflow(depth+1);
}

Xem ví dụ ban đầu trên Microsoft KB


4
Điều gì sẽ ngăn Trình biên dịch thông minh đầy đủ tối ưu hóa cả phân bổ ngăn xếp không sử dụng và lệnh gọi đuôi?
JB.

@JB: thật đáng tiếc không có ý tưởng nào vì không quen thuộc với logic tối ưu hóa trình biên dịch hiện có
sll

8
Vâng, được biên dịch ở đây với gcc 4.6.0 ở mức tối ưu hóa -O2 trở lên, nó tối ưu hóa tốt. Nó cần -O1 hoặc thấp hơn để segfault.
JB.

@Abhinav: Chỉ cần đăng câu trả lời của bạn với tất cả các cách được thể hiện dưới dạng ví dụ trong C ++ :)
sll

5

Sự cố này xảy ra trên hệ thống Linux của tôi, vì chuỗi ký tự được lưu trữ trong bộ nhớ chỉ đọc:

0[""]--;

Nhân tiện, g ++ từ chối biên dịch cái này. Trình biên dịch ngày càng thông minh hơn và thông minh hơn :)


4
int i = 1 / 0;

Trình biên dịch của bạn có thể sẽ cảnh báo bạn về điều này, nhưng nó chỉ biên dịch tốt trong GCC 4.4.3 Điều này có thể sẽ gây ra SIGFPE (ngoại lệ dấu phẩy động), có lẽ không có trong ứng dụng thực như SIGSEGV (vi phạm phân đoạn bộ nhớ) như các câu trả lời khác gây ra, nhưng nó vẫn là một sự cố. Theo tôi, điều này dễ đọc hơn nhiều.

Một cách khác, nếu chúng ta sẽ gian lận và sử dụng signal.h, là:

#include <signal.h>
int main() {
    raise(SIGKILL);
}

Điều này được đảm bảo để tiêu diệt quá trình con, tương phản với SIGSEGV.


2
Điều này không được đảm bảo để sụp đổ.
Lập trình viên Windows

11
Ngôn ngữ C ++ không đảm bảo rằng 1/0 sẽ gây ra SIGFPE. Hành vi không xác định. Việc thực hiện có thể nói kết quả là 42.
Lập trình viên Windows

1
Khi hành vi không được xác định, việc thực hiện có thể làm bất cứ điều gì nó muốn. Ngôn ngữ C ++ không ngăn cản cũng như không yêu cầu triển khai để viết kết xuất sự cố, ngôn ngữ C ++ không ngăn chặn cũng như không yêu cầu triển khai để gán 42, v.v.
Lập trình viên Windows

2
@Giorgio nếu phần cứng không có cách nào đó tự động bẫy thì bạn vẫn buộc các trình biên dịch phát ra ít nhất hai hướng dẫn, một trong số đó cũng sẽ là một nhánh. Đó là khoảng gấp đôi chi phí của một bộ phận. Mọi người đều trả chi phí như thế. Nếu nó là tùy chọn và bạn muốn nó, bạn luôn có thể sử dụng chức năng thư viện cho nó. Nếu nó không phải là tùy chọn và bạn không muốn thì cuối cùng bạn vẫn phải trả chi phí.
Flexo

2
@Giorgio: Tôi có một ứng dụng thực hiện 100.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000 * 10 ^ 1000000. Tôi biết một thực tế rằng 0 trong số này sẽ là một phép chia cho 0 mặc dù không có cách nào trình biên dịch có thể biết điều này. Tôi chắc chắn không muốn trình biên dịch thực hiện kiểm tra phân chia cho số không.
Martin York

4

Đây là phiên bản hủy bỏ được bảo đảm hơn được trình bày trong các câu trả lời ở trên. Nó xử lý tình huống khi sigabrt bị chặn. Bạn có thể sử dụng bất kỳ tín hiệu nào thay vì hủy bỏ có hành động mặc định làm sập chương trình.

#include<stdio.h>
#include<signal.h>
#include<unistd.h> 
#include<stdlib.h>
int main()
{
    sigset_t act;
    sigemptyset(&act);
    sigfillset(&act);
    sigprocmask(SIG_UNBLOCK,&act,NULL);
    abort();
}

3
int* p=0;
*p=0;

Điều này sẽ sụp đổ quá. Trên Windows, nó gặp sự cố với AccessViolation và nó sẽ làm tương tự trên tất cả các hệ điều hành tôi đoán.


5
on all OS-esKhông, nó không sụp đổ trong hệ điều hành không được bảo vệ (ví dụ như MS-DOS.) Trên thực tế, đôi khi có một cái gì đó ở địa chỉ 0! Đối với chế độ thực x86, Bảng Vector ngắt ở địa chỉ 0.
ikh

Nó đã không sụp đổ trên Irix. Tôi buồn bã nhận ra khi chúng tôi chuyển mã đó sang Linux (nơi chúng tôi thậm chí không đến được main().
Scheff

3

Đây là đoạn trích được cung cấp bởi Google trong Breakpad.

  volatile int* a = reinterpret_cast<volatile int*>(NULL);
  *a = 1;

1
Vì tôi đang thử Breakpad, đây chính xác là những gì tôi muốn! Tôi thấy rằng một số minidumps Breakpad không tạo ra dấu vết ngăn xếp trỏ đến dòng trong mã của tôi gây ra sự cố. Cái này thì có, nên tôi có thể dùng nó làm bài kiểm tra poc tốt.
BuvinJ


2

Mặc dù câu hỏi này đã có câu trả lời được chấp nhận ...

void main(){
    throw 1;
}

Hoặc là... void main(){throw 1;}


2

Ghi vào bộ nhớ chỉ đọc sẽ gây ra lỗi phân đoạn trừ khi hệ thống của bạn không hỗ trợ các khối bộ nhớ chỉ đọc.

int main() {
    (int&)main = 0;
}

Tôi đã thử nghiệm nó với MingGW 5.3.0 trên Windows 7 và GCC trên Linux Mint. Tôi cho rằng các trình biên dịch và hệ thống khác sẽ cho hiệu ứng tương tự.


1

Hoặc một cách khác kể từ khi chúng tôi ở trong đoàn xe.

Một mảnh đáng yêu của đệ quy vô hạn. Đảm bảo để thổi stack của bạn.

int main(int argv, char* argc)
{
   return main(argv, argc)
}

In ra:

Lỗi phân đoạn (đổ lõi)


13
Tự gọi mainmình là hành vi không xác định, trong trường hợp bạn không biết :) Ngoài ra, đệ quy đuôi không được đảm bảo để thổi bay ngăn xếp của bạn. Nếu bạn muốn có một "bảo đảm", bạn phải làm một cái gì đó sau cuộc gọi đệ quy, nếu không trình biên dịch có thể tối ưu hóa đệ quy thành một vòng lặp vô hạn.
dòng chảy

0

Một điều chưa được đề cập:

((void(*)())0)();

Điều này sẽ coi con trỏ null là một con trỏ hàm và sau đó gọi nó. Giống như hầu hết các phương thức, điều này không được đảm bảo để làm hỏng chương trình, nhưng khả năng HĐH cho phép điều này không được kiểm soát và chương trình sẽ quay trở lại là không đáng kể.


3
Tôi biết một số máy sẽ gây khởi động lại vì mã khởi động hệ điều hành được ánh xạ hiệu quả đến địa chỉ 0. Đừng cho rằng mọi thứ sẽ hoạt động như PC của bạn. Bạn có thể nói rằng đó là một sự cố nhưng nó không hữu ích lắm vì bạn không thể gỡ lỗi vì tất cả trạng thái bị xóa khi khởi động.
Martin York

@Loki Astari: Tôi sẽ không nói rằng đây là một sự cố - nếu điều này có thể gây ra nó, thì chương trình cũng được gỡ lỗi, có nghĩa là nó cũng là một thử nghiệm tốt như bất kỳ. Mặt khác, tôi tò mò máy nào trong số những máy này có thể chạy Python.
Anton Golov

Tôi nghĩ rằng bạn bị mất điểm. Tôi đã thấy mã hệ điều hành ở mức 0. Không có nghĩa là không có hệ thống nào có mã tốt thông thường để chạy tốt ở mức 0. Hoặc các byte ở 0 có thể dễ dàng trở thành opcode để trả về.
Martin York

Tôi biết mã hệ điều hành ở 0; đó là một trong những lý do tôi cực kỳ nghi ngờ rằng các byte ở 0 sẽ là opcode để trả về. Chương trình khá rõ ràng là không thực hiện nữa và không thoát theo cách thông thường, tức là nó bị hỏng - nếu điều này không đủ tốt cho người hỏi, tôi mong anh ấy tự nhận xét về nó.
Anton Golov

2
Bạn chỉ biết mã hệ điều hành cho máy của bạn. Những gì tôi đang cố gắng nói là nó có thể thất bại cho bạn. Nhưng điều đó có nghĩa là không có gì. Có rất nhiều hệ thống ra khỏi đó. Tôi chắc chắn rằng một số trong số chúng có thể hoạt động (nghĩa là không gặp sự cố). Dựa vào hành vi cụ thể của máy / HĐH là một ý tưởng tồi và gây ra vấn đề bảo trì trong thời gian dài. Ý tưởng của trang web là quảng bá mã tốt (không chỉ mã mà sắp xếp công việc).
Martin York

0
void main()
{

  int *aNumber = (int*) malloc(sizeof(int));
  int j = 10;
  for(int i = 2; i <= j; ++i)
  {
      aNumber = (int*) realloc(aNumber, sizeof(int) * i);
      j += 10;
  }

}

Hy vọng điều này sụp đổ. Chúc mừng.


0
int main()
{
    int *p=3;
    int s;
    while(1) {
        s=*p;
        p++;
    }
}

2
Sẽ thật tuyệt khi được làm rõ một chút :)
olyv

1
con trỏ p sẽ vượt ra ngoài không gian địa chỉ của chương trình sẽ là lỗi bộ nhớ, vì một quá trình không thể truy cập vào bộ nhớ của tiến trình khác. Điều này sẽ dẫn đến chương trình bị sập. con trỏ p đang trỏ đến một vị trí ngẫu nhiên trong không gian địa chỉ của nó, nếu nó được tăng lên và bị vô hiệu hóa tại một thời điểm nào đó, nó sẽ trỏ đến không gian địa chỉ (tiến trình) của chương trình khác. vì vậy nó sẽ sụp đổ sau một thời gian
sc_cs

Hoặc, theo giả thuyết, nó có thể đạt được số nguyên tràn và bao quanh, chạy vô tận. Tôi sẽ cố gắng sử dụng long longhoặc size_tvà bắt đầu với pgiá trị tối đa tương ứng hoặc gần với nó, để nhanh hơn. Mặc dù nó vẫn không được bảo đảm để sụp đổ ngay cả trong trường hợp đó.
Patrick Roberts

0

Một cách sành điệu để làm điều này là một cuộc gọi chức năng ảo thuần túy:

class Base;

void func(Base*);

class Base
{
public:
   virtual void f() = 0;
   Base() 
   {
       func(this);
   }
};

class Derived : Base
{
   virtual void f()
   {
   }
};

void func(Base* p)
{
   p->f();
}


int main()
{
    Derived  d;
}

Được biên dịch với gcc, bản in này:

phương pháp ảo thuần túy được gọi là

chấm dứt được gọi mà không có ngoại lệ hoạt động

Đã hủy bỏ (đổ lõi)


0

Bạn có thể sử dụng lắp ráp trong c ++ code BUT của mình INT 3 chỉ dành cho các hệ thống x86, các hệ thống khác có thể có các hướng dẫn bẫy / điểm dừng khác.

int main()
{
    __asm int 3;

    return 0;
}

INT 3 gây ra một ngắt và gọi một vectơ ngắt được thiết lập bởi HĐH.


0

Sử dụng __builtin_trap () trong GCC hoặc clang hoặc __debugbreak () trong MSVC. Không xử lý các điểm dừng / bẫy này sẽ dẫn đến ngoại lệ / sự cố điểm dừng chưa được xử lý. Các đề xuất khác sử dụng abort () hoặc exit (): những đề xuất này có thể được xử lý bởi các luồng khác, khiến cho việc nhìn thấy ngăn xếp của luồng phát tán sự cố trở nên khó khăn hơn.


-2
char*freeThis;
free(freeThis);

Giải phóng một con trỏ chưa được khởi tạo là hành vi không xác định. Trên nhiều nền tảng / trình biên dịch, freeThissẽ có một giá trị ngẫu nhiên (bất cứ thứ gì đã ở vị trí bộ nhớ đó trước đó). Giải phóng nó sẽ yêu cầu hệ thống giải phóng bộ nhớ tại địa chỉ đó, điều này thường sẽ gây ra lỗi phân đoạn và làm cho chương trình bị sập.

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.