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、プログラムのセグメント内にあります。
  • 2 番目のアドレスはスタックの近くにあります。
  • 3 つ目は、誰がどこを知っているかです。
于 2013-10-28T12:57:58.020 に答える
1

あなたの質問は実際にはブロックとは何の関係もありません。意味のない方法でローカル変数へのポインターを操作しているだけです。

まず、 に割り当てたブロック ポインターを使用することはありませんblocky。スタック上のローカル変数のアドレスを取得し、blockyそれに 1 つの単語を追加して逆参照します。アーキテクチャによっては、スタックはおそらく下に成長します。つまり、これはスタック フレームのすべての変数の前にあり、おそらく現在のスタック フレームの戻りアドレスです。または、それは別のものかもしれません。次に、この値を に割り当てますblocky

次に、スタック上のローカル変数のアドレスをblocky再度取得し、そこから 1 語を減算して逆参照します。繰り返しますが、スタックが成長すると仮定すると、これは現在のスタック フレームの終わりを過ぎている可能性があり、これはガベージです。次に、この値を に割り当てますblocky。次に、これをブロックへのポインターとして実行しようとします。もちろん、これはうまくいきません。

コードの 2 番目の部分ではblocky、スタック上のローカル変数のアドレスを再度取得し、そこから 1 ワードを加算および減算し (もちろん、これはローカル変数へのポインターですblocky)、逆参照します (これは、の値blocky)、それを に割り当てblockyます。この操作は何もしません。

于 2013-10-28T20:16:20.337 に答える