Bug 59193 - cast from Java.Lang.Integer to uint fails when the "integer" constains a negative number
Summary: cast from Java.Lang.Integer to uint fails when the "integer" constains a nega...
Status: RESOLVED ANSWERED
Alias: None
Product: Android
Classification: Xamarin
Component: Mono runtime / AOT Compiler (show other bugs)
Version: 7.4 (15.3)
Hardware: PC Windows
: --- normal
Target Milestone: ---
Assignee: Marek Habersack
URL:
Depends on:
Blocks:
 
Reported: 2017-09-02 14:38 UTC by softlion
Modified: 2017-10-18 15:48 UTC (History)
2 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description softlion 2017-09-02 14:38:38 UTC
The cast from Java.Lang.Integer to uint fails when the "integer" constains a negative number.

Repro:
create a variable of type Java.Lang.Integer containing -323575608
try to cast the variable to an uint.

var javaInt = new Java.Lang.Integer(-323575608);
var cast = (uint)javaInt;

=> exception.

You can still cast javaInt to an int, then an uint, it will work fine.
var castOk = (uint)(int)javaInt;
Comment 1 Jon Douglas [MSFT] 2017-09-09 00:50:17 UTC
I can CONFIRM this issue on 7.4. Here is a full stack trace on this issue:

09-08 18:31:39.615 I/MonoDroid( 3398): System.OverflowException: Value was either too large or too small for a character.
09-08 18:31:39.615 I/MonoDroid( 3398):   at System.Convert.ToChar (System.Int32 value) [0x00016] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 18:31:39.615 I/MonoDroid( 3398):   at Java.Lang.Integer.System.IConvertible.ToChar (System.IFormatProvider provider) [0x00006] in <d278c06ad5684d6882c743a94a93ebc2>:0 
09-08 18:31:39.615 I/MonoDroid( 3398):   at System.Convert.ToChar (System.Object value) [0x00003] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 18:31:39.615 I/MonoDroid( 3398):   at Java.Lang.Object.op_Explicit (Java.Lang.Object value) [0x00000] in <d278c06ad5684d6882c743a94a93ebc2>:0 
09-08 18:31:39.615 I/MonoDroid( 3398):   at App27.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState) [0x00020] in c:\users\dougl\documents\visual studio 2017\Projects\App27\App27\MainActivity.cs:19 
09-08 18:31:39.615 I/MonoDroid( 3398):   at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState) [0x0000f] in <d278c06ad5684d6882c743a94a93ebc2>:0 
09-08 18:31:39.615 I/MonoDroid( 3398):   at (wrapper dynamic-method) System.Object:015c9407-0e79-4525-8a27-091e2c964e8d (intptr,intptr,intptr)

The MIN_VALUE for Java.Lang.Integer is:

-2147483648

-323575608 does not quite surpass that. The following works fine in Android Studio using Java:

Integer integer = new Integer(-323575608);

Using Int32 and UInt32 seems to work just fine and is probably recommended.

This however seems like a bug. Thus I am CONFIRMING this issue.
Comment 2 softlion 2017-10-18 11:40:22 UTC
> Using Int32 and UInt32 seems to work just fine and is probably recommended.

I get the problem while calling into the bluetooth stack: some methods there returns java Integer instead of C# types.
Comment 3 Marek Habersack 2017-10-18 15:48:36 UTC
PR open: https://github.com/xamarin/xamarin-android/pull/945

For convenience, pasting explanation from the PR below:

Java does not include types to represent unsigned integers. This poses a problem
when either porting code from Java to managed languages or when attempting to
cast integer values between the Java and the managed land.

The issue described in the above bug could be fixed by adding appropriate
implicit and explicit operators to Java.Lang.Object in Xamarin.Android but that
would allow for behavior which may have adverse effects without any external
signs immediately visible to the developer.

Consider a situation when a minimum signed 32-bit integer value returned by Java
code is cast to the managed uint type - we end up with the same value but with
different sign and no indication given that such a thing happened. We could
up-cast the value to long but that changes the type of the result and is not
advisable, especially with implicit conversions. Also, even if the value was
up-cast to a type with a larger value range this would have to stop with the
64-bit integers since they can't be up-cast to any other primitive integer type.

Any casts between signed and unsigned integer types should be a conscious and
explicit action, thus the double cast (ulong)(long)value is considered the
correct behavior.

For those reasons we decided that the best action to to take is to actively
prevent direct casts from/to a managed unsigned integer type to/from a signed
Java integer type. This is implemented by way of adding a number of explicit and
implicit conversion operators to XA's Java.Lang.Object implementation that are
marked "obsolete" and being erroneous. This is done this way so that the code
attempting to perform such conversions won't build because the compiler, seeing
the attribute, will signal an error and abort the build.

Note You need to log in before you can comment on or make changes to this bug.