FontAwesomeKit icon indicating copy to clipboard operation
FontAwesomeKit copied to clipboard

FontAwesome font deallocated, causing crash

Open Ziewvater opened this issue 11 years ago • 20 comments

I'm having an issue where I believe FontAwesomeKit is causing my app to crash. When I am presenting views that contain FontAwesome icons created using FontAwesomeKit, the app can crash with an EXC_BAD_ACCESS exception. There are particular situations which are guaranteed to cause a crash, and I've given a pretty complete description here. Additionally, when Guard Malloc is enabled, the app will crash on every view that contains a FontAwesome icon.

We've recently found that removing FontAwesomeKit from our project entirely will result in our app no longer crashing in the problematic views. It seems like when iOS is trying to determine the height of a FontAwesome attributed string icon, the FontAwesome font is deallocated when CoreText tries to access it (there's a stack trace at the above link that may help illustrate what is going on here a bit better).

Not sure if it makes a difference, but we are including FontAwesomeKit in our project through Cocoapods.

Ziewvater avatar Dec 04 '13 01:12 Ziewvater

There isn't enough context to figure out what's wrong, have you ever used Instrument with zombie template to find out which object is causing the EXC_BAD_ACCESS? It would be nice if you could post some code about how you're using FontAwesomeKit on UI elements, especially the part that you believe is causing the crash.

PrideChung avatar Dec 04 '13 06:12 PrideChung

I've tried using NSZombies but unfortunately it doesn't give me any useful information.

I believe the problematic code is my subclass of UIBarButtonItem that I use to create navigation bar and toolbar buttons. The buttons are created with the following code. Is there something in there that I'm doing wrong?

#define ICON_SIZE 20 // icon size for all iconified bar buttons
- (id)initWithTitle:(NSString *)title
              style:(UIBarButtonItemStyle)style
             target:(id)target
             action:(SEL)action
{
    self = [super initWithTitle:title
                          style:style
                         target:target
                         action:action];

    // Set the font for the button
    UIFont *font = [FAKFontAwesome iconFontWithSize:ICON_SIZE];
    NSDictionary *buttonDict = @{NSFontAttributeName : font};
    [self setTitleTextAttributes:buttonDict forState:UIControlStateNormal];
    self.tintColor = [CLAppearanceManager colorForType:CLAppearanceColorTypeCellyCascade];

    return self;
}

+ (CLYBarButtonItem *)buttonWithStyle:(CLYBarButtonItemStyle)style
                               target:(id)target
                               action:(SEL)action
{
    NSAttributedString *title = [CLYBarButtonItem titleForStyle:style];
    UIBarButtonItemStyle uiStyle = UIBarButtonItemStylePlain;

    CLYBarButtonItem *button = [[CLYBarButtonItem alloc] initWithTitle:[title string]
                                                                 style:uiStyle
                                                                target:target
                                                                action:action];
    [button setButtonStyle:style];
    return button;
}

+titleForStyle: looks like the following, but is truncated to take up less space

+ (NSAttributedString *)titleForStyle:(CLYBarButtonItemStyle)style
{
    NSAttributedString *title;
    switch (style) {
        case CLYBarButtonItemStyleApprove:
            title = [[FAKFontAwesome checkIconWithSize:ICON_SIZE] attributedString];
            break;
        ... // Other style titles are defined
    }
    return title;
}

CLYBarButtonItemStyle is an enum defined in the following way:

typedef NS_ENUM(NSInteger, CLYBarButtonItemStyle) {
    ... // CLYBarButtonItemStyles defined
};

Ziewvater avatar Dec 04 '13 06:12 Ziewvater

I copied your code into a test project, works fine. Have you tried to put a break point to find out which line is causing the crash?

PrideChung avatar Dec 04 '13 07:12 PrideChung

