0

以下代码会引发 EXC_BAD_ACCESS 错误(特别是一般保护错误错误),我想知道为什么您不能错位块指针并执行它。

#include <stdio.h>
int main(int argc, const char * argv[])
{

void (^blocky)() = ^{
    printf("Hello!\n");
    printf("Hello Again!\n");
};

blocky = *(&blocky+1);

blocky = *(&blocky-1);
blocky();
return 0;
}

但以下工作:

#include <stdio.h>
int main(int argc, const char * argv[])
{

void (^blocky)() = ^{
    printf("Hello!\n");
    printf("Hello Again!\n");
};

blocky = *(&blocky+1-1);
blocky();
return 0;
}

编辑(对错位代码块的回答):

如果将块视为结构,您会发现指向内存中可执行代码的值距块开头偏移 16 个字节,长度为 8 个字节。

您可以有效地更改此值,将执行指向内存中的另一个位置。一般来说,这会崩溃。

假设您知道另一段可执行代码在内存中的特定地址,您可以将其指向那里。

为什么这是有用的:它不是。永远不要这样做。真的。绝不。

4

2 回答 2

2

第一个示例中的指针操作是错误的。尝试这个:

#include <stdio.h>

typedef void (^blocky_t)();

int main(int argc, const char * argv[])
{
    blocky_t blocky = ^{
        printf("Hello!\n");
        printf("Hello Again!\n");
    };

    printf("blocky=%p\n", blocky);

    blocky = (blocky_t)((char *)blocky + 1);
    printf("blocky=%p\n", blocky);

    blocky = (blocky_t)((char *)blocky - 1);
    printf("blocky=%p\n", blocky);

    blocky();
    return 0;
}

$ clang -o blocky blocky.c
$ ./blocky
blocky=0x10574d040
blocky=0x10574d041
blocky=0x10574d040
Hello!
Hello Again!

当我运行你的代码时,我得到了:

blocky=0x10e0ba040
blocky=0x7fff51b46c10
blocky=0x1300000000

在哪里:

  • 第一个地址在__TEXT程序段内。
  • 第二个地址靠近堆栈。
  • 第三是谁知道在哪里。
于 2013-10-28T12:57:58.020 回答
1

您的问题确实与块无关。您只是在以一种没有意义的方式操作指向局部变量的指针。

首先,您永远不会使用分配给blocky. 您获取堆栈上局部变量的地址blocky,然后向其添加一个单词,然后取消引用它。根据架构,堆栈可能会向下增长,这意味着它位于堆栈帧上的所有变量之前,并且可能是当前堆栈帧的返回地址。或者它可能是别的东西。然后将此值分配给blocky

然后,您再次获取堆栈上的局部变量的地址,blocky然后从中减去一个字,并取消引用它。同样,假设堆栈向下增长,这可能会超过当前堆栈帧的末尾,这将是垃圾。然后将此值分配给blocky。然后,您尝试将其作为指向块的指针运行。当然,这是行不通的。

在第二段代码中,你blocky再次取局部变量在栈上的地址,然后在其中加减一个字(当然又是指向局部变量的指针blocky),并取消引用它(也就是)的值blocky,并将其分配给blocky。这个操作什么都不做。

于 2013-10-28T20:16:20.337 回答