Skip to content
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

%subclass with protocols crashes in the constructor #9

Open
JonasGessner opened this issue Feb 12, 2015 · 3 comments · May be fixed by #94
Open

%subclass with protocols crashes in the constructor #9

JonasGessner opened this issue Feb 12, 2015 · 3 comments · May be fixed by #94
Assignees
Labels
bug Something isn't working

Comments

@JonasGessner
Copy link

In CCLoader I have %subclass that implements two protocols, a custom one and one defined in SpringBoardUIServices. That subclass (sometimes) crashes in the constructor function. I'm using the latest theos. Here's the crash log, and the %subclass is also in that project: JonasGessner/CCLoader#12

@JonasGessner
Copy link
Author

I got the precompiled .mm version of the .xm source file, and in the constructor the two protocols are added to the class like this:

class_addProtocol(_logos_class$_ungrouped$CCSectionViewController, objc_getProtocol("CCSectionDelegate"));
class_addProtocol(_logos_class$_ungrouped$CCSectionViewController, objc_getProtocol("_SBUIWidgetHost"));

I took a look at the output of the two objc_getProtocol calls:

Protocol *widgetHost = objc_getProtocol("_SBUIWidgetHost");
Protocol *sectionDelegate = objc_getProtocol("CCSectionDelegate");

NSLog(@"Protocols: %@ %@", widgetHost, sectionDelegate);

NSLog(@"AAAAAAAAAA 1");
class_addProtocol(_logos_class$_ungrouped$CCSectionViewController, sectionDelegate);
NSLog(@"AAAAAAAAAA 2");
class_addProtocol(_logos_class$_ungrouped$CCSectionViewController, widgetHost);
NSLog(@"AAAAAAAAAA 3");

Output:

Protocols: <Protocol: 0x1742bf860> (null)
AAAAAAAAAA 1
AAAAAAAAAA 2
->SpringBoard crashes

The CCSectionDelegate protocol is nil, because it is not implemented by a class (only the dynamic subclass) and because it is never referenced by a @protocol() call (See: https://developer.apple.com/legacy/library/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html -> Protocol Objects).

So changing the code to this:

Protocol *widgetHost = @protocol(_SBUIWidgetHost);
Protocol *sectionDelegate = @protocol(CCSectionDelegate);

NSLog(@"Protocols: %@ %@", widgetHost, sectionDelegate);

NSLog(@"AAAAAAAAAA 1");
class_addProtocol(_logos_class$_ungrouped$CCSectionViewController, sectionDelegate);
NSLog(@"AAAAAAAAAA 2");
class_addProtocol(_logos_class$_ungrouped$CCSectionViewController, widgetHost);
NSLog(@"AAAAAAAAAA 3");

Outputs this:

Protocols: <Protocol: 0x1702a3de0> <Protocol: 0x1702b5600>
AAAAAAAAAA 1
AAAAAAAAAA 2
AAAAAAAAAA 3
->Everything is fine

So to get rid of this issue, the protocols have to be referred to with @protocol() rather than objc_getProtocol() to make sure that the compiler creates a protocol object for custom protocols.

Changes that have to be made are:
These lines: https://github.com/DHowett/theos/blob/91f8ed9f1adfb8d01f1b73c1bec5600e245a26b8/bin/lib/Logos/Generator/MobileSubstrate/Subclass.pm#L26 and https://github.com/DHowett/theos/blob/91f8ed9f1adfb8d01f1b73c1bec5600e245a26b8/bin/lib/Logos/Generator/internal/Subclass.pm#L26 have to be changed to:

$return .= "class_addProtocol(".$self->variable($class).", \@protocol($_)); ";

Tested and I can confirm that it works. I'll fork the repo and open a pull request.

JonasGessner referenced this issue in JonasGessner/theos Feb 13, 2015
@rpetrich
Copy link
Contributor

I'm not sure what the right approach is here. Using @protocol will reference the version of the protocol that is declared in the headers, rather than the runtime version which can be different—especially when one considers the case of protocols that vary between iOS versions. On the other hand, it's very surprising for logos not to do the right thing when one has declared a custom protocol. Certainly it shouldn't crash if the protocol could not be found. A more modest fix would be to check the return of objc_getProtocol for NULL before registering.

@rpetrich rpetrich self-assigned this Feb 12, 2016
@JonasGessner
Copy link
Author

Yeah. Checking if the protocol returned from objc_getProtocol is nil and falling back to @protocol would probably be the best solution.

@uroboro uroboro transferred this issue from theos/theos Nov 2, 2018
@uroboro uroboro added the bug Something isn't working label Nov 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants