Closed holecekp closed 2 months ago
Hi I'm an AI powered bot that finds similar issues based off the issue title.
Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!
Note: You can give me feedback by thumbs upping or thumbs downing this comment.
This issue was not repro on Visual Studio 17.11.0 Preview 2.1 (8.0.60 & 8.0.40 & 8.0.10) with sample project(Android14).
Besides the stable version of VS 17.10.3, I have installed also the latest VS 17.11.0 Preview 2.1. It crashes on both of them. I have found out that it depends on the emulator, which I am using. Android 14 emulator (Pixel 5 based, x86_64) crashes in the release mode. Moreover, Android 12.1 emulator (Small Desktop, x86_64), and Android 9 emulator (Pixel 5 based, x86_64) crashes as well. However, if I launch the app on Android 11 emulator (pixel 7 emulator, x86) it runs in the release mode without crashing.
I have deleted bin and obj folders, cleaned the solution, and reset the Android emulator to factory settings to rule out the possibility that there could be some remains of any other MAUI or Xamarin.Forms apps that would interfere. It did not help. It still crashed with the same exception.
My suspicion is that the issue depends on the processor architecture (working on x86 but crashing on x86_64). Unfortunately, I have tested only on 4 emulators because it takes a lot of time to build and deploy Release version of the MAUI app.
Unfortunately, I can't reproduce this problem in my side. Maybe this issue needs help from others.
@jonathanpeppers ?
The app doesn't crash for me in Release
mode on a Pixel 7.
From your stacktrace, it crashes on this line, right? https://github.com/dotnet/maui/blob/14a080ebb595f929fc2282fd5a94b31b1f870225/src/Controls/src/Core/RadioButton/RadioButton.cs#L653
Since, it's printing a warning, you aren't supposed to put views in a RadioButton
? I don't actually know.
I'm also confused by the log message, is it supposed to be using $""
or is it using string.Format()
syntax?
I don't think this problem has anything to do with Android.
I think I have more questions than answers, sorry!
I did some more testing. Just to be sure, I have also updated to the latest MAUI 8.0.61 - no change. The problem seems to be related to x86_64 processor architecture. The app runs well on other processor architectures. Besides a x86_64 emulator (crashes), I have tested also on a x86 emulator (works) and on a Samsung physical phone with ARM64 (works).
I have also tried to turn off AOT and trimming to narrow down what could cause the problem:
If I use the standard VS template for new MAUI projects, the app instantly crashes on x86_64 emulator with the error that I have described before, but it runs on x86 emulator and ARM64 phone (the Debug version runs also on x86_64, only Release version have the issue).
I have turned off AOT. This time the app does not crash and the splashscreen appears, but notning else, the app ends up in an infinite loop. The same messages can be seen repeating in logcat. An interesting message is a warning that is repeated once a while:
Unexpected CPU variant for x86: x86_64. Known variants: atom, sandybridge, silvermont, goldmont, goldmont-plus, tremont, kabylake, default
Does it mean that MAUI does not support x86_64 Android devices at all?
Besides that the following error can be seen in logcat repeatidly:
FATAL UNHANDLED EXCEPTION: System.ArgumentException: ArgumentException_BufferNotFromPool Arg_ParamName_Name, array
at System.Buffers.SharedArrayPool`1[[System.Char, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Return(Char[] , Boolean )
at System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()
at Android.Runtime.JavaProxyThrowable.Create(Exception )
...
at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V(_JniMarshal_PP_V callback, IntPtr jnienv, IntPtr klazz)
Because DefaultInterpolatedStringHandler is mentioned, my guess is that there might be a problem with some kinds of string iterpolation.
This behavior is again only on x86_64 emulators. The x86 emulator and Samsung ARM64 physical device works.
This showed me that it is important not only to test both Debug and Release versions but also different ABIs for the Release version. According to the devices catalog in the Google Play Console the most of the users of my Xamarin.Forms app uses ARM processors. Devices with X86_64 ABI comprise only 0,2 % of the install base. The vast majority of them are various chromebooks. The only X86_64 phone in the install base is OnePlus 10 Pro. So migrating from Xamarin.Forms to the current version of MAUI would probably make the app unusable for these users. Even if it is only a minority, it would be better if migrating to MAUI had no negative effect on any of the current users.
In the repro project, I am using XAML from the official MAUI sample for the RadioButtons (https://github.com/dotnet/maui-samples/blob/main/8.0/UserInterface/Views/RadioButtonDemos/RadioButtonDemos/Views/RadioButtonControlTemplatePage.xaml). I have just removed images to simplify it a bit. So it should be correct. Moreover, I am using RadioButtons with a ControlTemplate in the Xamarin.Forms version in the production for a long time without any problems.
Unexpected CPU variant for x86: x86_64. Known variants: atom, sandybridge, silvermont, goldmont, goldmont-plus, tremont, kabylake, default
This message doesn't mean anything, you can ignore it.
MAUI does not support x86_64 Android devices at all?
No, the default emulator is x86_64. It is certainly supported, because no one could do development otherwise?
I have also tried to turn off AOT and trimming
I'm not sure that is the problem here. Maybe don't do this yet?
What I was suggesting, is to try to avoid the LogMessage()
call entirely:
.LogWarning("Warning - {RuntimePlatform} does not support View as the {PropertyName} property of RadioButton; the return value of the ToString() method will be displayed instead.", DeviceInfo.Platform, ContentProperty.PropertyName);
If you changed your RadioButton
to use a ControlTemplate
, do you get a different error now? Can you update the attached sample.
I can also test on an emulator; maybe I will see the crash myself there.
Hello. I did some more testing and I have found out what exactly causes it. You were right that the app does not craash when LogWarning is avoided.
The warning generated by the RadioButton is quite confusing because a View as a RadioButton.Content is supported scenario for Android if a ContronTemplate is used (which it is in the repro project). The line in the code where the app crashes uses the ToString() representation RadioButton.Content only for accessibility. A better way in this case would be a warning message that a RadioButton with a ControlTemplate might not by fully accessible in the current version of MAUI , or it would be even better not to generate this warning at all (especially in the release mode) because there is no reasonable way to avoid it and mention this drawback in the documentation instead.
It is quite demanding to find out where does the error message fired by LogWarning goes to. I have found out that it is sent to LoggerProviderDebugView in the Debug mode (this is arranged by "#if DEBUG" in the MauiProgram.cs in the defailt VS template). In the Release mode it however goes to MauiAppBuilder.NullLogger instead which does nothing and just ignores the message.
Before the NullLogger obtains the warning message so that it could throw it away a suprisingly lot of string manipulation is performed. The LogWarning method parses the message and replaces any names in the curly brackets with the number according to its order and remembers the names. So "Warning - {RuntimePlatform} does not support View as the {PropertyName} property of RadioButton; the return value of the ToString() method will be displayed instead."
becomes "Warning - {0} does not support View as the {1} property of RadioButton; the return value of the ToString() method will be displayed instead."
. This result is sent to CompositeFormat.Parse when .NET 8 or newer is used. The method expects numbers in the curly brackets and is not happy with what it gets and crashes.
After some more testing, I have found out that the issue is even more low-level. The problem is in the int.ToString() method. It works well in the Debug mode. It works well also in the Release mode on x86 emulator (the one that does not crash). But it returns a corrupted string in the Release mode on the x86_64 emulator (those where the RadioButtons crashes). There is a some kind of padding from unprintable characters before the string representation of the number. Because these characters before the number are not printed when they are for example in the Label.Text, it is hard to notice the problem. But it causes the crash, because the expressions in the curly brackets in the warning message should be replaced by their index and because of this flaw in the int.Parse method, there is someting like "{??????????????0}" instead of "{0}". I have no idea why is this happening.
I have logged the value of 2.ToString(), 12.ToString(), and 200.ToString() using the logcat messages. You can find the result in the x86_64 emulator in the image bellow. It can be seen that there are extra characters. The same code produces the correct texts in the Debug mode, or also in the release mode in x86 emulator.
To reproduce the problem, I have created a separate branch "5IntParse" in the repro project https://github.com/holecekp/MauiBugsRadioButton/tree/5IntParse. The code in this branch just displays the result of ToString() for 2, 12, and 200 in the Labels (it is created so that it would not crash, just print the numbers). Then each of the ToString() results are compared to the expected string representation (for example 2.ToString() == "2"). The results can be seen below.
The expected result looks like this. There are three "OK" Labels showing that the texts equals with the expected value for all three numbers. This is the result from Release mode in the x86 emulator where there is no issue.
However on the problematic x86_64 emulators where the RadioButtons crashes, the screen looks like this. The ToString() displays seemingly the correct values, but this is just because the additional incorrect characters before the numbers are invisible in the Label.Text. However, it can be seen that they do not equal to the expected values (2.ToString != "2") indicated by three "Incorrect!!!" messages.
Do you have any idea what could make int.Parse to behave so weird on some emulators? I have exported the properties of one of the problematic emulator in Android Studio in case that you would like to reproduce it using as similar emulator as possible. I think however that the key difference is the "x86_64" processor architecture: emulator properties.txt
@holecekp I think we move this issue to dotnet/runtime if the underlying problem is int.Parse()
, thanks!
@holecekp, could you share what those unknown Unicode characters are?
Given this is int.ToString()
on x64, I imagine many other apps would be seeing failing scenarios if it were a problem with the core code or RyuJIT. Just int.ToString()
is itself relatively simplistic and there's not many opportunities it could get messed up
Given Mono has a SmallNumberCacheLength
of 10, compared to RyuJIT's 300, and the failure includes 12
and 200
; I'd guess the issue is rather in UInt32ToDecStr_NoSmallNumberCheck
, in which case the most likely issue is in whatever Mono is producing from FormattingHelpers.CountDigits
. If you were able to debug and breakpoint, my guess is you'd see that its returning some too large value.
This could be representative of an emulator bug or maybe some intrinsic getting mishandled on the Mono side.
The extra characters have ASCII code 0. I did another test with numbers with various number of digits. I am including the result returned by int.ToString() method (the length of the resulting string and the ASCII codes of the individual characters in it:
Other numeric types have similar problem. I have tested byte.ToString() values 0, 10, 100 and it returns string of length 10, 9, 8.
Long.ToString() behaves in a similar way. In case of 0 it returns the same result as int.ToString() and byte.ToString(). For higher numbers 10, 100, 1000, ... the resulting strings have lengths 18, 17, 16, ... With each correct digit added, two unwanted ASCII 0 characters are removed from the beginning of the string.
The problem is in MAUI in the Release mode only and only if it runs on x86_64 processor architecture emulator. The same code runs well in Debug mode on the same emulator. It runs well also in the Release mode but on x86 emulator. Moreover, I have tested that this is specific to MAUI. The same code in Xamarin.Forms project gives the correct results also in the Release mode on the problematic emulator where the same code placed in MAUI project have the issue.
Moving this to Mono as it doesn't reproduce on RyuJIT. It appears to be unique to Mono
Doesn't repro with and arm64 android emulator.
Doesn't repro with a mono x86-64 console app (on an osx-arm64 mac via rosetta, anyway):
public class Program
{
public static unsafe void Main()
{
int i = 200;
Foo(i.ToString(), "200");
}
public static void Foo (string s, string e)
{
Console.WriteLine (s.Length);
Console.WriteLine (s == e ? "ok" : "unequal");
for (int i = 0; i < s.Length; i++)
{
int n = (int)s[i];
Console.WriteLine ($"{i}: 0x{n:x8}");
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="true">
<SelfContained>true</SelfContained>
<UseMonoRuntime>true</UseMonoRuntime>
</PropertyGroup>
</Project>
setting up an x86-64 android emulator...
@holecekp I can't reproduce this with .NET 8.0.7
What I did:
dotnet workload install maui
App labels show "OK" 3 times
Thank you for trying to reproduce the isssue. It is a mistery for me why the issue is on my computer only. I have updated everything in the meanwhile (latest VS preview 3, latest MAUI 8.0.70). Still the issue is there. I had a lot of old dotnet SDKs installed (.NET 6, .NET 5). I have unistalled them but this also had no effect on the issue.
I have also tried to uncheck Optimize code checkbox in the project properties for the Release version to make it more similar to Debug version, which works. Unfortunatelly, this did not solved the issue either.
I have created APK and I will try it tomorrow on an x86_64 emulator on a different computer so that I would know if the problem is really in the APK created by VS, or if it just an emulator issue.
Are you running on an i7-i9 13000 series Intel processor?
If so, you might be encountering https://community.intel.com/t5/Processors/June-2024-Guidance-regarding-Intel-Core-13th-and-14th-Gen-K-KF/m-p/1607807 and may see it fixed by updating your bios, which should acquire the latest microcode patches
Thank you for the investigation of the issue and for the suggestion what could cause it. The processor in the the computer with the issue is however older (i5-3470). The issue is also completely deterministic. The result is the same every time. If the issue would be caused by processor instabilities I would expect that the behavior would be probably more random.
I have found something interesting. I have created an APK for the repro project. When I install it and run it in the x86_64 emulator manually (drag&drop in the Android Studio] on my computer, there is the mentioned issue. However, when I install and run the same APK on a different computer (12th Gen Intel Core i7-1260P) on an emulator with the same configuration, it works correctly. So it seems that the problem could be in the emulator on my computer (however everything should be up-to-date, I have installed all available updates in the Android SDK Manager).
@holecekp since we are unable to reproduce, there's not a lot of action we can take. As a result, I'm going to close the issue. If you have any extra info that would help, please feel free to comment and reopen the issue.
Description
If RadioButton uses a ControlTemplate, it works on Android in the debug mode. However, running the app in the release mode causes an instant crash when the page with the RadioButtons is displayed.
The crash is caused in the following following exception in MAUI:
System.FormatException: Format_InvalidStringWithOffsetAndReason, ??????????????11, Format_ExpectedAsciiDigit"
at RadioButton.ContentAsString(). I amI am including the full Logcat log (I needed to rename the extension of the file to ".json" because uploading ".logcat" files is not supported here. MauiRadioButtonCrash.json
I am including a repro project wich is a simple combination of a new MAUI app using the standard VS template and the XAML for radion buttons from the demo project linked from the official MAUI documantation on RadioButtons.
The issue is somehow similar to https://github.com/dotnet/maui/issues/22377, however in that issue the problem is for iOS only and it is caused by setting the control template for all RadioButtons from styles. There is a workaround - to set the ContentTemplate for each of the RadionButtons directly without a style. Howevere, this workaroud does not work for my issue so I assime they are different (this one is more severe because there is no workaround).
I have tried to update from MAUI 8.0.40 used in the default VS template to the latest 8.0.60 and it did not help. The app still crashes, just this time the same crash is reported in the FontManager.
Steps to Reproduce
Link to public reproduction project repository
https://github.com/holecekp/MauiBugsRadioButton
Version with bug
8.0.40 SR5
Is this a regression from previous behavior?
Yes, this used to work in Xamarin.Forms
Last version that worked well
Unknown/Other
Affected platforms
Android
Affected platform versions
Tested on Android 14 emulator
Did you find any workaround?
No workaround. The only way is to use RadioButtons with a simple string without any ControlTemplate.
Relevant log output