I've tried breakpointing but as far as I can tell, what is causing my app to crash, while running it normally, is trying to present a UIImagePickerController while the FontAwesome font is in use in the app. Looking over the crashes more, it doesn't seem like the font that is being deallocated is the FontAwesome font itself, but rather the other font I have included in my app for the majority of displayed text (I'm using multiple weights of Open Sans, which have been listed in my info plist).

I have also found that these crashes will happen in more places when running with Guard Malloc enabled. One of the crashes occurs when I'm trying to set the back bar item for one of my view controllers. The code for this is as follows:

- (void)setUpView
{
    UIBarButtonItem *backTextButton = [[UIBarButtonItem alloc] initWithTitle:@"Celly"
                                                                       style:UIBarButtonItemStylePlain
                                                                      target:self.navigationController
                                                                      action:@selector(popViewControllerAnimated:)];
    self.navigationItem.backBarButtonItem = backTextButton;
}

When Guard Malloc is enabled, the app crashes when setting the navigationItem's backBarButtonItem property, spitting out the following stack trace:

#0  0x00f69bde in TComponentFont::GetSymbolicTraitsInternal() const ()
#1  0x00f5e3a5 in TBaseFont::GetSymbolicTraits(bool) const ()
#2  0x00f08551 in TFont::GetEffectiveSize() const ()
#3  0x00f01dd1 in TFont::GetScaleFactor() const ()
#4  0x00efc1e7 in CTFontGetGlyphsAndAdvancesForCharacterRange ()
#5  0x04707b06 in GSFontGetLatin1LayoutInfo ()
#6  0x0972b2c4 in -[UIFont(UIFont_AttributedStringDrawing) _getLatin1GlyphMapping:andAdvanceMapping:] ()
#7  0x096fb97e in __NSStringDrawingEngine ()
#8  0x096fe30b in -[NSAttributedString(NSExtendedStringDrawing) boundingRectWithSize:options:context:] ()
#9  0x01dd6647 in -[UILabel _textRectForBounds:limitedToNumberOfLines:includingShadow:] ()
#10 0x01dd62d0 in -[UILabel textRectForBounds:limitedToNumberOfLines:] ()
#11 0x01dd96db in -[UILabel _intrinsicSizeWithinSize:] ()
#12 0x01dd994e in -[UILabel sizeThatFits:] ()
#13 0x01ced4e6 in -[UINavigationItemView _titleSize] ()
#14 0x01cecd49 in -[UINavigationItemView _labelFrame] ()
#15 0x01cee68a in -[UINavigationItemButtonView _labelFrame] ()
#16 0x01cec4a3 in -[UINavigationItemView initWithNavigationItem:] ()
#17 0x01cc05b6 in -[UINavigationItem backButtonView] ()
#18 0x01cbfe1c in -[UINavigationItem setBackBarButtonItem:] ()
#19 0x000e27dd in -[CLLeftPanelViewController setUpView] at /Users/JeremyYL/Dropbox/Celly/celly-ios/Celly/Celly/CLLeftPanelViewController.m:173
#20 0x000e2bb4 in __42-[CLLeftPanelViewController downloadCells]_block_invoke at /Users/JeremyYL/Dropbox/Celly/celly-ios/Celly/Celly/CLLeftPanelViewController.m:196
#21 0x000a3a04 in __47+[CLCell(Network) downloadCellsWithCompletion:]_block_invoke_2 at /Users/JeremyYL/Dropbox/Celly/celly-ios/Celly/Celly/CLCell+Network.m:48
#22 0x0009f18e in __79+[CLNetClient downloadWithAction:parameters:coreDataHandler:successCompletion:]_block_invoke_3 at /Users/JeremyYL/Dropbox/Celly/celly-ios/Celly/Celly/CLNetClient.m:336
#23 0x038a27f8 in _dispatch_call_block_and_release ()
#24 0x038b74b0 in _dispatch_client_callout ()
#25 0x038a575e in _dispatch_main_queue_callback_4CF ()
#26 0x0366da5e in __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ ()
#27 0x035ae6bb in __CFRunLoopRun ()
#28 0x035adac3 in CFRunLoopRunSpecific ()
#29 0x035ad8db in CFRunLoopRunInMode ()
#30 0x0470d9e2 in GSEventRunModal ()
#31 0x0470d809 in GSEventRun ()
#32 0x01c29d3b in UIApplicationMain ()
#33 0x0000c8fd in main at /Users/JeremyYL/Dropbox/Celly/celly-ios/Celly/Celly/main.m:17

It should be noted that the -setUpView method is called without issue previous to this crash, in the view controller's viewDidLoad, and only causes the app to crash when called after the view appears with a FontAwesome icon in view. Commenting out this code results in other crashes that are still related to the UINavigationBar, with stack traces like the following:

#0  0x00f69bde in TComponentFont::GetSymbolicTraitsInternal() const ()
#1  0x00f5e3a5 in TBaseFont::GetSymbolicTraits(bool) const ()
#2  0x00f08551 in TFont::GetEffectiveSize() const ()
#3  0x00f01dd1 in TFont::GetScaleFactor() const ()
#4  0x00efc1e7 in CTFontGetGlyphsAndAdvancesForCharacterRange ()
...

Removing FontAwesomeKit from the project entirely stops these crashes from occurring. Commenting out the body of +iconFontWithSize: in FAKFontAwesome and just returning a system font also causes the crashes to stop, leading me to believe that the dynamic registration of the FontAwesome font is conflicting with the other fonts I am using in my app. Do you know if there are existing issues with using both dynamically registered fonts and fonts included in the info plist?

Ziewvater avatar Dec 04 '13 20:12 Ziewvater

It's hard to tell what happened from stack trace, multiple dynamically registered fonts usually won't conflict with each other, even if they registered with the same name, the new one will replace the old one, but won't cause any crash. You can try to create a new blank view controller and use icon fonts on labels to rule out other possible variables, if it does crash, try to add a exception breakpoint to figure out the exact line that causing crash, then run po [UIFont familyNames] in the debugger to check if FontAwesome is registered correctly.

PrideChung avatar Dec 05 '13 07:12 PrideChung

I've tried using an exception breakpoint but unfortunately it isn't triggered by this crash. The app simply crashes with EXC_BAD_ACCESS without any information.

I tried running po [UIFont familyNames] right before presenting the UIImagePickerController, and it seems like both Open Sans and FontAwesome are registered, but the app still crashes when trying to calculate the height of one particular font for some label. Further inspection has shown that the problematic label is likely using the system font, instead of Open Sans. Still, even though this is the case, removing FontAwesome from the project or replacing the code in FAKFontAwesome iconFontWithSize: to just return a system font prevents this crash.

I am going to try and play with the way my app registers and accesses the other fonts included in the project, probably try methods similar to what you are using instead of typing them into the plist, and see if that does any good. I will let you know what happens and how things go.

Ziewvater avatar Dec 06 '13 19:12 Ziewvater

Hi @Ziewvater, how's things going? I came up with a new idea, have you ever tried to register the Font-Awesome font manually and use it without FontAwesomeKit? The cause of crashes may be dynamic registration.

PrideChung avatar Dec 21 '13 08:12 PrideChung

Hey, sorry for the late response. I have done something similar to what you suggested: I created a local cocoapod repository for FontAwesomeKit, commented out the dynamic registration code in FAKFontAwesome.m, and manually registered the .otf file in my project's .plist file. Since doing this, I have not been having the same issues I had previously. I'm still not sure what was causing the problem before, but manual registration seems to have resolved the issue.

Ziewvater avatar Jan 06 '14 19:01 Ziewvater

Good, I will add an optional macro for excluding those auto registration code.

PrideChung avatar Jan 07 '14 04:01 PrideChung

@Ziewvater I've made a new version to provide some macros to disable auto registration, get an update with cocoapods, document is here: ~~https://github.com/PrideChung/FontAwesomeKit#disabling-icon-font-auto-registration~~ (Documentation has been moved to Known Issue)

This is just a workaround, I leave you to decide whether close this issue, you can reopen it later if it's closed by you. I'm still curious about the reason causing your crash, it would be nice if you could reproduce the bug with a demo later.

PrideChung avatar Jan 12 '14 15:01 PrideChung

@PrideChung I am using FontAwesomeKit in RubyMotion using CocoaPods and I have the same issue. The big problem is that macros are not supported (yet) in RubyMotion. Any suggestions?

RobertAudi avatar Jan 24 '14 18:01 RobertAudi

I removed the lines that register the fonts in FontAwesomeKit/FAKFontAwesome.m, FontAwesomeKit/FAKFoundationIcons.m, FontAwesomeKit/FAKIonIcons.m and FontAwesomeKit/FAKZocial.m and the problem still occurs. Here is the error message:

malloc: *** error for object 0x8e19490: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

I don't know if that is a RubyMotion issue or an issue with this library though...

RobertAudi avatar Jan 24 '14 23:01 RobertAudi

OK, apparently I did a stupid mistake. Problem solved....Sorry, nothing to do with this issue.

RobertAudi avatar Jan 25 '14 00:01 RobertAudi

@AzizLight Could you specify how you solved your problem? It might be helpful.

PrideChung avatar Jan 25 '14 03:01 PrideChung

@PrideChung I was creating a wrapper around FontAwesomeKit. I created a class (in Ruby, but that's irrelevant) with an initWithAwesomeIcon:withSize method (among other init methods) where I called the appropriate FAK*.*IconWithSize: method. Example: initWithAwesomeIcon(:star, withSize:10) would call FAKFontAwesome.starIconWithSize(10). I used metaprogramming to do that, but again, that's irrelevant.

Anyway, the problem was that I was essentially calling an init method inside of an init method (because FAKFontAwesome.starIconWithSize(10) calls an init method behind the scenes), and that caused the malloc error. The fix, in my case, was to only create class methods that call the FAK*.*IconWithSize: methods.

For an concrete example of what I am talking about, look at this diff.

RobertAudi avatar Jan 25 '14 11:01 RobertAudi

@AzizLight I never used RubyMotion before but I got your main idea, not related to this issue though. Thanks for creating RubyMotion wrapper for FAK by the way.

PrideChung avatar Jan 25 '14 12:01 PrideChung

I'm pretty sure I'm seeing this issue as well, but I haven't had a lot of time to debug the underlying cause. I think I've worked around the issue by calling [* iconFontWithSize] immediately in the AppDelegate like in #13

@PrideChung I did want to mention that the 2.1.4 tag doesn't include the DISABLE_*_AUTO_REGISTRATION workaround. Looks like that code slipped through the cracks a bit.

bmalkowski avatar Feb 27 '14 15:02 bmalkowski

@bmalkowski Oops, my mistake about those workaround macros. Anyway, I will come up a new way to handle the font registration and make a new release weekend, those macros will be useless by then.

PrideChung avatar Feb 28 '14 00:02 PrideChung

Hey @PrideChung that link to the registration disables are broken - is this fixed now? We'd love to move back on to your cocoapod instead of our private repo with the font registration fix.

z-br avatar Jul 22 '14 01:07 z-br

@gregpassmore I can't find a way to fix it because it's a Core Text framework level issue, but I did find a workaround. I moved that part of documentation to a separated file with more info: Known Issue

PrideChung avatar Jul 22 '14 01:07 PrideChung