C++ void(**rptr)()和main()中的调用在此解决方案中如何在C++;?

C++ void(**rptr)()和main()中的调用在此解决方案中如何在C++;?,c++,C++,在这个Quora答案中,我偶然发现了这段代码,并想了解发生了什么: 我问我的编程老师,他说他不太熟悉alloca(),但他肯定这个程序有未定义的行为,我最好继续问下去。 值得注意的是,Quora上答案的OP并不能保证它能在其他人的系统上工作 我很难理解void(**rptr)(的功能以及main()中的调用是如何工作的,为什么*200 #include <iostream> #include <stdlib.h> int num; void(**rptr)(); void

在这个Quora答案中,我偶然发现了这段代码,并想了解发生了什么:

我问我的编程老师,他说他不太熟悉
alloca()
,但他肯定这个程序有未定义的行为,我最好继续问下去。 值得注意的是,Quora上答案的OP并不能保证它能在其他人的系统上工作

我很难理解
void(**rptr)(
的功能以及
main()
中的调用是如何工作的,为什么
*200

#include <iostream>
#include <stdlib.h>
int num;
void(**rptr)();
void foo() {
  if(num >= 100) exit(0);
  std::cout << ++num << std::endl;
  *rptr++ = foo;
}
int main() {
  rptr = (void(**)())alloca(sizeof(*rptr) * 200) - 1;
  foo();
  return 0;
}
#包括
#包括
int-num;
无效(**rptr)();
void foo(){
如果(num>=100)退出(0);

std::cout这是一个利用未定义行为的可怕黑客。分析未定义行为是毫无意义的,但有时深入挖掘并找出确切原因很有趣

基本上,正在发生的是
alloca(…)
正在分配足够的内存来在堆栈上存储200个函数指针。到目前为止,这是不寻常的,但没有什么不好的。但关键是最后的-1-它返回的内存在该存储之前。因此
rptr
将堆栈指向未知位置

然后调用
foo
。在
foo
的末尾,我们将
foo
的地址写入
rptr
。但是
rptr
在有效内存之前是一个地址,所以我们正在覆盖其他内容

另一个东西恰好是
foo
返回的地址(应该是
main
)。因此,它基本上“返回”到
foo
的开头,而不是返回到
main
。这会重复,直到我们到达出口


它基本上是适度控制的堆栈粉碎。并且只适用于具有调用约定的架构,其中返回地址被放在这个庄园的堆栈上。

使用asm如何生成的技巧…fwiw,以某种方式,你需要一个循环来打印从1到100的数字。这只是一个游戏,实际上你称之为“循环”。代码在混淆“循环”方面做了大量工作,这些东西肯定是不可移植的,并且依赖于UB@idclev463035818我会将其标记为模糊递归,而不是循环。目的是
foo
以调用
foo
结束“为什么
*200
”可能只是因为200>100。我假设101会”“工作”也一样,0有一个外部机会。@idclev463035818:
std::cout