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

C++ instances as Objective-C++ method parameters - crashes in LIBOBJC2.DLL #1140

Closed
ghost opened this issue Oct 13, 2016 · 2 comments
Closed

Comments

@ghost
Copy link

ghost commented Oct 13, 2016

Passing instances of non-trivial C++ objects as Objective-C++ method parameters causes unexpected behavior, even if appropriate copy constructors and assignment operators have been provided, e.g. in case of smart pointer implementations - crashes.

CppParam.h (MSCVP)

#pragma once

class CppParam
{
public:
    CppParam();
};

CppParam.cpp (MSCVP)

#include "CppParam.h"

CppParam::CppParam()
{
}

partyCrasher.mm (Clang)

#include "CppParam.h"

// a lightweight smart pointer library, http://yasper.sourceforge.net
#include "yasper.h"

@implementation MainViewController

- (void)doMe1:(yasper::ptr<CppParam>)param1
{
    // NOOP
}

- (void)doMe2:(yasper::ptr<CppParam>)param1 alongWith:(NSObject*)param2
{
    // NOOP
}

- (void)doMe3:(NSObject*)param1 alongWith:(yasper::ptr<CppParam>)param2
{
    // NOOP
}

- (void)partyCrasher
{
    // a non-trivial C++ smart pointer object (with additional counter class members, etc.)
    yasper::ptr<CppParam> pParam(new CppParam());

    // single-param: ok
    [self doMe1:pParam];

    // multi-param: crash!
    [self doMe2:pParam alongWith:[[NSObject alloc] init]];

    // multi-param, reversed: crash!
    [self doMe3:[[NSObject alloc] init] alongWith:pParam];
}

@end

The relevant error message:

Exception thrown at 0x0FB17FEC (LIBOBJC2.DLL) in PartyCrasher.exe: 0xC0000005: Access violation reading location 0x00000000.

Notes:

1.) The problem does not occur under Apple Xcode/iOS.

2.) The problem does not occur for single-parameter Objective-C++ method calls (Clang requires, thus uses, a copy constructor), hence it is probably not a problem with yasper::ptr<> itself, the sample smart pointer implementation. Some kind of Objective-C++ variadic memcpy() -ing stuff around instead of using a copy constructor?

As of: WinObjC version 0.2.160927 (September 27, 2016).

@DHowett-MSFT
Copy link

DHowett-MSFT commented Oct 13, 2016

Thanks for the report!

This looks like a code generation issue.

In doMe2 and doMe3, the function begins with the ARC prologue that should take a strong reference on the NSObject* parameter.

That usually looks something like this:

00B579A0  push        dword ptr [ebp+10h]  ; parameter area is above ebp
00B579A3  lea         eax,[param]  
00B579A6  push        eax  
00B579A7  call        _objc_storeStrong (0B646B6h)

which corresponds to the call objc_storeStrong(&param_local_temp, param_passed_in_as_argument).

However, what's getting emitted in 2 and 3 above looks more like this:

00B578D0  push        dword ptr [ebp-10h]  ; local temp area is below ebp
00B578D3  push        dword ptr [ebp-10h]  
00B578D6  call        _objc_storeStrong (0B646B6h)  

This corresponds to objc_storeStrong(&param_local_temp, &param_local_temp).

It looks like marking the NSObject parameter __unsafe_unretained fixes the issue (at, of course, a cost), as further references to the parameter don't codegen improperly.

@DHowett-MSFT
Copy link

This should be fixed with #2869.

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

No branches or pull requests

2 participants