0

I want to test the implementation of NSUncaughtExceptionHandler. What I've tried:

int[] array = new int[3];
array[4] = 1;

object o = null;
o.GetHashCode();

This is my implementation in AppDelegate.cs:

public delegate void NSUncaughtExceptionHandler(IntPtr handle);
[DllImport("/System/Library/Frameworks/Foundation.framework/Foundation")]
private static extern void NSSetUncaughtExceptionHandler(IntPtr handle);

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App());

    NSSetUncaughtExceptionHandler(Marshal.GetFunctionPointerForDelegate(new NSUncaughtExceptionHandler(MyUncaughtExceptionHandler)));

    return base.FinishedLaunching(app, options);
}

[MonoPInvokeCallback(typeof(NSUncaughtExceptionHandler))]
private static void MyUncaughtExceptionHandler(IntPtr handle)
{
    NSException exception = (NSException)ObjCRuntime.Runtime.GetNSObject(handle);

}

The exception is not caught. How can I raise an exception, which NSUncaughtExceptionHandler can catch?

testing
  • 19,681
  • 50
  • 236
  • 417

1 Answers1

1

How about a real world exception: NSInvalidArgumentException (due to unrecognized selector)

Declare the messaging send signature:

[DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")]
static extern CGSize cgsize_objc_msgSend_IntPtr_float_int_foobar(IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);

Exception Handler:

[MonoPInvokeCallback(typeof(NSUncaughtExceptionHandler))]
private static void MyUncaughtExceptionHandler(IntPtr handle)
{
    NSException exception = (NSException)ObjCRuntime.Runtime.GetNSObject(handle);
    Console.WriteLine(exception);
    Console.WriteLine(exception.CallStackSymbols[0]);
}

Make a valid and invalid call:

    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
    {
        // Override point for customization after application launch.
        // If not required for your application you can safely delete this method
        NSSetUncaughtExceptionHandler(Marshal.GetFunctionPointerForDelegate(new NSUncaughtExceptionHandler(MyUncaughtExceptionHandler)));

NSString target = new NSString("StackOverFlow");
Selector selector = new Selector("sizeWithFont:forWidth:lineBreakMode:");
UIFont font = null;
nfloat width = 1.0f;
UILineBreakMode mode = UILineBreakMode.CharacterWrap;
CGSize size = cgsize_objc_msgSend_IntPtr_float_int_foobar( target.Handle, selector.Handle, font == null ? IntPtr.Zero : font.Handle, width, mode);

// `NSInvalidArgumentException` (due to unrecognized selector)
selector = new Selector("StackOverFlowSelector:");
size = cgsize_objc_msgSend_IntPtr_float_int_foobar(target.Handle, selector.Handle, font == null ? IntPtr.Zero : font.Handle, width, mode);

return true;

}

Output:

-[__NSCFString StackOverFlowSelector:]: unrecognized selector sent to instance 0x7cb0a4e0
0   CoreFoundation                      0x00976494 __exceptionPreprocess + 180

Note:

Remember you are calling back into managed code to catch a unmanaged exception, this really should be done in a ObjC library..

SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • So I shouldn't use `NSUncaughtExceptionHandler` here? Should I instead bind a ObjC library so that I can access the exception in managed code? How should this ObjC library look like? Normally it is only [some code](http://www.learn-cocos2d.com/tag/nssetuncaughtexceptionhandler/) in the *AppDelegate*. – testing May 31 '16 at 09:31
  • @testing It is not that you shouldn't do, it is do not expect that to work 100% of the time as the native exception could have caused a corruption in the call-stack of the Mono VM and itself is now crashing and your managed handled has no chance of working. And of course registering for signals should not be done in managed code, so if you plan on expanding to cover SIGABRT, etc... faults do this from un-managed code. – SushiHangover May 31 '16 at 21:31
  • To sum it up: I can use it that way, but it may not work. But what did you mean with *this really should be done in a ObjC library* then? Yeah, I also thought about a signal handler, but I read that should be very complex and you only should do that if you know what you are doing. I didn't find some Objective-C code, which would do that for me. (More precisely the methods I found are not recommended.) But would I be able to bind the Objective-C code and do some logging in managed code? – testing Jun 01 '16 at 08:37
  • @testing It really depends upon what your goals are. Take a read through the comments in the HockeyApp Crash Reporter header file. It discusses a number of items that I think might help @ https://github.com/bitstadium/HockeySDK-iOS/blob/bfb9101ca8a71bb0f4bd4a9036e61df04fc73b2d/Vendor/CrashReporter.framework/Versions/A/Headers/CrashReporter.h – SushiHangover Jun 01 '16 at 09:01
  • The goal is to implement a custom logger, but not only for iOS. There is a [solution out there](http://stackoverflow.com/questions/14499334/how-to-prevent-ios-crash-reporters-from-crashing-monotouch-apps) where you are be able to register the signal handlers for the logging library and for Xamarin itself. I also found the [blog post](http://landonf.bikemonkey.org/code/objc/Reliable_Crash_Reporting.20110912.html) from the maker of PLCrashReporter, where he describes the issues. But I haven't found a way for including a signal handler in Xamarin, except using a logger library like Hockey. – testing Jun 01 '16 at 09:29