3

私が取り組んでいる目的の C アプリで、腹立たしい EXC_BAD_ACCESS エラーが発生しています。あなたが提供できるどんな助けも大歓迎です。このエラーに対して通常のデバッグ方法 (NSZombieEnabled を有効にする、retain/release/autorelease をチェックして、割り当て解除されたオブジェクトにアクセスしようとしていないことを確認するなど) を試しましたが、役に立たないようです。

基本的に、この関数では常にエラーが発生します。

void op_TJ(CGPDFScannerRef scanner, void *info)
{
    PDFPage *self = info;
    CGPDFArrayRef array;

    NSMutableString *tempString = [NSMutableString stringWithCapacity:1];
    NSMutableArray *kernArray = [[NSMutableArray alloc] initWithCapacity:1];

    if(!CGPDFScannerPopArray(scanner, &array)) {
        [kernArray release];
        return;
    }

    for(size_t n = 0; n < CGPDFArrayGetCount(array); n += 2)
    {
        if(n >= CGPDFArrayGetCount(array))
            continue;

        CGPDFStringRef pdfString;

        // if we get a PDF string
        if (CGPDFArrayGetString(array, n, &pdfString))
        {
            //get the actual string
            const unsigned char *charstring = CGPDFStringGetBytePtr(pdfString);

            //add this string to our temp string
            [tempString appendString:[NSString stringWithCString:(const    char*)charstring encoding:[self pageEncoding]]];
            //NSLog(@"string: %@", tempString);

            //get the space after this string
            CGPDFReal r = 0;
            if (n+1 < CGPDFArrayGetCount(array)) {
                CGPDFArrayGetNumber(array, n+1, &r);

                // multiply by the font size
                CGFloat k = r;
                k = -k/1000 * self.tmatrix.a * self.fontSize;


                CGFloat kKern = self.kern * self.tmatrix.a;
                k = k + kKern;

                // add the location and kern to the array
                NSNumber *tempKern = [NSNumber numberWithFloat:k];
                NSLog(@"tempKern address: %p", tempKern);
                [kernArray addObject:[NSArray arrayWithObjects:[NSNumber numberWithInt:[tempString length] - 1], tempKern, nil]];

            }
        }
    }

    // create an attribute string
    CFMutableAttributedStringRef attString =    CFAttributedStringCreateMutable(kCFAllocatorDefault, 10);

    CFAttributedStringReplaceString(attString, CFRangeMake(0, 0), (CFStringRef)tempString);

    //apply overall kerning
    NSNumber *tkern = [NSNumber numberWithFloat:self.kern * self.tmatrix.a * self.fontSize];
    CFAttributedStringSetAttribute(attString, CFRangeMake(0, CFAttributedStringGetLength(attString)), kCTKernAttributeName, (CFNumberRef)tkern);

    //apply individual kern attributes
    for (NSArray *kernLoc in kernArray) {
        NSLog(@"kern location: %i, %i", [[kernLoc objectAtIndex:0] intValue],[[kernLoc objectAtIndex:1] floatValue]);
        CFAttributedStringSetAttribute(attString, CFRangeMake([[kernLoc objectAtIndex:0] intValue], 1), kCTKernAttributeName, (CFNumberRef)[kernLoc objectAtIndex:1]);
    }

    CFAttributedStringReplaceAttributedString([self cfAttString], CFRangeMake(CFAttributedStringGetLength([self cfAttString]), 0), attString);

    //release
    CFRelease(attString);
    [kernArray release];


}

行が原因でプログラムが常にクラッシュする

CFAttributedStringSetAttribute(attString, CFRangeMake([[kernLoc objectAtIndex:0] intValue], 1), kCTKernAttributeName, (CFNumberRef)[kernLoc objectAtIndex:1])

そして、それはいくつかのことに依存しているようです:

  1. [kernLoc objectAtIndex:1] が k = 0 の [NSNumber numberWithFloat:k] を参照する場合 (つまり、kernArray を設定する場所の上で k = 0 の場合)、プログラムはほぼ即座にクラッシュします。

  2. 行 k = k + kKern をコメントアウトすると、プログラムがクラッシュするまでに時間がかかりますが、最終的にはクラッシュします (なぜクラッシュがこの値に依存するのでしょうか?)

  3. CFRangeMake の長さを 1 から 0 に変更すると、プログラムがクラッシュするまでに時間がかかりますが、最終的にはクラッシュします。(attStringの境界を越えてアクセスしようとしているとは思いませんが、何か不足していますか?)

クラッシュすると、次のようなものが表示されます。

#0  0x942c7ed7 in objc_msgSend ()
#1  0x00000013 in ?? ()
#2  0x0285b827 in CFAttributedStringSetAttribute ()
#3  0x0000568f in op_TJ (scanner=0x472a590, info=0x4a32320) at /Users/Richard/Desktop/AppTest/PDFHighlight 2/PDFScannerOperators.m:251

何か案は?途中でメモリを上書きしたり、変更されたメモリにアクセスしようとしているようですが、わかりません。私が提供できる情報が他にある場合は、お知らせください。

ありがとう、リチャード

4

2 に答える 2

4

あなたのクラッシュは、どこかでオーバーリリースした結果のようです。特にコア ファンデーションと Cocoa を混在させている場合、問題の原因を突き止めるのは困難です。メモリ管理ルールは、コア基盤によって異なります。

次のように、データへのすべての参照を CFAttributedStringSetAttribute から引き出して、それらを NSLog したり、デバッガーで検査したりできるようにすると思います。

NSNumber* rangeStart = [kernLoc objectAtIndex:0];      // Debug: make sure it is a number
NSNumber attrValue = [kernLoc objectAtIndex:1];        // Debug: make sure it is a number
CFRange range = CFRangeMake([rangeStart intValue], 1); // Debug: make sure it is a valid range for the string
CFAttributedStringSetAttribute(attString, range, kCTKernAttributeName, (CFNumberRef)attrValue)
于 2010-06-07T09:17:59.877 に答える
2

フォローアップ - CFAttributedStringSetAttributes (複数) が進むべき道のようです。まだプログラムに実装する必要がありますが、小さなテストでは、この関数を使用すると、EXC_BAD_ACCESS クラッシュを発生させることなく、以前に定義した値を上書きできます。これがどこかに文書化されていればよかったのに。これが他の人々に役立つことを願っています。ありがとう!

于 2010-06-08T08:06:39.110 に答える