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

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

Related

How to detect that a thread has started using javassist?

I have to instrument any given code (without directly changing given code ) at the beginning and end of every thread. Simply speaking , how can I print something at entry and exit points of any thread.
How can I do that using javassist ?
Short Answer
You can do this by creating an ExprEditor and use it to modify MethodCalls that match with start and join of thread objects.
(very) Long answer (with code)
Before we start just let me say that you shouldn't be intimidated by the long post, most of it is just code and once you break things down it's pretty easy to understand!
Let's get busy then...
Imagine you have the following dummy code:
public class GuineaPig {
public void test() throws InterruptedException {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 10; i++)
System.out.println(i);
}
});
t.start();
System.out.println("Sleeping 10 seconds");
Thread.sleep(10 * 1000);
System.out.println("Done joining thread");
t.join();
}
}
When you run this code doing
new GuineaPig().test();
You get an output like (the sleeping system.out may show up in the middle of the count since it runs in the main thread):
Sleeping 10 seconds
0
1
2
3
4
5
6
7
8
9
Done joining thread
Our objective is to create a code injector that will make the output change for the following:
Detected thread starting with id: 10
Sleeping 10 seconds
0
1
2
3
4
5
6
7
8
9
Done joining thread
Detected thread joining with id: 10
We are a bit limited on what we can do, but we are able to inject code and access the thread reference. Hopefully this will be enough for you, if not we can still try to discuss that a bit more.
With all this ideas in mind we create the following injector:
ClassPool classPool = ClassPool.getDefault();
CtClass guineaPigCtClass = classPool.get(GuineaPig.class.getName());
guineaPigCtClass.instrument(new ExprEditor() {
#Override
public void edit(MethodCall m) throws CannotCompileException {
CtMethod method = null;
try {
method = m.getMethod();
} catch (NotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String classname = method.getDeclaringClass().getName();
String methodName = method.getName();
if (classname.equals(Thread.class.getName())
&& methodName.equals("start")) {
m.replace("{ System.out.println(\"Detected thread starting with id: \" + ((Thread)$0).getId()); $proceed($$); } ");
} else if (classname.equals(Thread.class.getName())
&& methodName.equals("join")) {
m.replace("{ System.out.println(\"Detected thread joining with id: \" + ((Thread)$0).getId()); $proceed($$); } ");
}
}
});
guineaPigCtClass
.writeFile("<Your root directory with the class files>");
}
So what's happening in this small nifty piece of code? We use an ExprEdit to instrument our GuineaPig class (without doing any harm to it!) and intercept all method calls.
When we intercept a method call, we first check if the declaring class of the method is a Thread class, if that's the case it means we are invoking a method in a Thread object. We then proceed to check if it's one of the two particular methods start and join.
When one of those two cases happen, we use the javassist highlevel API to do a code replacement. The replacement is easy to spot in the code, the actual code provided is where it might be a bit tricky so let's split one of those lines, let's take for example the line that will detect a Thread starting:
{ System.out.println(\"Detected thread starting with id: \" + ((Thread)$0).getId()); $proceed($$); } "
First all the code is inside curly brackets, otherwise javassist won't accept it
Then you have a System.out that references a $0. $0 is a special parameter that can be used in javassist code manipulations and represents the target object of the method call, in this case we know for sure it will be a Thread.
$proceed($$) This probably is the trickiest instruction if you're not familiar with javassist since it's all javassist special sugar and no java at all. $proceed is the way you have to reference the actual method call you are processing and $$ references to the full argument list passed to the method call. In this particular case start and join both will have this list empty, nevertheless I think it's better to keep this information.
You can read more about this special operators in Javassist tutorial, section 4.2 Altering a Method Body (search for MethodCall subsection, sorry there's no anchor for that sub-section)
Finally after all this kung fu we write the bytecode of our ctClass into the class folder (so it overwrites the existing GuinePig.class file) and when we execute it... voila, the output is now what we wanted :-)
Just a final warning, keep in mind that this injector is pretty simple and does not check if the class has already been injected so you can end up with multiple injections.

Typhoon - Runtime Configurable Components Using Storyboard

When my application starts I fetch a remote config file containing information (URLs, etc) required to configure other dependencies.
After I fetch the remote config I have a Config object that I need to supply to other TyphoonDefinitions.
Now I am also using the plist storyboard integration.
I was originally going down the path of injecting the assembly into the ViewController that loads the Config object, and when I receive the remote config and create the Config object, I would somehow set it as a property on the assembly. I did this hoping that I could then use the property in the definitions, but this did not work and I got:
2014-10-22 21:18:06.203 four[39840:516543] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'No component matching id 'setConfig:'.'
*** First throw call stack:
(
0 CoreFoundation 0x000000010a3e63f5 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010a07fbb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010a3e632d +[NSException raise:format:] + 205
3 four 0x00000001070a011d -[TyphoonComponentFactory componentForKey:args:] + 148
4 CoreFoundation 0x000000010a2de22c __invoking___ + 140
5 CoreFoundation 0x000000010a2de082 -[NSInvocation invoke] + 290
6 CoreFoundation 0x000000010a36d456 -[NSInvocation invokeWithTarget:] + 54
7 four 0x000000010709d358 -[TyphoonBlockComponentFactory forwardInvocation:] + 276
Is there any way for me to inject an object into an assembly at runtime?
Is there a cleaner way to do what I'm trying to do?
I was reading about run-time arguments which sounds like what I need, but I really don't understand the docs.
For example, I have this as a definition. I need to pass the runtime Config object as a parameter to the constructor.
- (id<ApiService>)apiService
{
return [TyphoonDefinition withClass:[ApiService class] configuration:^(TyphoonDefinition* definition) {}];
}
Using runtime arguments
For example, I have this as a definition. I need to pass the runtime
Config object as a parameter to the constructor.
- (id<ApiService>)apiService {
return [TyphoonDefinition withClass:[ApiService class] configuration:^(TyphoonDefinition* definition) {}]; }
Try something like this:
- (id<ApiService>)apiServiceWithConfig:(Config *)config {
return [TyphoonDefinition withClass:[ApiService class] configuration:^(TyphoonDefinition* definition) {
// inject into property:
[definition injectProperty:#selector(config) with:config];
// inject into constructor:
[definition useInitializer:#selector(initWithConfig:) parameters:^(TyphoonMethod *initializer) {
[initializer injectParameterWith:config];
}];
}];
}
Using factory definition
Take a look into next two definitions:
- (Config *)currentConfig {
return [TyphoonDefinition withFactory:[self configManager] selector:#selector(currentConfig)];
}
- (ConfigManager *)configManager {
return [TyphoonDefinition withClass:[ConfigManager class] configuration:^(TyphoonDefinition *definition){
definition.scope = TyphoonScopeSingleton;
}];
}
Imagine you have a ConfigManager which downloads remote config and stores it as 'currentConfig' property, 'configManager' definition describes that object.
Then check the 'currentConfig' definition. This definition just returns result of calling 'currentConfig'method on ConfigManager instance.
Then you can inject config as:
- (id<ApiService>)apiService {
return [TyphoonDefinition withClass:[ApiService class] configuration:^(TyphoonDefinition* definition) {
[definition injectProperty:#selector(config) with:[self currentConfig]];
}];
}
But make sure that currentConfig loaded (not nil) during 'apiService' creation. (maybe better inject ConfigManager instead - then if currentConfig nil, it would be filled later)
A few points:
Run-time arguments are super-cool feature and really help to get the full power of Typhoon. We strongly recommend to learn about them (ask questions here, if you like). They're not a good fit for what you're trying to do though.
It is possible to register a new definition in the container at runtime using:
.
- (void)registerDefinition:(TyphoonDefinition *)definition;
. . you probably don't want to do this in your case either.
what you are interested in is:
TyphoonComponentFactoryPostProcessor and TyphoonComponentPostProcessor:
Typhoon has two kinds of interfaces that can be attached, one is TyphoonComponentFactoryPostProcessor and the other is TyphoonComponentPostProcessor. They are used internally, but you can also write your own and do all kinds of cool things with them.
TyphoonComponentFactoryPostProcessor: Modifies the definitions (recipes) for a component before it gets built.
TyphoonComponentPostProcessor: Modifies the instances after they are built.
TyphoonConfig:
There is an existing TyphoonComponentFactoryPostProcessor that you can use for the task you described. Its called TyphoonConfigPostProcessor and is described in the user guide here.
All post processors can be attached either at built-time (in the assembly), or at runtime, as follows:
TyphoonConfigPostProcessor* configurer = [[TyphoonConfigPostProcessor alloc] init];
[configurer useResourceWithName:#"Configuration.plist"]];
[factory attachPostProcessor:configurer];
Note that, since TyphoonComponentFactoryPostProcessor modifies definitions, if you have components of singleton scope that are already built, they would not be affected. You'd have to either create lazy singletons, or call [factory unload].
How do I get a reference to the TyphoonComponentFactory after startup?
Whichever thing in your app is doing the configuration step will need to be made 'Typhoon Aware'. You can do this by using the following:
- (ConfigController *)configController
{
return [ConfigController withClass:[INFGiftDeliveryAddressController class]
configuration:^(TyphoonDefinition *definition)
{
[definition injectProperty:#selector(factory) with:self];
}];
. . when inject the assembly you can declare a property of type TyphoonComponentFactory or any of your assembly sub-classes. It will work either way. The documentation for this feature is here.
In mobile and desktop applications, your components will often need to be made 'Typhoon aware' so they we can proceed from one object graph (eg a view controller) to another (and this is where the run-time arguments feature can be useful). Note that you're coding to your own domain-specific assembly interface, so Typhoon is "non-invasive". For the most part your apps don't refer to any Typhoon APIs directly.
We've covered quite a lot here, so if you have any further questions or need clarifications don't hesitate to ask.

Google Analytics IOS v2(beta) crash under ARC

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:]

Conditional breakpoint using strcmp() in GDB on Mac OS X conflicts with Objective-C runtime

I'm trying to debug a program that I do not have the source for on Mac OS X. I would like to know what arguments it is calling gettattrlist() with, and inspect the return value, for two different volumes (in order to compare and see why it will let you use one volume and not the other).
I first tried dtruss; but that's useless for getattrlist(); it shows only the pointers that are being passed into getattrlist() (and doesn't even know how many arguments getattrlist() takes).
635/0x1dc5: getattrlist("/Volumes/MyVolume\0", 0x113FA6380, 0x113FA5FD0) = 0 0
635/0x1dc5: getattrlist("/Volumes/MyVolume\0", 0x113FA4F00, 0x113FA4B30) = 0 0
635/0x1dc5: getattrlist("/Volumes/MyVolume\0", 0x113FA5870, 0x113FA54C0) = 0 0
635/0x19c6: getattrlist("/Volumes/MyVolume\0", 0x7FFF5FBF9140, 0x7FFF5FBF8D70) = 0 0
635/0x19c6: getattrlist("/Volumes/MyVolume\0", 0x7FFF5FBFA8A0, 0x7FFF5FBFA4F0) = 0 0
So I tried GDB. I can set an unconditional breakpoint on getattrlist(), and take a look at its first argument, but it's called way too often for that to be useful.
(gdb) break getattrlist
Breakpoint 1 at 0x7fff8e90b6ac
(gdb) cont
Continuing.
Breakpoint 1, 0x00007fff8e90b6ac in getattrlist ()
(gdb) p (char *)$rdi
$1 = 0x7fff5fbfd67e "/some/random/path"
So, I probably need a conditional breakpoint, that will break only when the first argument matches the path I'm interested in. That shouldn't be too hard, right?
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) break getattrlist if ((int)strcmp((char *)$rdi, "/Volumes/My Volume")) == 0
Breakpoint 2 at 0x7fff8e90b6ac
(gdb) cont
Continuing.
Canceling call as the malloc lock is held so it isn't safe to call the runtime.
Issue the command:
set objc-non-blocking-mode off
to override this check if you are sure your call doesn't use the malloc libraries or the ObjC runtime.
Error in testing breakpoint condition:
Canceling call as the malloc lock is held so it isn't safe to call the runtime.
Issue the command:
set objc-non-blocking-mode off
to override this check if you are sure your call doesn't use the malloc libraries or the ObjC runtime.
Breakpoint 2, 0x00007fff8e90b6ac in getattrlist ()
(gdb) p (char *)$rdi
$12 = 0x7fff5fbfd67e "/some/other/random/path"
What's this? GDB has ignored my condition because it suspects that it might call malloc() or the ObjC runtime? OK, well, strcmp() shouldn't call malloc(); it should just compare the strings byte by byte until it gets to a null character. So lets set that option the message recommends to override the check:
(gdb) set objc-non-blocking-mode off
(gdb) cont
Continuing.
Segmentation fault: 11
No dice. GDB and the application both die.
Any suggestions on how to set a conditional watchpoint on a string from GDB without running into this issue? Or other ways of capturing the arguments and return values (which are stored via an output argument) of getattrlist(), that works better than dtruss()?
Edit
Tried matt's solution, but no luck:
(gdb) set $vol = (char *) malloc((int)strlen("/Volumes/My Volume") + 1)
(gdb) call (int)strcpy($vol, "/Volumes/My Volume")
$1 = 236411760
(gdb) break getattrlist if ((int)strcmp((char *)$rdi, $vol)) == 0
Breakpoint 1 at 0x7fff8e90b6ac
(gdb) cont
Continuing.
Unsafe to run code: malloc zone lock is held for some zone..
Error in testing breakpoint condition:
Canceling call as the malloc lock is held so it isn't safe to call the runtime.
Issue the command:
set objc-non-blocking-mode off
to override this check if you are sure your call doesn't use the malloc libraries or the ObjC runtime.
Breakpoint 1, 0x00007fff8e90b6ac in getattrlist ()
(gdb) p (char *)$rdi
$4 = 0x11a715838 "/some/other/random/path"
I decided to try memcmp() instead of strcmp(); no luck there either:
(gdb) break getattrlist if ((int)memcmp((char *)$rdi, $vol, 18)) == 0
Breakpoint 1 at 0x7fff8e90b6ac
(gdb) cont
Continuing.
Unsafe to run code: malloc zone lock is held for some zone..
Error in testing breakpoint condition:
Canceling call as the malloc lock is held so it isn't safe to call the runtime.
Issue the command:
set objc-non-blocking-mode off
to override this check if you are sure your call doesn't use the malloc libraries or the ObjC runtime.
Breakpoint 1, 0x00007fff8e90b6ac in getattrlist ()
(gdb)
At this point, I figured "OK, now there really shouldn't be anything using malloc()", so I decided to try set objc-non-blocking-mode off again. Still no luck:
(gdb) set objc-non-blocking-mode off
(gdb) cont
Continuing.
Reading symbols for shared libraries ... done
Reading symbols for shared libraries . done
Reading symbols for shared libraries ....... done
[Switching to process 5456 thread 0x2971b]
[Switching to process 5456 thread 0x29e2f]
warning: Unable to restore previously selected frame.
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
[Switching to process 5456 thread 0x29e2f]
0x0000000000000000 in ?? ()
Error in testing breakpoint condition:
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on"
Evaluation of the expression containing the function (memcmp) will be abandoned.
Breakpoint 1, 0x0000000000000000 in ?? ()
Error in testing breakpoint condition:
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on"
Evaluation of the expression containing the function (memcmp) will be abandoned.
Breakpoint 1, 0x0000000000000000 in ?? ()
Hmm. What state am I in?
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x000000011e6ec070 in ?? ()
Ick. That doesn't look good. What if I continue here?
(gdb) cont
Continuing.
[Switching to process 5456 thread 0x2971b]
(gdb) bt
#0 0x00007fff8e90b6ac in getattrlist ()
#1 0x00007fff897c9c4b in GetPathVolFSAttributes ()
#2 0x00007fff897c9459 in PathGetObjectInfo ()
#3 0x00007fff897c9279 in FSPathMakeRefInternal ()
#4 0x00007fff8767b3ee in FSNodePrepareFSRef ()
... snip ...
(gdb) p (char *)$rdi
$2 = 0x10db1c2b0 "/System/Library/CoreServices/CoreTypes.bundle"
Nope. Still not actually breaking on the correct call to getattrlist(); and everything has died in the meantime due to the null pointer dereference.
I believe that something like the following should work.
(gdb) start
...
(gdb) set $x = malloc(strlen("foobar") + 1)
(gdb) call strcpy($x, "foobar")
(gdb) break a_leg if strcmp(foo, $x) == 0
In recent versions of GDB:
(gdb) start
(gdb) break a_leg if $_streq(foo, "foobar")
I'm not sure in what version this was introduced, but it's at least present in 7.7.1.

Objective-C: How to pass a tree of objects to a remote distributed object?

I have a class called Node which contains a set of parameters and an NSMutableArray called subNodes. One process creates one Node object as a root of the tree and uses the subNodes arrays to create a large tree of Nodes. This entire tree should be passed to another process, so I set up an NSConnection:
Node *tree;
// ...create Node-Tree...
NSConnection *otherProcess = [NSConnection connectionWithRegisteredName:#"MyApp"
host:nil];
MyObj *remoteObj = (MyObj*) [[otherProcess rootProxy] retain];
[remoteObj setNodeTree:tree];
The communication itself works, the remote method 'setNodeTree', which expects the root-Node will be called. However, the transfer of the tree doesn't work. I had to implement a copyWithZone method for the Node class:
-(id)copyWithZone:(NSZone*)zone
{
Node *nodeCopy = [[[self class] allocWithZone:zone] init];
[nodeCopy setSize:[self size]];
[nodeCopy setSubnodes:[[self subnodes] copyWithZone:zone]];
return nodeCopy;
}
But the client terminates with the following exception:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: '[NOTE: this exception originated in the server.]
Cannot create BOOL from object <Node: 0x10018f640> of class NSDistantObject'
*** Call stack at first throw:
(
0 CoreFoundation 0x00007fff81f687b4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff823a80f3 objc_exception_throw + 45
2 Foundation 0x00007fff8831e0c3 -[NSConnection sendInvocation:internal:] + 4304
3 CoreFoundation 0x00007fff81f3a98c ___forwarding___ + 860
4 CoreFoundation 0x00007fff81f36a68 _CF_forwarding_prep_0 + 232
5 MyProgram 0x00000001000015d5 main + 260
6 MyProgram 0x0000000100000fa8 start + 52
7 ??? 0x0000000000000002 0x0 + 2
)
terminate called after throwing an instance of 'NSException'
Any ideas what went wrong here? Apparently a BOOL variable is expected somewhere, but the Node doesn't contain any and there is no method used which expects or returns a BOOL.
Two alternatives are possible:
serialization and deserialization of whole tree,
shared memory between processes.
For performance and code readability, my preference goes to shared memory. A reference start is shmget(2) manual page.