Google Analytics IOS v2(beta) crash under ARC - cocoa-touch

I get the following crash from Google Analytics v2.0 beta 3:
It's started by:
__45-[GAIDispatcher queueDispatch:url:timestamp:]_block_invoke_0 + 119 at GAIDispatcher.m:633
Followed by:
-[GAIDispatcher persistAndDispatch:url:timestamp:] + 427 at GAIDispatcher.m:525
The error is:
** -[__NSDictionaryM setObject:forKey:]: message sent to deallocated instance 0xb68c690
My setup is as follows:
I have an app that uses ARC (the limited one.. from ios 4.3)
My app supports a minimum SDK of 4.3, developed under SDK 6.0.
The crash appears only on the simulator (works fine on device) and it's a EXC_BREAKPOINT(code=EXC_I386_BPT, subcode=0x0)
All I have in my code is this, in applicationDidFinishLaunching:
[GAI sharedInstance].trackUncaughtExceptions = NO;
// Optional: set Google Analytics dispatch interval to e.g. 20 seconds.
[GAI sharedInstance].dispatchInterval = 5;
// Optional: set debug to YES for extra debugging information.
[GAI sharedInstance].debug = YES;
// Create tracker instance.
id<GAITracker> tracker = [[GAI sharedInstance] trackerWithTrackingId:UA_NUMBER];
[tracker trackEventWithCategory:#"TestV1"
withAction:#"ActionV1"
withLabel:#"LabelV1"
withValue:[NSNumber numberWithInt:10]];
Any ideas on what might be wrong?
Your help is greatly appreciated,
Thanks!
P.S.: This is the Zombie detected when running with the Zombies tool.
# Address Category Event Type RefCt Timestamp Size Responsible Library Responsible Caller
0 0xd18fe30 __NSDictionaryM Malloc 1 00:20.889.002 32 PostcodeGazette -[GAIDispatcher queueDispatch:url:]
1 0xd18fe30 __NSDictionaryM Autorelease 00:20.889.015 0 PostcodeGazette -[GAIDispatcher queueDispatch:url:]
2 0xd18fe30 __NSDictionaryM Release 0 00:24.832.529 0 UIKit _UIApplicationHandleEvent
3 0xd18fe30 __NSDictionaryM Zombie -1 00:25.067.003 0 PostcodeGazette -[GAIDispatcher persistAndDispatch:url:timestamp:]

Related

macOS deprecated APIs

