Advice on Debugging a UIAppFonts Issue on iPad - ipad

I recently found this post which seems to describe the same problem I am having with adding my own ttf. My app freezes. However, a few things about the post confuse me, and I'd love to get some help deciphering it.
The post is here: http://web.archiveorange.com/archive/v/nagQXB5eX3YsQpevIXMk
The relevant passages that I'm trying to understand are below:
Attaching the debugger and pausing
the application reveals a not
especially helpful call stack:
0 0xffff028f in __spin_lock
1 ??
Specific code that is causing the
problem:
CTFontCollectionRef collection =
CTFontCollectionCreateFromAvailableFonts(NULL);
CFArrayRef fonts =
CTFontCollectionCreateMatchingFontDescriptors(collection);
for(id fontDescRef in (NSArray
*)fonts) { CFStringRef fontName = CTFontDescriptorCopyAttribute((CTFontDescriptorRef)fontDescRef,
kCTFontNameAttribute); NSLog(#"%#",
fontName); CFRelease(fontName); }
CFRelease(fonts);
Execution never moves beyond the
second line.
Question: How did he figure out what line and function was causing the problem? Was this something having to do with displaying the disassembly, showing it in mixed mode, or looking up a hex value in a map file? I'd like to learn how this was done.
Having been asked to supply a demo and
hence having investigated further,
I've found that the problem manifests
if the code is in my
application:didFinishLaunchingWithOptions:
but not if I have the same stuff in
the viewDidLoad of my initial view
controller.
Question: what is 'the code' he's referring to here? The problem had to do with adding custom fonts through a plist value, so I'm not sure what he could be referring to or how I can workaround my issue.
Please Help!

