Я хочу иметь возможность регистрировать сообщения (и предпочтительно прерывать отладчик) каждый раз, когда конкретный объект CFType
(для моих текущих целей CGPDFDocument
) выделяется, сохраняется, освобождается или освобождается.
Поскольку не существует метода Create...()
для CGPDFDocument
, который принимает CFAllocatorRef
, я пытаюсь временно изменить распределитель по умолчанию, как показано ниже:
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
) имеет NULL для context.retain и context.release, поэтому у меня нетлюбые оригинальные реализации для вызова.Возможно, поэтому, когда я пытаюсь выполнить приведенный выше код, я получаю следующую трассировку стека:
#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
.
. Следует отметить, что LogRetain()
и LogAllocate()
каждый из них успешно вызывается один раз (в указанном порядке) с 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()
в # 2 вызовет проблемный CFRetain()
, подробно описанный выше.
Может кто-нибудь помочь мне понять, что здесь происходит (особенно, как обработчик по умолчанию обрабатывает сохранение и освобождение, и почему я получаю SIGTRAP);как это исправить;и есть ли лучший способ сделать то, что я пытаюсь сделать?
(я подумал, что смогу разобраться, как использовать DTrace для проверки CFRetain()
и CFRelease()
, отфильтрованных с помощью CFTypeID
для CGPDFDocument
, но я не знаю, что проверять на освобождение (распределение не так важно отслеживать, поскольку я знаю, что оно выполняется в CGPDFDocumentCreateWithProvider()
). Также я предпочел бы иметь возможность перейти котладчик при сохранении / выпуске / освобождении, что я не считаю возможным с помощью DTrace.)
ОБНОВЛЕНИЕ: Прочитав исходный код для CFRelease
Я понимаю, что неправильно понял цель context.retain
и context.release
- они предназначены для сохранения и освобождения context.info
.Таким образом, весь описанный выше подход не является началом.Однако, возможно, мастер DTrace / Instruments все еще может творить магию?!