The company I work for has developed a program and the last time the code was touched was 2 years ago. Now the program needs to become notarized so I was asked to take care of the program.
I ported the code to latest Xcode (10.2.1) and latest macOS. But Xcode warns me about the deprecation of a few API calls:
/Users/rowelz/Documents/Develop/Code/ThinPrint/in GIT/myProject/osx-client/src/com.myProject.bootstrap/EZPBootstrapper.m:116:51: 'SMJobCopyDictionary' is deprecated: first deprecated in macOS 10.10
NSDictionary *plist = (__bridge NSDictionary *) SMJobCopyDictionary(
kSMDomainSystemLaunchd, (__bridge CFStringRef) (label));
/Users/rowelz/Documents/Develop/Code/ThinPrint/in GIT/myProject/osx-client/src/com.myProject.bootstrap/EZPBootstrapper.m:193:21: 'SMJobRemove' is deprecated: first deprecated in macOS 10.10
result = (BOOL) SMJobRemove(kSMDomainSystemLaunchd,
(__bridge CFStringRef) label, self->_authRef, FALSE, &cfError);
/Users/rowelz/Documents/Develop/Code/ThinPrint/in GIT/myProject/osx-client/src/com.myProject.bootstrap/EZPAppDelegate.m:193:15: 'SMJobSubmit' is deprecated: first deprecated in macOS 10.10
submitted = SMJobSubmit(kSMDomainUserLaunchd, (__bridge CFDictionaryRef)(plist), NULL, &cfError);
/Users/rowelz/Documents/Develop/Code/ThinPrint/in GIT/ezeep/osx-client/src/com.myProject.bootstrap/EZPAppDelegate.m:214:13: 'SMJobRemove' is deprecated: first deprecated in macOS 10.10
removed = SMJobRemove(kSMDomainUserLaunchd, (__bridge CFStringRef)kEzeepServiceNameUpdaterBstrap, NULL, false, NULL);
My Supervisor in this project gave the following boundary conditions:
Program should work during the next one year only. After that It will be replaced by another program of our house.
During this year it should work without limitations, crashes and so on.
I would prefer not to make any changes to the code, since the warnings regarding SMJobCopyDictionary, SMJobRemove and SMJobSubmit means that there is a big change to do - the whole program has to be written anew. And this would be a big effort for a one year life-span.
My Question:
I would like to write a little tool that checks for the availability of these API calls. I will then execute this tool on every beta of macOS until the final release of macOS 10.15. Of course if that tool shows a problem I will then rewrite the "now defective" program.
Would that be sufficient to detect a problem with the existence of the API? And what function can I use to detect the availability without actually calling them trying to install a launchd binary? I guess the above APIs are CoreFoundation ?
Thanks in advance for you help.
I found this here at stack overflow and it seems to work:
#include <dlfcn.h>
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
BOOL notFound = NO;
void *lib = dlopen("/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement", RTLD_LAZY);
if(lib == NULL)
{
printf("Library not found. (/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement).\n");
exit(1);
}
void *function1 = dlsym(lib, "SMJobCopyDictionary");
if(function1 == NULL)
{
printf("Function not found: SMJobCopyDictionary\n");
notFound = YES;
}
// .... and so on
dlclose(lib);
if(notFound)
{
exit(1);
}
printf("Ok, all functions found.\n");
}
return 0;
}
will that be sufficient to show a call to a deprecated and removed API?
This is speculation, but I feel confident in it: Apple will not remove these APIs from 10.15. Deprecating APIs is done regularly, but actually removing them breaks existing applications and is done very rarely.
It is possible (though unlikely I think) that they will remove the headers from the 10.15 SDK, in which case you will need to keep building against the 10.14 SDK (using Xcode 10).
And if the 10.15 SDK still contains the headers, the situation is the same as it is now and you won't have any problems.

CoreMediaIO, an alleged OS Bug / Memory Leak