Well, nothing on figuring out this post, but I did find a workaround posted by someone on the apple dev forums. Basically, calling this from the applicationDidFinishLaunching fn:
- (NSUInteger) loadFonts {
NSUInteger newFontCount = 0;
NSBundle *frameworkBundle = [NSBundle bundleWithIdentifier:#"com.apple.GraphicsServices"];
const char *frameworkPath = [[frameworkBundle executablePath] UTF8String];
if (frameworkPath) {
void *graphicsServices = dlopen(frameworkPath, RTLD_NOLOAD | RTLD_LAZY);
if (graphicsServices) {
BOOL (*GSFontAddFromFile)(const char *) = dlsym(graphicsServices, "GSFontAddFromFile");
if (GSFontAddFromFile)
for (NSString *fontFile in [[NSBundle mainBundle] pathsForResourcesOfType:#"ttf" inDirectory:nil])
newFontCount += GSFontAddFromFile([fontFile UTF8String]);
}
}
return newFontCount;
}
and making sure to include dlcfn.h and to cast the result of dlsym to the following:
(BOOL()(const char))
I did not alter the original post just in case this error was just something that affected me.

Related

Capturing NSLog Output with Firebase Crashlytics

I used to use Crashlytics long ago and there was a simple macro that could be used to capture all output from NSLog() to send it along with the crash report to Crashlytics. Very very helpful so that if a user has a crash, I can see the related logging that led up to it. I even had this working after Google gobbled up Crashlytics for awhile.
But a few years (many?) later and I'm trying to use Crashlytics in a new project and none of these macros are working anymore. The best I've come up with is the following :
#define NSLog(...) [[FIRCrashlytics crashlytics] logWithFormat:(__VA_ARGS__)]
However this generates compile warnings for every NSLog call and it does not appear to be compatible with anything either than NSStrings as arguments to the format. For instance the following will not compile...
NSLog (#"My Float Value : %f", myFloat);
I realize this is Objective C so my apologies to the Swift folk out there. Also I'm not sure if switching over to OSLog would actually help either. I'm just looking to capture the logging output so I can get some more information past just the stack trace. Otherwise this is no better than what TestFlight gives me and is therefore useless to add in for my use case.
Remove the parenthesis around the __VA_ARGS__ from the macro:
#define NSLog(...) [[FIRCrashlytics crashlytics] logWithFormat: __VA_ARGS__]
After doing that, I was able to call these NSLogs:
NSLog (#"My Float Value %f", 1.0);
NSLog (#"My Float string %s", "some string");
NSLog (#"My decimal Value %d", 963);
And this is the result I got in the crash report:
In order to resolve this for a call that has both a format string and values for that format string (NSLog (#"My Value %d", myValue);) and the case for just a single string (NSLog (#"Hello");) then the solution I found was this...
#define NSLog(__FORMAT__, ...) { NSString * str = [NSString stringWithFormat:__FORMAT__, ##__VA_ARGS__]; [[FIRCrashlytics crashlytics] log:str];}
However I ended up with this instead.
#define NSLog(__FORMAT__, ...) rrlog(__FORMAT__, ##__VA_ARGS__)
And this Class...
#interface RRLogger : NSObject
OBJC_EXTERN void rrlog(NSString* format, ...) NS_FORMAT_FUNCTION(1, 2);
#end
#implementation RRLogger
void rrlog(NSString* format, ...)
{
if (!format) return;
va_list args;
va_start(args, format);
NSString *msg = [[NSString alloc] initWithFormat:format arguments:args];
NSLogv(format, args);
va_end(args);
[[FIRCrashlytics crashlytics] log:msg];
}
#end
The reason for this is because the Firebase -FIRDebugEnabled launch argument in my launch scheme wasn't outputting everything to the console. I'm not sure why but it was missing some of the log output. Hence the call to NSLogv in the above function.

FB.AppRequest Crash

So I'm not sure if this is an issue with Unity or with the Facebook Unity SDK, or something I might be doing? It only started appearing recently, it was working perfectly fine up until I had to update Unity for iOS9 font issues.
The point at which it crashes in Xcode is:
+ (instancetype)instanceWithRequestID:(int)requestID
{
FBUnitySDKDelegate *instance = [[FBUnitySDKDelegate alloc] init];
instance->_requestID = requestID;
[g_instances addObject:instance]; // Breaks on this line. instance is nil
return instance;
}
And the code I am using for the AppRequest is
public void RequestLivesFromFriends(string[] friendIds)
{
if(!FB.IsLoggedIn)
{
LoginToFacebook ();
return;
}
FB.AppRequest(
"Please send me a life!",
Facebook.Unity.OGActionType.ASKFOR,
livesIdValue,
friendIds,
"RequestLife",
"Request a life from your friends",
requestLifeCallback
);
}
Is there currently an issue with the SDK's? Or am I just doing something wrong?
Well, I found the solution myself in the end.
I had -fno-objc-arc set as the Compiler Flag on FBUnitySDKDelegate.m
Apparently, having that on with the more recent versions of the SDK (or maybe something else was causing it, I'm not exactly sure) causes the NSMutableArray g_instances to be converted to an NSString. So when the code tries to add the FBUnitySDKDelegate object 'instance' to g_instances, it is trying to call addObject on an NSString, passing in an FBUnitySDKDelegate, which obviously doesn't work.
So yeah, if you have this problem, check for Compiler Flags on the file.

Does any know how to bypass entitlements in iOS 8?

As you aware that the famous _XPConnectionHasEntitlement has no longer works in iOS 8, is there anyother way to bypass the entitlements with the tweaks that requires entitlements? I come to know that _BSAuditTokenTaskHasEntitlement might solve the issue, but I can't get through it.
I'm using following snippet of code to hook into backboardd & assertionsd.
static int (*orig_BSAuditTokenTaskHasEntitlement)(id connection, NSString *entitlement);
static int hooked_BSAuditTokenTaskHasEntitlement(id connection, NSString *entitlement) {
NSLog(#"Got it.");
if (xpc_connection_get_pid(connection) == [[UIDevice currentDevice] __qrwaGetPIDForProcess:#"SpringBoard"] && [entitlement isEqualToString:#"com.apple.multitasking.unlimitedassertions"]) {
return 1;
} else {
return orig_BSAuditTokenTaskHasEntitlement(connection, entitlement);
}
}
%ctor {
%init;
MSHookFunction(((int *)MSFindSymbol(NULL, "_BSAuditTokenTaskHasEntitlement")), (int*) hooked_BSAuditTokenTaskHasEntitlement, (int**) &orig_BSAuditTokenTaskHasEntitlement);
}
The problem with it, the NSLog statements never printed. So I feel that something wrong with syntax of the function _BSAuditTokenTaskHasEntitlement, but not sure.
If anyone points me right direction, I appreciate their help.

If statement causes a crash in the iOS device but not in the Simulator

So, this code runs properly, without causing any crashes in the iOS simulator. However, on my iOS device (my iPhone), this causes a crash! Can anyone guess why? The logs haven't helped anywhere.
NSInteger loops = 1;
char character = '.';
if ([futureTr rangeOfString:[NSString stringWithFormat:#"%c",character]].location != NSNotFound) {
NSArray *dotsArray = [futureTr componentsSeparatedByString:[NSString stringWithFormat:#"%c",character]];
loops = [dotsArray count];
if ([[dotsArray objectAtIndex:loops-1] isEqualToString:#""] || [dotsArray objectAtIndex:loops-1] == nil) {
loops--;
}
}
And I know that it's this statement that causes trouble, because I comment it out and the app just works fine! What can be going on?
Based on the discussion in the comments, the problem is that futureTr is being released at some point and this code then attempts to use the now deallocated pointer resulting in the "BAD_ACCESS" exception.
Proper memory management of this variable will alleviate the problem.

CFReadStreamRead blocking forever under iOS 7

I'm seeing an issue wherein CFReadStreamRead, as part of a streamed file upload, never returns.
This seems to happen only on iOS7 — and far more often when debugging against a physical device than in the simulator — or at least, it's far more evident there.
We have an HTTP (or HTTPS, the problem occurs either way, with a locally-hosted or remote server) POST of a file, via straight-line, blocking (non-event-driven) CFNetwork calls. It's a necessity of the C code calling this handler; there's no provision for callbacks.
That's well and good, the network calls are happening in background threads and/or via async dispatch.
The network code in question boils down to (removing error handling for brevity):
CFReadStreamRef upload = CFReadStreamCreateWithFile(
kCFAllocatorDefault, upload_file_url);
CFRelease(upload_file_url);
CFReadStreamOpen(upload);
CFReadStreamRef myReadStream = CFReadStreamCreateForStreamedHTTPRequest(
kCFAllocatorDefault, myRequest, upload);
CFReadStreamOpen(myReadStream);
CFIndex numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf));
// etc.
On its own, this code wants to hang immediately under iOS7. If I add a loop with some calls to usleep before it (checking CFReadStreamHasBytesAvailable along the way), it will almost always succeed. Every few hundred tries, it will still fail, never returning. Again, the main thread is unaffected.
I'd hoped the GM would clear up this behavior, but it's still present.
Adding a runloop/callback method to watch for bytes-available events has no effect - when the call hangs, no events are seen, either.
Any suggestions as to why this is happening, or how it can be prevented? Anyone else seeing different CFReadStream behavior under iOS 7?
I've try such nasty workaround and it works for me, problem is that I'm requesting delta values from server, so if something goes wrong I'm just fetching new delta value with, in general case it will not work (in logs I see that timeout kicks in sometimes). At least this prevents form permanent thread blocking and gives a chance to handle somehow this problem:
NSInteger readStreamReadWorkaround(CFReadStreamRef readStrem, UInt8 *buffer, CFIndex bufferLength) {
static dispatch_once_t onceToken;
static BOOL isProblematicOs = YES;
dispatch_once(&onceToken, ^{
isProblematicOs = [[UIDevice currentDevice].systemName compare: #"7.0" options: NSNumericSearch]!=NSOrderedAscending;
});
NSInteger readBytesCount = -2;
if (isProblematicOs) {
CFStreamStatus sStatus = CFReadStreamGetStatus(readStrem);
NSDate *date = [NSDate date];
while (YES) {
if(CFReadStreamHasBytesAvailable(readStrem)) {
readBytesCount = CFReadStreamRead(readStrem, buffer, bufferLength);
break;
}
sStatus = CFReadStreamGetStatus(readStrem);
if (sStatus!=kCFStreamStatusOpen && sStatus !=kCFStreamStatusAtEnd
|| [date timeIntervalSinceNow]<-15.0) {
break;
}
usleep(50000);
}
} else {
readBytesCount = CFReadStreamRead(readStrem, buffer, sizeof(buffer));
}
return readBytesCount;
}
I don't like this solution but so far I don't see an alternative.

Resources