3

CFType特定のオブジェクト (現在の目的では a CGPDFDocument) が割り当て、保持、解放、または割り当て解除されるたびに、メッセージをログに記録できるようにしたいと考えています (できればデバッガーにブレークします) 。

を取るCreate...()メソッドがないため、次のようにデフォルトのアロケーターを一時的に変更しようとしています。CGPDFDocumentCFAllocatorRef

void MyPDFDocumentCreate()
{
    // ...

    CFAllocatorRef defaultAllocator = CFAllocatorGetDefault();
    CFAllocatorSetDefault(MyLogAllocator());

    CGPDFDocumentRef documentRef = CGPDFDocumentCreateWithProvider(provider);

    CFAllocatorSetDefault(defaultAllocator);

    // ...
}

MyLogAllocator()次のように定義されます。

static void *(*DefaultAllocate)(CFIndex size, CFOptionFlags hint, void *info);
static const void *(*DefaultRetain)(const void *info);
static void (*DefaultRelease)(const void *info);

void *LogAllocate(CFIndex size, CFOptionFlags hint, void *info)
{
    fprintf(stderr, "LogAllocate %p", info);
    if (DefaultAllocate)
        return DefaultAllocate(size, hint, info);
    else
        return NULL;
}

const void *LogRetain(const void *info)
{
    fprintf(stderr, "LogRetain");
    if (DefaultRetain)
        return DefaultRetain(info);
    else
        return info;
}

void LogRelease(const void *info)
{
    fprintf(stderr, "LogRelease");
    if (DefaultRelease)
        DefaultRelease(info);
}

static CFAllocatorRef MyLogAllocator()
{
    static CFAllocatorRef theLogAllocator = NULL;

    if (!theLogAllocator)
    {
        CFAllocatorContext context;
        CFAllocatorRef defaultAllocator = CFAllocatorGetDefault();
        CFAllocatorGetContext(defaultAllocator, &context);

        DefaultAllocate = context.allocate;
        DefaultRetain = context.retain;
        DefaultRelease = context.release;

        context.allocate = LogAllocate;
        context.retain = LogRetain;
        context.release = LogRelease;

        theLogAllocator = CFAllocatorCreate(kCFAllocatorUseContext, &context);
    }

    return theLogAllocator;
}

ただし、デフォルトのアロケーター (kCFAllocatorSystemDefault私が知る限り) には context.retain と context.release に NULL があるようです。そのため、呼び出す元の実装はありません。そのため、上記のコードを試すと、次のスタック トレースが表示されます。

#0  0x357ded12 in CFRetain ()
#1  0x357dcb68 in _CFRuntimeCreateInstance ()
#2  0x303fe35e in CGTypeCreateInstanceWithAllocator ()
#3  0x303fe34c in CGTypeCreateInstance ()
#4  0x304b32f4 in CGPDFDocumentCreateWithProvider ()
#5  0x000293f4 in MyPDFDocumentCreate ([...]) at [...]

XCode は、停止している理由を実際には教えてくれませんが、続行しようとすると、次のようになります。

(gdb) continue
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x357ded12 in CFRetain ()
(gdb) continue
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x357ded12 in CFRetain ()
(gdb) 

しかし、何回続けても同じ SIGTRAP が表示されます。解釈の仕方がわかりません。私が設定した唯一のブレークポイントは、上のシンボリック ブレークポイントですobjc_exception_throw

注意すべきことの 1 つは、LogRetain()LogAllocate()がそれぞれ から 1 回 (この順序で) 正常に呼び出されることCFAllocatorCreate()です。

#0  LogRetain (info=0x1a8000) at [...]
#1  0x358086f2 in CFAllocatorCreate ()
#2  0x00028d58 in MyLogAllocator () at [...] 
#3  0x000293e0 in MyPDFDocumentCreate ([...]) at [...]

#0  LogAllocate (size=104, hint=0, info=0x1a8000) at [...] 
#1  0x3580882e in CFAllocatorCreate ()
#2  0x00028d58 in MyLogAllocator () at [...]
#3  0x000293e0 in MyPDFDocumentCreate ([...]) at [...]

そして、LogAllocate()から再び成功しCFAllocatorAllocate()ます:

#0  LogAllocate (size=64, hint=1024, info=0x1a8000) at [...] 
#1  0x357dcc06 in CFAllocatorAllocate ()
#2  0x357dcb04 in _CFRuntimeCreateInstance ()
#3  0x303fe35e in CGTypeCreateInstanceWithAllocator ()
#4  0x303fe34c in CGTypeCreateInstance ()
#5  0x304b32f4 in CGPDFDocumentCreateWithProvider ()
#6  0x000293f4 in MyPDFDocumentCreate ([...]) at [...]

_CFRuntimeCreateInstance()at #2 が上記の問題を呼び出す前にCFRetain()

誰かがここで何が起こっているのかを理解するのを手伝ってくれませんか (特に、デフォルトのアロケーターが保持と解放を処理する方法と、SIGTRAP を取得する理由)。修正方法; そして、私がやろうとしていることを行うためのより良い方法があるかどうか?

(DTrace を使用して、 forでフィルター処理されたCFRetain()とをプローブする方法を考え出すことができるかもしれないと考えましたが、割り当て解除のために何をプローブすればよいかわかりません (割り当ては 内で行われることがわかっているので、追跡することはそれほど重要ではありません)。また、retain / release / deallocate でデバッガーを中断できるようにしたいと考えていますが、これは DTrace では不可能だと思います。)CFRelease()CFTypeIDCGPDFDocumentCGPDFDocumentCreateWithProvider()

更新:ソースコードを読んだので、 andCFReleaseの目的を誤解していることに気づきました。したがって、上記のアプローチ全体は初心者向けではありません。しかし、おそらく DTrace/Instruments ウィザードはまだ何らかの魔法を働かせることができるでしょうか?!context.retaincontext.releasecontext.info

4

1 に答える 1

0

とても興味深い問題です。DTrace のフィルタリングを深く調査し、ソースに飛び込んでいるCFReleaseので、gdb ブレークポイント条件を使用していつブレークするかを選択できます。割り当て解除が発生するかどうかを判断するには、単にCFGetRetainCount().

そうは言っても、オーバーリリースのクラッシュを追跡して髪を引っ張っていると思いますよね?リバース エンジニアリングよりも役立つ可能性がありますCFRelease()

  • CFゾンビ
  • Instruments の Allocations インストゥルメントは、オブジェクトが保持および解放されたとき、割り当てられ、破棄されたときの完全なスタックを提供します。「参照カウントを記録する」オプションをオンにします。
于 2011-02-24T14:25:23.320 に答える