Environment
OS-X 10.10
xcode 6.4
C++/Obj-C OS-X application
Use-case
Capture video using CoreMediaIO, capture source is iPod5
Capturing machine is OS-X Yosemite
Capture feed consists of Video and Audio samples
Problem description
While video capture is working fine, when video samples are received, there is an accumulating memory leak, when no video samples are received ( only audio ), there is no leak ( memory consumption stops growing )
I am mixing Cocoa thread and POSIX threads, I have made sure to have [NSThread isMultiThreaded] set to YES ( by creating an empty NSThread )
"Obj-C Auto Ref Counting" is set to YES in the project properties
The following is a short code-snap of the code causing the leak:
OSStatus status = 0;
#autoreleasepool {
m_udid = udid;
if (0 != (status = Utils::CoreMediaIO::FindDeviceByUDID(m_udid, m_devId)))
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
if (0 != (status = Utils::CoreMediaIO::GetStreamByIndex(m_devId, kCMIODevicePropertyScopeInput, 0, m_strmID)))
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
status = Utils::CoreMediaIO::SetPtopertyData(m_devId, kCMIODevicePropertyExcludeNonDALAccess, 1U);
status = Utils::CoreMediaIO::SetPtopertyData<int>(m_devId, kCMIODevicePropertyDeviceMaster, getpid());// Exclusive access for the calling process
// Results in an infinitely accumulating memory leak
status = CMIOStreamCopyBufferQueue(m_strmID, [](CMIOStreamID streamID, void* token, void* refCon) {
#autoreleasepool {
CMSampleBufferRef sampleBuffer;
while(0 != (sampleBuffer = (CMSampleBufferRef)CMSimpleQueueDequeue(m_queueRef))) {
CFRelease(sampleBuffer);
sampleBuffer = 0;
}
}
}, this, &m_queueRef);
if(noErr != status)
return E_FAIL;
if(noErr != (status = CMIODeviceStartStream(m_devId, m_strmID)))
return E_FAIL;
}
Having sample de-queuing done in the main thread ( using 'dispatch_async(dispatch_get_main_queue(), ^{' ) didn't have any affect...
Is there anything wrong with the above code snap? might this be an OS Bug?
Reference link: https://forums.developer.apple.com/message/46752#46752
AN UPDATE
The QuickTime player support using an iOS device as a capture source ( mirroring it's A/V to the mac machine ), having a preview session running for a while reproduce the above mentioned problem w/ the OS provided QuickTime player, this strongly indicate an OS Bug, bellow is a screen-shot showing the QT player taking 140Mb of RAM after running for ~2hours ( where it starts around 20Mb ), by the end of the day it has grown to ~760Mb...
APPLE Please have this Fixed, I have standing customers commitments...

NSProxy pretending to be Class doesn't handle respondsToSelector in 64-bit runtime

In OCMockito, test doubles are implemented with NSProxy. A double standing in for an instance implements -respondsToSelector: as follows:
- (BOOL)respondsToSelector:(SEL)aSelector {
return [_mockedClass instancesRespondToSelector:aSelector];
}
But a double standing in for a class implements -respondsToSelector: like this:
- (BOOL)respondsToSelector:(SEL)aSelector {
return [_mockedClass respondsToSelector:aSelector];
}
This all works in the 32-bit runtime. For example, if _mockedClass is [NSString class], the proxy correctly answers that it responds to the selector +pathWithComponents:
But in the 64-bit runtime, it crashes:
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: EXC_I386_GPFLT
Application Specific Information:
objc[1868]: GC: forcing GC OFF because OBJC_DISABLE_GC is set
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff95cbffc6 cache_getImp + 6
1 libobjc.A.dylib 0x00007fff95ccd1dc lookUpImpOrForward + 50
2 libobjc.A.dylib 0x00007fff95ccd198 lookUpImpOrNil + 20
3 libobjc.A.dylib 0x00007fff95cc218a class_respondsToSelector + 37
4 com.apple.CoreFoundation 0x00007fff91c131ad ___forwarding___ + 429
5 com.apple.CoreFoundation 0x00007fff91c12f78 _CF_forwarding_prep_0 + 120
6 org.mockito.OCMockitoTests 0x000000010451a55b -[StubClassTest testStubbedMethod_ShouldReturnGivenObject] + 107 (StubClassTest.m:48)
Note that it's calling class_respondsToSelector(…). I suspect that I'm being bitten by an optimization made to the runtime. What can I do to fix this?
it's a bit long answer, so bear with me. I ran a simple code just to verify the behavior:
Class mock = mockClass([NSProcessInfo class]);
[mock processInfo];
[verify(mock) processInfo];
Indeed It does crash with bad pointer exception. Replacing first line with
id mock = mockClass([NSProcessInfo class]);
works as expected. I figured that it might be worth to look at the code after ARC. Those snippets are a bit to long, so here are the gists: Class-based test, id-based test
As you can see, when you declare variable of type Class there is an extra release. My guess is that since classes are registered for the entire runtime duration (unless removed using runtime api) it's ok to have Class variable as __unsafe_unretained.
To summarize, you have two possible solutions:
#implementation StubClassTest
{
__strong Class mockClass;
}
or
#implementation StubClassTest
{
id mockClass;
}
seem to fix the issue for me.
Update
As a special case, if the object’s base type is Class (possibly protocol-qualified), the type is adjusted to have __unsafe_unretained qualification instead.
From http://clang.llvm.org/docs/AutomaticReferenceCounting.html#objects

iOS 6.1 AudioQueueStop, AudioQueueDispose error

Using Audio Queue for my iOS App, I have some problem with a test on iOS6.1, though it has worked fine on iOS6.
The problem is AudioQueueStop and AudioQueueDispose don't return immediately, or sometimes they crash.
Like this:
if (_audioQueue)
{
auto err = AudioQueueStop(_audioQueue, true); // Some delay before return
for (int i = 0; i < kNumberAudioQueueBuffers; i++) {
AudioQueueFreeBuffer(_audioQueue, _audioQueueBuffer[i]);
}
err = AudioQueueDispose(_audioQueue, true); // This also has delay
_audioQueue = nil;
}
This isn't called on main thread but another thread, but other stuffs such as AudioQueueNewoutput and AudioQueueStart also called on that thread.
Actually I tried to run a simple app which uses AudioQueue as a test and in that case it worked fine (on both of iOS6 and 6.1). So other parts in my codes might affect but I couldn't figure out.
Is there anyone who had similar problems and hopefully fixed?
I'm seeing similar issues with AudioQueueSetProperty() and kAudioQueueProperty_MagicCookie. My app crashes every single time this is called, when it worked fine on iOS 6.0 and earlier. I'm thinking Apple messed up the audio queue implementation in 6.1.

How do I reference iOS 4.0 only enums in a project with a deployment target < 4.0?

I am attempting to write an app for iOS that will take advantage of iOS 4.0 features, but also work on an earlier version of the OS (3.1.3). I have set the deployment target to 3.1.3 and the Base SDK to 4.3 (latest)
Specifically, I am trying to take advantage of the ability to intercept commands from the remote control.
The document linked below is very useful in explaining how to (at run-time) check for the presence of classes and methods, but I still get a compiler error when attempting to reference an enum from the UIEvent class which only appears in iOS 4.0 and later.
https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Using/using.html#//apple_ref/doc/uid/20002000-SW3
Here is the section of code which causes the compilation to fail:
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
[self playPauseAction:nil];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
[self previousChapter:nil];
break;
case UIEventSubtypeRemoteControlNextTrack:
[self nextChapter:nil];
break;
default:
break;
}
}
}
The compiler complains that:
error: 'UIEventTypeRemoteControl' undeclared (first use in this function)
UIEventTypeRemoteControl is an enum that isn't defined until 4.0
(from UIEvent.h)
typedef enum {
UIEventTypeTouches,
UIEventTypeMotion,
UIEventTypeRemoteControl,
} UIEventType;
typedef enum {
// available in iPhone OS 3.0
UIEventSubtypeNone = 0,
// for UIEventTypeMotion, available in iPhone OS 3.0
UIEventSubtypeMotionShake = 1,
// for UIEventTypeRemoteControl, available in iOS 4.0
UIEventSubtypeRemoteControlPlay = 100,
UIEventSubtypeRemoteControlPause = 101,
UIEventSubtypeRemoteControlStop = 102,
UIEventSubtypeRemoteControlTogglePlayPause = 103,
UIEventSubtypeRemoteControlNextTrack = 104,
UIEventSubtypeRemoteControlPreviousTrack = 105,
UIEventSubtypeRemoteControlBeginSeekingBackward = 106,
UIEventSubtypeRemoteControlEndSeekingBackward = 107,
UIEventSubtypeRemoteControlBeginSeekingForward = 108,
UIEventSubtypeRemoteControlEndSeekingForward = 109,
} UIEventSubtype;
So how do I stop the compiler complaining about it?
Also - how do i stop the compiler warnings that someClass may not respond to someMethod (where I check at runtime if that class does actually respond to the method, before calling it.) I suppose I could turn off that warning in the compiler settings - but it's a useful warning in other cases.
OK - Here's what I have discovered:
Switching the deployment_target to 4.3 then 3.1.3 causes the compilation errors and warnings to appear.
Once they appear you can get rid of them by compiling using a simulator scheme.
Once you have done that, you can compile using a real device scheme and the errors and warnings are gone.