Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Fix partial mock override implementation when returning structs #41
Fix partial mock override implementation when returning structs. The current implementation uses a trick to get a handle to the objc_msgForward function (or whatever the runtime is using to forward normal messages) and installs that as the "implementation" for any stubbed methods; however depending on the struct and the architecture
In particular, the frame in the objc_msgSend_stret situations typically has an extra argument on the stack
*** NSForwarding: warning: object 0x679e0 of class 'nil' does not implement methodSignatureForSelector: -- trouble ahead
before crashing. If it is some other non-zero value, it will probably crash earlier.
Problem mentioned at http://stackoverflow.com/questions/16559191/returning-cgrect-from-mocked-method-crashes .
The solution is to determine which forwarder function needs to be used (I used class_getMethodImplementation_stret() to get the right one), and use that in the override instead.
With this fix in, the test case mentioned in the stackoverflow article passes (test case added here).
referenced this pull request
Jul 31, 2013
Thanks! This is super helpful. I had briefly stepped through the assembler code but couldn't understand why things were the way they were. It didn't occur to me that the wrong forward function was being used... Out of curiosity, where is the ABI description that we'd have to follow to support x86_64 properly?
By the way, I checked the GNUstep source code but that wasn't helpful. I'll also check whether NSMethodSignature has a non-public method that might help us. I'd be happy to call that (with a test guarding it). After all I can't see how anyone would need OCMock code in the App Store.
Ok, so, there is a method named _frameDescriptor, and its return type is
For documentation links, there are:
A good overview of the situation:
Apple's low-level ABI documentation (has details for ppc, i386, and ppc64, with an external reference for x86-64):
The document for x86_64 (archive.org link since I can't get to main site at the moment):
It's possible that libffi might have the code to determine this stuff, but I don't know enough about it.
Yeah, I looked at class-dump to see if I could find any useful private methods, but nothing was evident. Class-dump does show that method, and the structure it returns (and also expands NSMethodFrameArgInfo, which is several more fields plus about 10-15 bitfield flags, and there are two of those in whatever is returned from _frameDescriptor).
Reading the GNUStep NSMethodSignature.m, there may be an extra '+' character in the type string for the return type to indicate a needed struct return, not sure. But that may be a GNU runtime thing only. It would be very nice to find better API to figure it out, to be sure. The current hack is technically not private API, but... it might be fragile. Not sure how often Apple changes the output of that method.
Does look like libffi has the logic...
Also, in theory, all the above would hold true for unions as well, but it appears that NSMethodSignature throws an exception if you try to initialize with a type string that uses them. Thus, nothing that uses NSInvocation would appear to be able to support union returns. It works if you just implement forwardingTargetForSelector:, which apparently avoids NSMethodSignature/NSInvocation creation, but once you need NSInvocation it's a problem.