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

Dynamic class name in %init(<class>=<expr>) and %hook <class> to assume type #43

Open
Nosskirneh opened this issue Jul 23, 2019 · 6 comments

Comments

@Nosskirneh
Copy link

TLDR

Specifying the class like %init([<class>=<expr>, …]);, results in the hooked object (self) being left without type to the compiler. I understand that not assuming any class is the most sane thing to do, but I was wondering if it would be possible to automatically set the object to a known type or to one that conforms to a protocol in order to avoid casting.

Background

I have a few hooks for iOS 11 and 12 (pre 12.2) that hooks the class MediaControlsPanelViewController in a few of my tweaks. In iOS 12.2 however, this class was renamed to MRPlatterViewController. All properties and methods seems to be the same. Thus, I would like to reuse the code within the hook, like:

%ctor {
    ...

    Class c;
    if (running iOS 12.2)
        c = %c(MRPlatterViewController);
    else
        c = %c(MediaControlsPanelViewController);
    %init(MediaControlsPanelViewController = c);
}

This works fine, but inside the actual hooked code, the compiler does no longer know which type self has.

I realize that it's possible to do something like this:

@protocol PanelViewController<NSObject>
@property (nonatomic, retain) MediaControlsParentContainerView *parentContainerView;
...
@end

@interface MediaControlsPanelViewController : UIViewController <PanelViewController>
@end

@interface MRPlatterViewController : UIViewController <PanelViewController>
@end

and then in the code cast it to an object that conforms to that protocol:

%hook MediaControlsPanelViewController

- (void)viewDidLoad {
    %orig;

    UIViewController<PanelViewController> *controller = (UIViewController<PanelViewController> *)self;

    controller.parentContainerView...
}
...

instead of using self. I was wondering if it would be possible to automatically set the object to a known type or to one that conforms to a protocol in order to avoid doing this casting. Ideally this would be done in the %ctor once instead of once in every hooked method.

@Muirey03
Copy link

Elaborating on this:
For example if f we take the code:

%hook ClassToHook
-(void)hookedMethod {}
%end

%ctor {
	%init(ClassToHook = objc_getClass("aClass"));
}

Logos will currently generate the function definition:

static void _logos_method$_ungrouped$ClassToHook$hookedMethod(_LOGOS_SELF_TYPE_NORMAL id _LOGOS_SELF_CONST __unused self, SEL __unused _cmd) {}

and declarations:

@class ClassToHook;
static void (*_logos_orig$_ungrouped$ClassToHook$hookedMethod)(_LOGOS_SELF_TYPE_NORMAL id _LOGOS_SELF_CONST, SEL); static void _logos_method$_ungrouped$ClassToHook$hookedMethod(_LOGOS_SELF_TYPE_NORMAL id _LOGOS_SELF_CONST, SEL);

(notice how it still generates the @class, but is unused). Logos should instead generate the definition:

static void _logos_method$_ungrouped$ClassToHook$hookedMethod(_LOGOS_SELF_TYPE_NORMAL ClassToHook* _LOGOS_SELF_CONST __unused self, SEL __unused _cmd) {}

and declarations:

@class ClassToHook;
static void (*_logos_orig$_ungrouped$ClassToHook$hookedMethod)(_LOGOS_SELF_TYPE_NORMAL ClassToHook* _LOGOS_SELF_CONST, SEL); static void _logos_method$_ungrouped$ClassToHook$hookedMethod(_LOGOS_SELF_TYPE_NORMAL ClassToHook* _LOGOS_SELF_CONST, SEL);

As would be generated if the class was hooked normally, without being passed into %init.

@NSExceptional
Copy link
Contributor

@Nosskirneh How exactly is logos supposed to know which class it's supposed to be at compile-time?

@Muirey03
Copy link

Muirey03 commented Apr 30, 2020

@NSExceptional my examples show the output I believe that logos should generate to resolve this issue, and that this is indeed a bug by the unused @class forward declaration. Normally when hooking with %hook UIView for example, logos will declare the self variable as _LOGOS_SELF_TYPE_NORMAL UIView* _LOGOS_SELF_CONST. However when hooking labels defined in %init, logos declares self as _LOGOS_SELF_TYPE_NORMAL id _LOGOS_SELF_CONST, instead of declaring it as a ClassToHook*, leaving the @class ClassToHook; unused.

@NSExceptional
Copy link
Contributor

Ah, my bad. I understand now.

@NSExceptional
Copy link
Contributor

This is really biting me in the ass right now. @uroboro do you know where exactly I might go to resolve this in Logos? I've been digging around for an hour and can't find it

@NSExceptional
Copy link
Contributor

I think I've found it, in bin/lib/Logos/Class.pm:

sub type {
	my $self = shift;
	if(@_) { $self->{TYPE} = shift; }
	# return $self->{TYPE} if $self->{TYPE};
	return $self->{NAME}." *";
}

Commenting out the 2nd-to-last line as above does the trick. @uroboro If this is the only thing type is used for (and it as AFAICT) then can you just commit this change?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants