erikdoe/ocmock — pull request #41 by carllindberg (2013-07-31 04:19:36+00:00)
Title: Fix partial mock override implementation when returning structs

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
it may be necessary to override with objc_msgForward_stret instead since that is how the compiler is going to set
up the frame for the call. When using the wrong one, the compiler will set up the frame differently, and
objc_msgForward will then assume its arguments are in places they are not, leading to crashes very quickly.

In particular, the frame in the objc_msgSend_stret situations typically has an extra argument on the stack
(the memory address for the returned structure memory), and the normal objc_msgFoward implementation
will take the value at that frame location and assume it is "self", and try to obtain the class for that to
start the forwarding process (create NSInvocation etc.). If that happens to be nil, you will see some error
logs like

*** 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.
Unfortunately, determining whether it is needed or not is very architecture dependent, and the rules
can get mind-numbingly complex particularly for the 64-bit architectures. I found a horrid backhanded way
where NSMethodSignature can sort of tell us, and went with that. You probably want to find a better way
if at all possible.

With this fix in, the test case mentioned in the stackoverflow article passes (test case added here).