C阻止间接和错位

时间:2013-10-28 12:41:35

标签: objective-c objective-c-blocks

以下代码抛出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个字节。

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

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

为什么这很有用: 事实并非如此。永远不要这样做。真。从不。

2 个答案:

答案 0 :(得分: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段内。
  • 第二个地址靠近堆栈。
  • 第三个是who-know-where。

答案 1 :(得分:1)

你的问题确实与积木无关。你只是以一种没有意义的方式操纵指向局部变量的指针。

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

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

在第二段代码中,再次获取堆栈中局部变量blocky的地址,然后从中添加和减去一个单词(当然这是指向局部变量的指针{{ 1}}再次),并取消引用它(这是blocky的值),并将其分配给blocky。此操作无效。