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

Selector forwarding is broken on Windows (mingw and msvc) #312

Closed
qmfrederik opened this issue Nov 16, 2024 · 4 comments · Fixed by #313
Closed

Selector forwarding is broken on Windows (mingw and msvc) #312

qmfrederik opened this issue Nov 16, 2024 · 4 comments · Fixed by #313

Comments

@qmfrederik
Copy link
Collaborator

Selector forwarding from one object to another seems to be broken when using libobjc2 on Windows (see also: gnustep/plugins-themes-WinUXTheme#7 (comment)).

I've opened a PR in libs-base which shows the problem: gnustep/libs-base#466

@qmfrederik
Copy link
Collaborator Author

@davidchisnall Any idea what's going on here? The simplest program to reproduce the issue is like this:

#import <Foundation/Foundation.h>
#import "Testing.h"
#import "ObjectTesting.h"

@interface GSFakeNSString : NSObject
{
  NSString* _originalItem;
}

- (id) initWithItem: (NSString*)item;
- (NSString*) originalItem;
- (id) target;
- (SEL)action;
- (void) action: (id)sender;
@end

@implementation GSFakeNSString
- (id) initWithItem: (NSString*)item
{
  self = [super init];
  if (self)
  {
    _originalItem = item;
  }
  return self;
}

- (NSString*) originalItem
{
  return _originalItem;
}

- (id)target
{
  return self;
}

- (SEL)action
{
  return @selector(action:);
}

- (id)forwardingTargetForSelector:(SEL)selector
{
  if ([_originalItem respondsToSelector:selector])
    return _originalItem;
  return nil;
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
  SEL selector = [invocation selector];

  // Forward any invocation to the original item if it supports it...
  if ([_originalItem respondsToSelector:selector])
    [invocation invokeWithTarget:_originalItem];
}

-(NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
	NSMethodSignature *signature = [[_originalItem class] instanceMethodSignatureForSelector:selector];
	if(signature == nil)
	{
		signature = [NSMethodSignature signatureWithObjCTypes:"@^v^c"];
	}
	return(signature);
}

- (void)doesNotRecognizeSelector:(SEL)selector
{
  NSLog(@"%s:selector not recognized: %@", __PRETTY_FUNCTION__, NSStringFromSelector(selector));
}
@end

int main(int argc,char **argv)
{
  START_SET("GSFFIInvocation")

  NSString *string = @"Hello, World!";

  GSFakeNSString *fakeString = [[GSFakeNSString alloc] initWithItem:string];

  NSString *upperCaseString = [string uppercaseString];
  NSString *fakeUpperCaseString = [fakeString uppercaseString];

  PASS_EQUAL(upperCaseString, fakeUpperCaseString, "uppercaseString selector is forwarded from the fake string to the actual NSString object");
  NSLog(@"Upper case string: %@, fake upper case string: %@", upperCaseString, fakeUpperCaseString);

  END_SET("GSFFIInvocation")
  return 0;
}

On Linux this passes, on Windows this gives:

EXCEPTION: NSRangeException in rangeOfCharacterFromSet:options:range:, range { 0, 32759 } extends beyond size (13) (null)

From what I can see, when the NSString uppercaseString method is invoked, the value of self is incorrect (and interestingly, *self seems to hold the correct value).

@davidchisnall
Copy link
Member

I thought we had a test for the hook that forwardingTargetForSelector uses. It is the one that is allowed to rewrite the receiver and so the passes a pointer to the receiver to the forwarding hook, which can the rewrite it and message send then uses the result. It sounds like something is going wrong there and we’re somehow passing the pointer to the pointer instead.

@qmfrederik
Copy link
Collaborator Author

Yes, there's Test/Forward.m. But it seems the implementation of those hooks in libs-base is more complex than what's in that test.

@qmfrederik
Copy link
Collaborator Author

qmfrederik commented Nov 17, 2024

@davidchisnall As far as I can tell:

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

Successfully merging a pull request may close this issue.

2 participants