我正在尝试创建一个与不同崩溃进程(这是我无法控制的)交互的Python程序。不幸的是,我正在连接的程序甚至不能可靠地崩溃!所以我想做一个快速的C++程序,它是故意崩溃的,但是我不知道最好的最短的方法,有人知道我应该把什么放在我的:
1 2 3
| int main() {
crashyCodeGoesHere();
} |
让我的C++程序可靠崩溃
- 可以使用内联程序集尝试执行特权指令:asm { cli; };。
- @我认为每个问题的答案在可用性上是有区别的。(仅供参考:我对这两个问题都没有投票)
- 当一个已经提出异常的时候,是否有任何关于抛出异常的评论?请检查我在下面的答案和评论
- redis使用下面的*((char*)-1) = 'x';代码来引发崩溃,以便在这里调试我的答案中的更多内容。
- 我发现这个问题是为了寻找一个碰撞报告系统的测试用例。我需要在正常运行时强制崩溃来调用崩溃报告程序和堆栈转储发送。谢谢!
abort()函数可能是您最好的选择。它是C标准库的一部分,定义为"导致异常程序终止"(例如致命错误或崩溃)。
- 注意,通过abort()的崩溃并不调用任何析构函数或atexit函数,尽管这在这里可能并不重要。
- @Xeo:如果它确实调用了析构函数和atexits,那么现在就不会是崩溃了,是吗?
- @唐纳:说得对。
- 既然abort()是正确的答案,那么‘退出(-1);’是可以接受的吗?
- 不,因为它不会导致撞车,只是报告一些无法完成的事情。
- 窗户。GCC-5.4.0。退出代码:3。无错误消息框。控制台消息:"此应用程序已请求运行时以异常方式终止它。有关更多信息,请联系应用程序的支持团队。"。
尝试:
1 2
| raise(SIGSEGV); // simulates a standard crash when access invalid memory
// ie anything that can go wrong with pointers. |
发现于:
- 我不知道这个终止是否是实现定义的…
- 它不仅仅是定义的实现——信号可以用signal()捕获。不过,大多数健全的应用程序都没有。
- 它将以与应用程序中正常SIGSEGV完全相同的方式崩溃(这是大多数应用程序崩溃的方式)。它定义得很好(默认情况下,它退出应用程序并生成一个核心文件)。是的,您可以设置一个处理程序,但是如果您有一个处理程序,您不想用同样的方法测试它!!
- +1用于raise()。这允许您通过更改参数来测试大量不同类型的异常。
- 最喜欢的解决方案,但是它依赖于平台。
- @纳迪姆法尔特:以什么方式。信号是所有平台上的信号。
- 窗户。GCC-5.4.0。退出代码:3。无错误消息框。没有控制台消息。
除以零将使应用程序崩溃:
1 2 3 4
| int main()
{
return 1 / 0;
} |
- 我的最爱,毫无疑问。
- 这一个适用于大多数语言。
- 根据编译器的聪明程度,这将在编译时被捕获。我知道VisualStudio 2008不会为C++或C语言编译这个。
- 因为这段代码需要不断地折叠,所以它甚至不会被成功地编译,所以我们不能在这里说它可以崩溃任何东西,因为您没有可执行文件来运行。
- 我已经编译并运行了它,你想让我把.exe沙化吗?
- (1/0);也会起作用。
- 在Visual Studio最新版本(如2010)的版本配置中,它将毫无问题地运行。我想这是一些优化。
- 返回0/0有什么问题;:。|
- IIRC,它不会在手臂上碰撞
- 看在K&R的份上,别再写void main()了!
- 这是未定义的行为,不能保证崩溃。编译器通常假定无法访问未定义的行为。这可能导致main的主体被完全删除,包括ret指令。执行可能只属于以下功能。
- 我的编译器不允许1/0,我必须这样做:int x=0;1/x;
- 窗户。GCC-5.4.0。退出代码:-1073741676。没有控制台消息。弹出错误消息框:"应用程序错误。异常整数被零除。(0x0000094)发生在应用程序的位置0x001A3FE2。单击"确定"终止程序。"
1
| *((unsigned int*)0) = 0xDEAD; |
- 这并不能保证会崩溃。
- @WindowsProgrammer:不,不保证。但是哪个健全的操作系统不能阻止试图访问地址0的内存的应用程序?
- "但是哪个健全的操作系统不能阻止试图访问地址0的内存的应用程序?"--这不是你想问的,但我还是会回答的。在某些计算机中,地址0处有RAM,程序在其中存储值是非常有意义的。一个更有意义的问题是"哪个操作系统不会阻止一个应用程序访问在一个C++实现中为一个空指针保留的地址上的内存?"那样的话,我什么都不知道。但是最初的程序是关于C++语言的,而不是关于OSES的。
- 其未定义的行为。这件事什么都不做是完全可以的。不会崩溃的机器:运行Z80系列处理器的任何东西(我假设(我的Z80A什么也不做))。
- 虽然这并不能保证崩溃,但它是C++中最常见的崩溃类型之一。所以,如果你想模拟一个崩溃,这是一个"真实"的方法来做它:)
- @ChrisburtBrown:在会崩溃的机器上访问零地址会产生一个sigsegv信号。仅仅提高(sigsegv)就容易多了。因此,您可以以可复制的方式模拟精确的行为。
- @洛基:你在基于Z80的系统上运行python?我印象深刻,我不认为你能在一个8位系统上寻址足够的内存来做到这一点…
- @唐纳菲尔:不,你怎么会认为是Python?
- @洛基,Python是在原来的问题上的顶端。考虑到它运行的是python,它很可能运行在一个带有mmu的系统上,如果是这样,它最有可能一直崩溃。
- @基思·尼古拉斯:我的观点是正确的。我刚想出了一个系统。假设它会崩溃是一个坏主意,因为什么可能崩溃在你的电脑并不意味着它持有任何进一步。许多人认为PC是主要的体系结构而受到伤害。最近的发展发生了巨大的变化,很多发展都转移到了移动设备上,如果有些假设不再成立的话。谁知道下一个体系结构更改将要做什么/什么时候做。依赖(或习惯)未定义的行为,以特定的方式工作,只会导致后来的坏事。
- @洛基,我认为在所问问题的背景下,这是可以的。这家伙只是想要一个临时的方法来启动他的Python测试代码。这种方法是C++系统中常见的一种真正的崩溃。除了堕胎,这是一种非"真实"的撞车,没有明确的撞车方式,几乎按照定义,撞车是发生在你进入行为不明确的土地。
- @基思·尼古拉:我不同意。这个问题将被更多的人阅读,而不是操作试图解决如何导致撞车。考虑到这些人,我们需要回答这个问题。
- @Joachimsauer:MacOSClassic就是这样一个操作系统(当然,MacOSX会停止程序)。
- @Joachimsauer:hpux允许读取和写入0。而且这是一个最近足够多的操作系统,仍然有人在运行它。
- 如果您的编译器警告标志过于热情,并且有时您没有能力更改它们,则无法编译。
- 升高(SIGSEGV)工作G
- 那是UB。它不仅仅依赖于体系结构,编译器可以假设从未到达过该代码。echo 'void crash(void) { *(unsigned *)0 = 0xdead; }' | clang -std=c99 -O2 -c -x c -给:1:20: warning: indirection of non-volatile null pointer will be deleted, not trap [-Wnull-dereference]并建议使用__builtin_trap或*(volatile unsigned *)0。
- 这是未定义的行为,不能保证崩溃。编译器通常假定无法访问未定义的行为。在这种情况下,至少要删除此行,其他代码也可能会被删除。
- @joachimsauer:win95/98允许用户空间写零页(news.ycombinator.com/item?ID=13263976),其中IDT(中断描述符表)驻留。哦,NVM,你说"神智清醒",而不是"曾经被广泛使用"。
好吧,我们是不是在stackoverflow上?
1
| for (long long int i = 0; ++i; (&i)[i] = i); |
(不保证按任何标准崩溃,但也没有任何建议的答案,包括自SIGABRT被抓获以来接受的答案)。实际上,这会在任何地方崩溃。)
- 我可以看到,在一个没有保护代码页的系统上很有趣,你用一些意外的无限循环的代码覆盖你的程序。极不可能,但可能。
- @洛基:如果它只是从每4000字节读取一次呢?那会不会不太可能崩溃?绝对不那么危险。
- 崩溃算法不是O(1)!
- @穆灵鸭:我只是在做一个有趣的评论。别那么认真地看待它。—)但是如果有人发现一系列指令做了一些有趣的事情,那就很有趣了。
- @你说得对。我考虑的是(&i)[i] += !i,但我担心编译器可能足够聪明,并希望对其进行优化。-)
- 即使这会失败:你的同事会理解吗?
只是答案…:)
- 窗户。GCC-5.4.0。退出代码:3。无错误消息框。控制台消息:"Terminate在抛出"int"实例后调用此应用程序已请求运行时以异常方式终止它。有关更多信息,请联系应用程序的支持团队。"。
assert(false);也不错。
根据ISO/IEC 9899:1999,当未定义ndebug时,保证发生碰撞:
If NDEBUG is defined [...] the assert macro is defined simply as
1
| #define assert(ignore) ((void)0) |
The assert macro is redefined according to the current state of NDEBUG each time that is included.
[...]
The assert macro puts diagnostic tests into programs; [...] if expression (which shall have a scalar type) is false [...]. It
then calls the abort function.
- 我模糊地记得VC 2005在使用断言进行调试和发布之间的行为不同吗?
- @tom assert在释放模式下等价于((void)0)。
- @sethcarnegie不知道这有什么问题-只有定义的ndebug不会崩溃?丹的回答很公平。
- @我只是在回答汤姆·克尔的问题,而不是说这个答案是错的。我没有否定这个答案。
- 是的……很多人投了反对票,没有解释为什么
- @Danf:有一种解释:如果定义了NDEBUG,那么assert就是((void)0),它什么也不做。所以发布版本不会崩溃!答案比以前更错误,现在你引用了规范。
- 我没有引用,有人补充说。
- 我不知道他为什么要做这个测试代码的"发布"构建。
由于崩溃是调用未定义行为的一种症状,并且由于调用未定义行为可能导致任何事情,包括崩溃,我认为您不希望真的使您的程序崩溃,只需要将它放到调试器中即可。最便携的方法可能是abort()。
虽然raise(SIGABRT)具有相同的效果,但它肯定更适合写作。但是,两种方法都可以通过为SIGABRT安装信号处理程序来截获。因此,根据您的情况,您可能需要/需要发出另一个信号。可能是SIGFPE、SIGILL、SIGINT、SIGTERM或SIGSEGV等,但都可以拦截。
当您不可移植时,您的选择可能会更广泛,比如在Linux上使用SIGBUS。
- 我真的怀疑他是否需要一个调试器。他似乎想测试当一个崩溃程序的调用程序发生崩溃时会发生什么。这是非常合理的。
我只有abort()函数:
它以异常的程序终止中止进程。它生成sigabrt信号,默认情况下,该信号使程序终止,并向主机环境返回一个不成功的终止错误代码。程序终止时,不会对自动或静态存储持续时间的对象执行析构函数,也不会调用任何atexit(在程序终止之前由exit()调用)函数。它永远不会回到它的呼叫者那里。
答案是平台特定的,取决于您的目标。但这里是mozilla javascript崩溃函数,我认为它说明了实现此功能的许多挑战:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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
} |
- 您应该完全放弃它,改用jquery。
- 这是未定义的行为,不能保证崩溃。编译器通常假定无法访问未定义的行为。在这种情况下,至少会删除崩溃行,其他代码也可能会被删除。
C++可以通过在处理另一个异常时抛出异常来确定地崩溃!标准规定,绝不从析构函数中抛出任何异常,也绝不在可能抛出异常的析构函数中使用任何函数。
我们必须做一个函数,所以让我们离开析构函数等。
ISO/IEC 14882第15.1-7节中的示例。应该是按C++标准崩溃的。这里有一个例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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节提到不使用try块的throw,导致隐式调用中止:
If no exception is presently being handled, executing a
throw-expression with no operand calls std::terminate()
其他包括:自毁器抛掷:ISO/IEC 14882第15.2/3节
这个不见了:
- 它是连在一起的吗?
- 是的,的确如此,但当你跑步的时候,它会让人大吃一惊。
1
| *( ( char* ) NULL ) = 0; |
这将产生分段错误。
- 这并不能保证会崩溃。
- 会发生什么呢?
- "相反,会发生什么?"--任何事情都有可能发生。行为未定义,因此实现可以将0分配给程序的一个变量,或者将42分配给程序的一个变量,或者格式化硬盘并继续执行程序。
- (继续"Windows程序员"的想法)它可能会让你的电脑爆炸,或者它可能会使它成为一个活生生的东西,接管人类。或者…它将以99.9%的比例崩溃,并被定义为"未定义的行为",因为没有人想对此负责。
- 事实上,这甚至不能保证做不定义的行为——它可以完全定义并正常工作。考虑下面的代码:pastebin.com/wxctidd(在Linux上作为根用户进行测试,如果进行一些配置更改wiki.debian.org/mmap-min-addr,也可以作为非根用户进行测试)
- @cha0site:标准保证它是未定义的行为,因为它取消了对空指针的引用。在Linux上观察到的任何行为在"未定义行为"的保护伞下都是允许的。
- 不同的平台可以有不同的巴哈维尔
- 这是未定义的行为,不能保证崩溃。编译器通常假定无法访问未定义的行为。在这种情况下,至少会删除崩溃行,其他代码也可能会被删除。
死循环递归方法调用的堆栈溢出怎么办?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <windows.h>
#include <stdio.h>
void main()
{
StackOverflow(0);
}
void StackOverflow(int depth)
{
char blockdata[10000];
printf("Overflow: %d
", depth);
StackOverflow(depth+1);
} |
查看Microsoft知识库上的原始示例
- 什么会阻止足够智能的编译器同时优化未使用的堆栈分配和尾部调用?
- @不幸的是,不知道,因为不熟悉现有的编译器优化逻辑
- 好吧,在这里用GCC4.6.0在优化级别(氧气和更高级别)编译,它优化得很好。它需要-O1或更低的值来进行SegFault。
- @JB:谢谢,非常有趣,知道这个!
- AbNeAv:只需用C++中的一个例子来表达你的答案
这是上面答案中给出的中止的一个更可靠的版本。它可以处理SIGABRT被阻止的情况。您可以使用任何具有程序崩溃默认操作的信号而不是中止。
1 2 3 4 5 6 7 8 9 10 11 12
| #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();
} |
这在我的Linux系统上崩溃,因为字符串文本存储在只读内存中:
顺便说一下,G++拒绝编译这个。编译器越来越智能化:)
您的编译器可能会警告您这一点,但它在GCC4.4.3下编译得很好。这可能会导致SIGFPE(浮点异常),这在实际应用程序中可能不像其他答案造成的SIGSEGV(内存分段冲突)那样,但它仍然是崩溃。在我看来,这更具可读性。
另一种方法,如果我们打算欺骗和使用signal.h,是:
1 2 3 4
| #include <signal.h>
int main() {
raise(SIGKILL);
} |
与sigsegv相比,这保证会杀死子进程。
- 这并不能保证会崩溃。
- C++语言不能保证1/0会导致SigFPE。行为未定义。实施可以说结果是42。
- 这是一个正确的实现吗?42是一个定义良好的数字,它不是未定义的。
- 那不是整数除法吗?为什么会导致浮点异常?
- 当行为未定义时,实现可以做它想要做的任何事情。C++语言既不阻止也不需要实现一个崩溃转储,C++语言既不阻止也不要求实现分配42等。
- 在我个人看来,sigfpe不是0除法的合适选择,而且它不是16位机器上的最佳选择,在16位机器上-32768除以-1不适合16位带符号的in t。Intel不同意我的观点,很多编译器开发人员不同意我的观点。无论如何,由于行为是未定义的,因此SIGFPE与分配42或格式化硬盘驱动器一样是允许的。
- @Windows程序员:重点是未定义的含义。如果我有一个部分函数f:a->b,并且f(a)在a中的某个a中是未定义的,那么计算f(a)不能返回b中的值:要么f(a)不终止,要么它返回b之外的某个特殊值。返回b中的某个随机值b使f(a)由f(a)=b定义,即不计算f,因为它是指定的(f(a)必须是未定义的)。所以计算1/0不能返回数字,因为1/0在整数和实数上都是未定义的。IMO使用未定义的行为(即任何事情都会做)是不正确的方法。
- 我认为正确的未定义方法是抛出异常或返回一个表示未定义的特殊值(参见haskell中的maybe monad)。另请参见en.wikipedia.org/wiki/&hellip;、en.wikipedia.org/wiki/partial_函数
- @Giorgio——这一标准定义了处理此类事情的正确方法是什么,而且非常清楚——这是未定义的行为,任何事情都会发生。
- @阿伍德兰德:恐怕你是对的。我只能希望C++规范将被固定在下一个C++修订中。
- @吉奥吉奥- C++规范被编写为尽可能灵活。因此,实现可能选择引发异常或设置标志来指示无效的数字。标准故意避免指定应该是什么,以避免在平台上施加巨大的负担,例如,为了做到这一点,必须包装每个部门。
- @awoodland:检查x/y的第二个参数是否为零是一个很大的负担?据我所知,检查寄存器是否包含零是处理器最便宜的操作之一。
- @Giorgio如果硬件没有某种自动捕获的方法,您仍然强制编译器发出至少两条指令,其中一条也是分支。这大约是一个部门成本的两倍。每个人都是这样支付费用的。如果它是可选的,并且您想要它,您可以始终为它使用库函数。如果它不是可选的,而且你不想要它,你最终还是要付出代价。
- 让我们在聊天中继续讨论
- 对于以后搜索的任何人来说,维基百科告诉我,Sigfpe是为了向后兼容而提出的。在POSIX平台上,没有"适当"的零除信号——SIGFPE可能是最接近的。如果正确使用signal()调用——也就是说,在可能引起信号的代码前设置一个处理程序,然后在这些语句执行后立即将信号处理程序重置为SIG_DFL——信号类型并不太重要。如果你在处理整数,你得到了一个sigfpe,很明显发生了什么。
- @请不要引用维基百科作为权威来源。当然,这是很好的查找东西,但遵循参考真正的来源。甚至维基百科也说不要把它们作为权威来源。
- @Giorgio:我有一个应用程序,它可以处理10000000000000000000000000000000000000000000000000000000000000000000,&zwnj;&35;8203;00000000000000000000000,&zwnj;&35;8203;00000000000000000000000000000,&zwnj;&;8203;000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,&zwnj;&&820 3;00000000000000,&zwnj;&8203;00000000000000,&zwnj;&8203;0000000000000000000,&zwnj;&8203;0000000000000000000,&zwnj;&8203;0000000000000000000,&zwnj;&8203;0000000000000000000,&zwnj;&8203;0000000000000000*10^1000000个分区。我知道其中的0是一个除以0的事实,尽管编译器不可能知道这一点。我绝对不希望编译器将除法检查设为零。
- @LokiAstari:如果这会造成一个真正的性能问题,那么您可以使用内联汇编来执行您的划分。此外,编译器只需要在一个处理器上安装这种检查,它本身不捕获除数为零,据我所知,这是非常罕见的。不管怎样,我理解C++的策略,因为性能原因,没有用零、指针、数组索引检查除法。
- @乔治:为什么我要为你的需要而支付费用呢?最好不要检查,当我需要检查时,我会明确地进行检查。语言设计者做出了选择。他们选择不进行检查,这样我们就可以有最佳的速度作为默认值(因此操作员[]和at()),另一个选择是为每个人放慢代码的速度,就像不称职/学习者的开发人员安全地这样做一样。我认为他们做出了正确的选择。我可以在不进行自动检查的情况下编写好的安全/快速代码,在需要时显式地添加检查,因此在必要时只会减慢代码速度。
- 这是未定义的行为,不能保证崩溃。编译器通常假定无法访问未定义的行为。在这种情况下,至少会删除崩溃行,其他代码也可能会被删除。
这也应该崩溃。在Windows上,它会因访问冲突而崩溃,我猜它应该在所有操作系统上都这样做。
- on all OS-es不,它不会在不受保护的操作系统(如MS-DOS)中崩溃。实际上,有时地址0中会有一些内容!对于x86实模式,中断向量表位于地址0中。
这是Google在BreakPad中提供的代码片段。
1 2
| volatile int* a = reinterpret_cast<volatile int*>(NULL);
*a = 1; |
- 因为我正在测试BreakPad,这正是我想要的!我发现一些breakpad小型转储不会生成指向代码中导致崩溃的行的堆栈跟踪。这一个可以,所以我可以用它作为好的P.O.C.测试。
尽管这个问题已经得到了公认的答案…
1 2 3
| void main(){
throw 1;
} |
或者…void main(){throw 1;}
1 2 3 4 5
| int main(int argc, char *argv[])
{
char *buf=NULL;buf[0]=0;
return 0;
} |
除非系统不支持只读内存块,否则写入只读内存将导致分段错误。
1 2 3
| int main() {
(int&)main = 0;
} |
我在Windows7上用mingggw5.3.0测试过,在linux mint上用gcc测试过。我认为其他编译器和系统也会产生类似的效果。
或者另一种方式,因为我们在乐队。
一段可爱的无限递归。保证会把你的烟囱炸开。
1 2 3 4
| int main(int argv, char* argc)
{
return main(argv, argc)
} |
打印输出:
Segmentation fault (core dumped)
- 调用main您自己实际上是未定义的行为,以防您不知道:)此外,尾递归也不能保证会破坏您的堆栈。如果您想要一个"保证",您必须在递归调用之后做一些事情,否则编译器可以将递归优化为无限循环。
1 2 3 4 5 6 7 8 9 10 11 12
| 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;
}
} |
希望这次崩溃。干杯。
尚未提及的:
这将把空指针视为函数指针,然后调用它。与大多数方法一样,这并不能保证会使程序崩溃,但是操作系统不检查和程序返回的可能性是微乎其微的。
- 我知道有几台机器这会导致重新启动,因为OS启动代码有效地映射到地址0。不要以为一切都会像你的电脑一样工作。你可以说这是一次崩溃,但它不是很有用,因为你不能调试它,因为启动时所有的状态都会被清除。
- @洛基·阿斯塔里:我还是会说这是一个崩溃——如果这可能导致它,那么正在调试的程序也可能,这意味着它和任何测试一样好。另一方面,我很好奇这些机器中哪些可以运行Python。
- 我认为你没抓住要点。我在0看到了操作系统代码。这并不意味着没有运行正常良好代码的系统在0时可以正常工作。或者0处的字节可以很容易地作为返回的操作码。
- 我知道0处的操作系统代码;这是我强烈怀疑0处的字节是否是返回的操作码的原因之一。很明显,程序不再执行了,也没有以通常的方式退出,也就是说,它崩溃了——如果这对询问者来说不够好,我希望他自己对它进行评论。
- 您只知道您机器的操作系统代码。我想说的是,这对你来说可能会失败。但这毫无意义。外面有很多系统。我确信其中一些可能会起作用(例如,不会发生碰撞)。依赖机器/操作系统特定的行为是一个坏主意,从长远来看会导致维护问题。这个网站的目的是推广好的代码(而不仅仅是代码之类的工作)。
- 不要那样做。这将调用中断向量表。
这样做的一种时尚方式是纯虚拟函数调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 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;
} |
用GCC编译,打印:
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
1 2 3 4 5 6 7 8 9
| int main()
{
int *p=3;
int s;
while(1) {
s=*p;
p++;
}
} |
- 如果能澄清一下,那就太好了。)
- P指针将超出程序的地址空间,这将是一个内存错误,因为一个进程无法访问另一个进程的内存。这将导致程序崩溃。指针P指向其地址空间中的一个随机位置,如果它在某个点上无限地递增和取消引用,它将指向另一个程序(进程)的地址空间。所以过一段时间它就会崩溃。
- 或者,假设它可以实现整数溢出和环绕,无限运行。我会尝试使用long long或size_t,从p开始,以各自的最大值,或接近它,以更快地崩溃。尽管在这种情况下它仍然不能保证崩溃。
1 2
| char*freeThis;
free(freeThis); |
释放未初始化的指针是未定义的行为。在许多平台/编译器上,freeThis将具有随机值(以前在该内存位置的任何值)。释放它会要求系统释放该地址的内存,这通常会导致分段错误并导致程序崩溃。