Monobjc / monobjc

Git Repository for the Monobjc Project
http://www.monobjc.net/
17 stars 3 forks source link

UTF-16 conversion sometimes fails #420

Closed aarononeal closed 9 years ago

aarononeal commented 11 years ago

An app I'm working on sometimes crashes with this exception:

Unhandled Exception: System.ArgumentException: invalid utf-16 sequence at -1073749680 (missing surrogate head)

I don't have a consistent repro of this and oddly the app just shuts down without breaking into the debugger when the exception occurs.

Given the recent change to UTF-16, this is something to monitor.

aarononeal commented 11 years ago

I hit this again tonight. The app still crashed without giving me a stacktrace or breaking into the debugger.

I ran a test with the method below to see if I could figure out what's going on. Any idea why this would always give me an empty string?

const uint NSUTF16StringEncoding = 10;
static Id StringToNative(String str)
{
    if (str == null)
        return null;

    Id nativeString;
    IntPtr utf16 = Marshal.StringToHGlobalUni(str);
    if (utf16 == IntPtr.Zero)
        throw new NullReferenceException("Attempt to marshal '\" + str + \"' to native pointer resulted in null value");

    try 
    {
        nativeString = ObjectiveCRuntime.SendMessage<Id>(Class.Get ("NSString"), "stringWithCString:encoding:",
                                                         utf16, NSUTF16StringEncoding);

        if (nativeString == null)
            throw new NullReferenceException("Attempt to convert string '" + str + "' to native resulted in null value");
    } 
    finally 
    {
        Marshal.FreeHGlobal(utf16);
    }

    return nativeString;
}

Also, the existing Monobjc wrapped method StringWithCStringEncoding is not very useful because it expects a managed string as the first parameter. Due to the native string descriptor, the managed string will always be converted to UTF8 before passing the pointer to the Objective-C call. It may be better to define that first param as IntPtr.

lemonmojo commented 9 years ago

@aarononeal @letiemble I just updated to Monobjc 5.1 and noticed a very similar issue. Altough I'm converting the other way around.

When calling NSString.ToString() either explicitly or through conversion between NSString and System.String, in some cases I get garbage appended to the end of the string. Please check the attached screenshots for reference.

If I instead convert the NSString by calling Marshal.PtrToStringAuto(MyNSString.UTF8String) all is fine. I guess this is caused by the new icall_Monobjc_Foundation_NSString_ToString method, but I'm not sure why it would cause such issues. Looks like some kind of encoding problem. I noticed the same in Monobjc 6.0, but I have another issue that prevents me from updating to that.

Here's a simplified version of the code that is causing the issue shown in the screenshots (although I also get this in a lot of other places):

public static string Translate(string text) {
    NSString strNs = FoundationFramework.NSLocalizedStringFromTableInBundle(text, "Localizable", NSBundle.MainBundle, string.Empty);
    return strNs.ToString();
}

If I change the last line to return Marshal.PtrToStringAuto(strNs.UTF8String); I get a well formed string.

monobjcnsstring_01 monobjcnsstring_02 monobjcnsstring_03