New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Class Mocks Not Thread-Safe #328
Comments
I just hit this same issue, with OCMock 3.3 (which the release notes claims makes mocking thread-safe). I believe the root issue here is OCMock's class mocking isa-swizzles the metaclass prior to installing methods. This means that background threads may start interacting with the metaclass while it's in the process of installing methods, which is pretty bad. |
Since I'm not sure if moving the metaclass swizzle to the end is safe (I don't know if any of the intervening code relies on it already being installed), I believe a safe fix is to reorder two lines in diff --git a/Pods/OCMock/Source/OCMock/OCClassMockObject.m b/Pods/OCMock/Source/OCMock/OCClassMockObject.m
index f8a8180..39b5f22 100644
--- a/Pods/OCMock/Source/OCMock/OCClassMockObject.m
+++ b/Pods/OCMock/Source/OCMock/OCClassMockObject.m
@@ -148,8 +148,8 @@ - (void)setupForwarderForClassMethodSelector:(SEL)selector
Class metaClass = object_getClass(mockedClass);
IMP forwarderIMP = [originalMetaClass instanceMethodForwarderForSelector:selector];
- class_replaceMethod(metaClass, selector, forwarderIMP, types);
class_addMethod(metaClass, aliasSelector, originalIMP, types);
+ class_replaceMethod(metaClass, selector, forwarderIMP, types);
} |
@erikdoe I assume you're getting notifications for issue updates anyway, but just in case, I'm mentioning you as this is a nasty issue that has been causing spurious test failures for us for a long time and I'm surprised that this ticket never got a response. |
@erikdoe Can you please take a look at this? It's a real issue with a trivial fix. FWIW, it turns out that uninstalling class mocks isn't thread safe either, which doesn't seem to be a solvable short of simply never destroying the dynamically-created class pairs, but in my experience the uninstall issue crops up a lot less frequently than the install issue did. |
Sorry. I should have responded earlier. My concern is that the failing test provided in the issue tests a scenario that, as far as I can tell, cannot be supported by OCMock. It has always been clear that OCMock is only thread-safe to a certain degree. Repeatedly calling a method while setting up and removing a mock would, as far as I am aware, require most of the operations on the class to be atomic, and I don't see a way how to achieve this. The fix provided by @kballard looks benign, but it doesn't fix the issue reported. In fact, there is no test that I can think of that would fail without the change but pass with it. That said, the change is small and it feels like it brings the two operations into a "more correct" sequence. So I have accepted it now. |
Hi Erik,
I’m debugging thread safety in OCMock 3 and have an example test case that demonstrates some faulty behavior. In short, it looks like invoking a class method from a background thread while a class mock is being restored causes crashes due to unrecognized selectors.
Strangely, this isn’t a problem with OCMock 2. I suspect 1ad7292 may have something to do with it.
I realize this is a contrived example, but it’s flaky enough to prevent me from upgrading my project from v2 to v3.
Thanks,
Alan
The text was updated successfully, but these errors were encountered: