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

Create main.yml #4

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft

Create main.yml #4

wants to merge 2 commits into from

Conversation

dellis1972
Copy link
Owner

No description provided.

@dellis1972 dellis1972 force-pushed the githubactions branch 4 times, most recently from cf6d801 to 4642ae1 Compare June 15, 2022 09:25
dellis1972 pushed a commit that referenced this pull request Jan 27, 2023
…otnet#7732)

Fixes: dotnet#7335

Context: d236af5

Commit d236af5 introduced embedded assembly compression, using LZ4,
which speeds up startup and reduces final package size.

Assemblies are compressed at build time and, at the same time, pre-
allocated buffers for the **decompressed** data are allocated in
`libxamarin-app.so`.  The buffers are then passed to the LZ4 APIs,
all threads using the same output buffer.  The assumption was that we
can do fine without locking as even if overlapped decompression
happens, the output data will be the same and so even if two threads
do the same thing at the same time, the data will be valid at all
times, so long as at least one thread completes the decompression.

This assumption proved to be **largely** true, but it appears that in
high concurrency cases it is possible that the data in the
decompression buffer differs.  This can result in app crashes:

	A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 3092 (.NET ThreadPool), pid 2727 (myapp.name)
	A/DEBUG: pid: 2727, tid: 3092, name: .NET ThreadPool  >>> myapp.name <<<
	A/DEBUG:       #1 pc 0000000000029b1c  /data/app/myapp.name-B9t_3dF9i8mDxJEKodZw5w==/split_config.arm64_v8a.apk!libmono-android.release.so (offset 0x103d000) (xamarin::android::internal::MonodroidRuntime::mono_log_handler(char const*, char const*, char const*, int, void*)+144) (BuildId: 29c5a3805a0bedee1eede9b6668d7c676aa63371)
	A/DEBUG:       #2 pc 00000000002680bc  /data/app/myapp.name-B9t_3dF9i8mDxJEKodZw5w==/split_config.arm64_v8a.apk!libmonosgen-2.0.so (offset 0x109b000) (BuildId: 4a5dd4396e8816b7f69881838bd549285213d53b)
	A/DEBUG:       #3 pc 00000000002681e8  /data/app/myapp.name-B9t_3dF9i8mDxJEKodZw5w==/split_config.arm64_v8a.apk!libmonosgen-2.0.so (offset 0x109b000) (BuildId: 4a5dd4396e8816b7f69881838bd549285213d53b)
	A/DEBUG:       #4 pc 000000000008555c  /data/app/myapp.name-B9t_3dF9i8mDxJEKodZw5w==/split_config.arm64_v8a.apk!libmonosgen-2.0.so (offset 0x109b000) (mono_metadata_string_heap+188) (BuildId: 4a5dd4396e8816b7f69881838bd549285213d53b)
	…

My guess is that LZ4 either uses the output buffer as a scratchpad
area when decompressing or that it initializes/modifies the buffer
before writing actual data in it.  With overlapped decompression, it
may lead to one thread overwriting valid data previously written by
another thread, so that when the latter returns the buffer it thought
to have had valid data may contain certain bytes temporarily
overwritten by the decompression session in the other, still running,
thread.  It may happen that MonoVM reads the corrupted data just when
it is still invalid (before the still running decompression session
actually writes the valid data), a classic race condition.

To fix this, the decompression block is now protected with a startup-
aware mutex.  Mutex will be held only after the initial startup phase
is completed, so there should not be much loss of startup performance.
dellis1972 pushed a commit that referenced this pull request Feb 28, 2023
…otnet#7732)

Fixes: dotnet#7335

Context: d236af5

Commit d236af5 introduced embedded assembly compression, using LZ4,
which speeds up startup and reduces final package size.

Assemblies are compressed at build time and, at the same time, pre-
allocated buffers for the **decompressed** data are allocated in
`libxamarin-app.so`.  The buffers are then passed to the LZ4 APIs,
all threads using the same output buffer.  The assumption was that we
can do fine without locking as even if overlapped decompression
happens, the output data will be the same and so even if two threads
do the same thing at the same time, the data will be valid at all
times, so long as at least one thread completes the decompression.

This assumption proved to be **largely** true, but it appears that in
high concurrency cases it is possible that the data in the
decompression buffer differs.  This can result in app crashes:

	A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 3092 (.NET ThreadPool), pid 2727 (myapp.name)
	A/DEBUG: pid: 2727, tid: 3092, name: .NET ThreadPool  >>> myapp.name <<<
	A/DEBUG:       #1 pc 0000000000029b1c  /data/app/myapp.name-B9t_3dF9i8mDxJEKodZw5w==/split_config.arm64_v8a.apk!libmono-android.release.so (offset 0x103d000) (xamarin::android::internal::MonodroidRuntime::mono_log_handler(char const*, char const*, char const*, int, void*)+144) (BuildId: 29c5a3805a0bedee1eede9b6668d7c676aa63371)
	A/DEBUG:       #2 pc 00000000002680bc  /data/app/myapp.name-B9t_3dF9i8mDxJEKodZw5w==/split_config.arm64_v8a.apk!libmonosgen-2.0.so (offset 0x109b000) (BuildId: 4a5dd4396e8816b7f69881838bd549285213d53b)
	A/DEBUG:       #3 pc 00000000002681e8  /data/app/myapp.name-B9t_3dF9i8mDxJEKodZw5w==/split_config.arm64_v8a.apk!libmonosgen-2.0.so (offset 0x109b000) (BuildId: 4a5dd4396e8816b7f69881838bd549285213d53b)
	A/DEBUG:       #4 pc 000000000008555c  /data/app/myapp.name-B9t_3dF9i8mDxJEKodZw5w==/split_config.arm64_v8a.apk!libmonosgen-2.0.so (offset 0x109b000) (mono_metadata_string_heap+188) (BuildId: 4a5dd4396e8816b7f69881838bd549285213d53b)
	…

My guess is that LZ4 either uses the output buffer as a scratchpad
area when decompressing or that it initializes/modifies the buffer
before writing actual data in it.  With overlapped decompression, it
may lead to one thread overwriting valid data previously written by
another thread, so that when the latter returns the buffer it thought
to have had valid data may contain certain bytes temporarily
overwritten by the decompression session in the other, still running,
thread.  It may happen that MonoVM reads the corrupted data just when
it is still invalid (before the still running decompression session
actually writes the valid data), a classic race condition.

To fix this, the decompression block is now protected with a startup-
aware mutex.  Mutex will be held only after the initial startup phase
is completed, so there should not be much loss of startup performance.
dellis1972 pushed a commit that referenced this pull request Jul 18, 2023
)

Context: 929e701
Context: ce2bc68
Context: dotnet#7473
Context: dotnet#8155

The managed linker can produce assemblies optimized for the target
`$(RuntimeIdentifier)` (RID), which means that they will differ
between different RIDs.  Our "favorite" example of this is
`IntPtr.Size`, which is inlined by the linker into `4` or `8` when
targeting 32-bit or 64-bit platforms.  (See also dotnet#7473 and 929e701.)

Another platform difference may come in the shape of CPU intrinsics
which will change the JIT-generated native code in ways that will
crash the application if the assembler instructions generated for the
intrinsics aren't supported by the underlying processor.

In addition, the per-RID assemblies will have different [MVID][0]s
and **may** have different type and method metadata token IDs, which
is important because typemaps *use* type and metadata token IDs; see
also ce2bc68.

All of this taken together invalidates our previous assumption that
all the managed assemblies are identical.  "Simply" using
`IntPtr.Size` in an assembly that contains `Java.Lang.Object`
subclasses will break things.

This in turn could cause "mysterious" behavior or crashes in Release
applications; see also Issue dotnet#8155.

Prevent the potential problems by processing each per-RID assembly
separately and output correct per-RID LLVM IR assembly using the
appropriate per-RID information.

Additionally, during testing I found that for our use of Cecil within
`<GenerateJavaStubs/>` doesn't consistently remove the fields,
delegates, and methods we remove in `MarshalMethodsAssemblyRewriter`
when marshal methods are enabled, or it generates subtly broken
assemblies which cause **some** applications to segfault at run time
like so:

	I monodroid-gc: 1 outstanding GREFs. Performing a full GC!
	F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x8 in tid 12379 (t6.helloandroid), pid 12379 (t6.helloandroid)
	F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
	F DEBUG   : Build fingerprint: 'google/raven_beta/raven:14/UPB3.230519.014/10284690:user/release-keys'
	F DEBUG   : Revision: 'MP1.0'
	F DEBUG   : ABI: 'arm64'
	F DEBUG   : Timestamp: 2023-07-04 22:09:58.762982002+0200
	F DEBUG   : Process uptime: 1s
	F DEBUG   : Cmdline: com.microsoft.net6.helloandroid
	F DEBUG   : pid: 12379, tid: 12379, name: t6.helloandroid  >>> com.microsoft.net6.helloandroid <<<
	F DEBUG   : uid: 10288
	F DEBUG   : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
	F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000008
	F DEBUG   : Cause: null pointer dereference
	F DEBUG   :     x0  0000000000000000  x1  0000007ba1401af0  x2  00000000000000fa  x3  0000000000000001
	F DEBUG   :     x4  0000007ba1401b38  x5  0000007b9f2a8360  x6  0000000000000000  x7  0000000000000000
	F DEBUG   :     x8  ffffffffffc00000  x9  0000007b9f800000  x10 0000000000000000  x11 0000007ba1400000
	F DEBUG   :     x12 0000000000000000  x13 0000007ba374ad58  x14 0000000000000000  x15 00000013ead77d66
	F DEBUG   :     x16 0000007ba372f210  x17 0000007ebdaa4a80  x18 0000007edf612000  x19 000000000000001f
	F DEBUG   :     x20 0000000000000000  x21 0000007b9f2a8320  x22 0000007b9fb02000  x23 0000000000000018
	F DEBUG   :     x24 0000007ba374ad08  x25 0000000000000004  x26 0000007b9f2a4618  x27 0000000000000000
	F DEBUG   :     x28 ffffffffffffffff  x29 0000007fc592a780
	F DEBUG   :     lr  0000007ba3701f44  sp  0000007fc592a730  pc  0000007ba3701e0c  pst 0000000080001000
	F DEBUG   : 8 total frames
	F DEBUG   : backtrace:
	F DEBUG   :       #00 pc 00000000002d4e0c  /data/app/~~Av24J15xbf20XdrY3X2_wA==/com.microsoft.net6.helloandroid-4DusuNWIAkz1Ssi7fWVF-g==/lib/arm64/libmonosgen-2.0.so (BuildId: 761134f2369377582cc3a8e25ecccb43a2e0a877)
	F DEBUG   :       #1 pc 00000000002c29e8  /data/app/~~Av24J15xbf20XdrY3X2_wA==/com.microsoft.net6.helloandroid-4DusuNWIAkz1Ssi7fWVF-g==/lib/arm64/libmonosgen-2.0.so (BuildId: 761134f2369377582cc3a8e25ecccb43a2e0a877)
	F DEBUG   :       #2 pc 00000000002c34bc  /data/app/~~Av24J15xbf20XdrY3X2_wA==/com.microsoft.net6.helloandroid-4DusuNWIAkz1Ssi7fWVF-g==/lib/arm64/libmonosgen-2.0.so (BuildId: 761134f2369377582cc3a8e25ecccb43a2e0a877)
	F DEBUG   :       #3 pc 00000000002c2254  /data/app/~~Av24J15xbf20XdrY3X2_wA==/com.microsoft.net6.helloandroid-4DusuNWIAkz1Ssi7fWVF-g==/lib/arm64/libmonosgen-2.0.so (BuildId: 761134f2369377582cc3a8e25ecccb43a2e0a877)
	F DEBUG   :       #4 pc 00000000002be0bc  /data/app/~~Av24J15xbf20XdrY3X2_wA==/com.microsoft.net6.helloandroid-4DusuNWIAkz1Ssi7fWVF-g==/lib/arm64/libmonosgen-2.0.so (BuildId: 761134f2369377582cc3a8e25ecccb43a2e0a877)
	F DEBUG   :       #5 pc 00000000002bf050  /data/app/~~Av24J15xbf20XdrY3X2_wA==/com.microsoft.net6.helloandroid-4DusuNWIAkz1Ssi7fWVF-g==/lib/arm64/libmonosgen-2.0.so (BuildId: 761134f2369377582cc3a8e25ecccb43a2e0a877)
	F DEBUG   :       #6 pc 00000000002a53a4  /data/app/~~Av24J15xbf20XdrY3X2_wA==/com.microsoft.net6.helloandroid-4DusuNWIAkz1Ssi7fWVF-g==/lib/arm64/libmonosgen-2.0.so (mono_gc_collect+44) (BuildId: 761134f2369377582cc3a8e25ecccb43a2e0a877)
	F DEBUG   :       #7 pc 000000000000513c  <anonymous:7ec716b000>

This is because we generate Java Callable Wrappers over a set of
original (linked or not) assemblies, then we scan them for classes
derived from `Java.Lang.Object` and use that set as input to the
marshal methods rewriter, which makes the changes (generates wrapper
methods, decorates wrapped methods with `[UnmanagedCallersOnly]`,
removes the old delegate methods as well as delegate backing fields)
to all the `Java.Lang.Object` subclasses, then writes the modified
assembly to a `new/<assembly.dll>` location (efa14e2), followed by
copying the newly written assemblies back to the original location.
At this point, we have the results returned by the subclass scanner
in memory and **new** versions of those types on disk, but they are
out of sync, since the types in memory refer to the **old** assemblies,
but AOT is ran on the **new** assemblies which have a different layout,
changed MVIDs and, potentially, different type and method token IDs
(because we added some methods, removed others etc) and thus it causes
the crashes at the run time.  The now invalid set of "old" types is
passed to the typemap generator.  This only worked by accident, because
we (incorrectly) used only the first linked assembly which happened
to be the same one passed to the JLO scanner and AOT - so everything
was fine at the execution time.

Address this by *disabling* LLVM Marshal Methods (8bc7a3e) for .NET 8,
setting `$(AndroidEnableMarshalMethods)`=False by default.
We'll attempt to fix these issues for .NET 9.

[0]: https://learn.microsoft.com/dotnet/api/system.reflection.module.moduleversionid?view=net-7.0
dellis1972 pushed a commit that referenced this pull request Aug 6, 2024
Context: dotnet/maui#23694 (review)
Context: https://github.com/dotnet/maui/blob/d38ca872f68326ab623c050b0efd93c7d212e000/src/Essentials/test/DeviceTests/Tests/Preferences_Tests.cs#L305-L310
Context: dotnet/android@06bb1dc...45855b8

A .NET MAUI on-device test is crashing on API 23 emulators:

    07-23 11:35:45.837  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115] JNI ERROR (app bug): local reference table overflow (max=512)
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115] local reference table dump:
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]   Last 10 entries (of 512):
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       511: 0x6ff7e140 java.lang.Class<android.app.SharedPreferencesImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       510: 0x6ff7db18 java.lang.Class<android.app.SharedPreferencesImpl$EditorImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       509: 0x6fed5750 java.lang.Class<android.content.SharedPreferences$Editor>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       508: 0x6ff7e140 java.lang.Class<android.app.SharedPreferencesImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       507: 0x6fed57d8 java.lang.Class<android.content.SharedPreferences>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       506: 0x6ff7e140 java.lang.Class<android.app.SharedPreferencesImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       505: 0x6fed57d8 java.lang.Class<android.content.SharedPreferences>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       504: 0x6ff7db18 java.lang.Class<android.app.SharedPreferencesImpl$EditorImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       503: 0x6fed5750 java.lang.Class<android.content.SharedPreferences$Editor>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       502: 0x6ff7e140 java.lang.Class<android.app.SharedPreferencesImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]   Summary:
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       511 of java.lang.Class (7 unique instances)
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]         1 of android.app.SharedPreferencesImpl
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]
    07-23 11:35:45.930  4252  4277 F art     : art/runtime/barrier.cc:90] Check failed: count_ == 0 (count_=-1, 0=0) Attempted to destroy barrier with non zero count
    07-23 11:35:45.930  4252  4277 F art     : art/runtime/runtime.cc:366] Runtime aborting --- recursively, so no thread-specific detail!
    07-23 11:35:45.930  4252  4277 F art     : art/runtime/runtime.cc:366]
    --------- beginning of crash
    07-23 11:35:45.930  4252  4277 F libc    : Fatal signal 6 (SIGABRT), code -6 in tid 4277 (.NET TP Worker)
    07-23 11:35:46.003  1640  1640 I SELinux : SELinux: Loaded file_contexts contexts from /file_contexts.
    07-23 11:35:46.006  1640  1640 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    07-23 11:35:46.006  1640  1640 F DEBUG   : Build fingerprint: 'Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/6695544:userdebug/test-keys'
    07-23 11:35:46.006  1640  1640 F DEBUG   : Revision: '0'
    07-23 11:35:46.006  1640  1640 F DEBUG   : ABI: 'x86_64'
    07-23 11:35:46.006  1640  1640 F DEBUG   : pid: 4252, tid: 4277, name: .NET TP Worker  >>> com.microsoft.maui.essentials.devicetests <<<
    07-23 11:35:46.006  1640  1640 F DEBUG   : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    07-23 11:35:46.014  1640  1640 F DEBUG   : Abort message: 'art/runtime/indirect_reference_table.cc:115] JNI ERROR (app bug): local reference table overflow (max=512)'
    07-23 11:35:46.014  1640  1640 F DEBUG   :     rax 0000000000000000  rbx 00007f7dadfbf500  rcx ffffffffffffffff  rdx 0000000000000006
    07-23 11:35:46.014  1640  1640 F DEBUG   :     rsi 00000000000010b5  rdi 000000000000109c
    07-23 11:35:46.014  1640  1640 F DEBUG   :     r8  0000000000000001  r9  0000000000000003  r10 0000000000000008  r11 0000000000000206
    07-23 11:35:46.014  1640  1640 F DEBUG   :     r12 00000000000010b5  r13 0000000000000006  r14 00007f7dc7305a40  r15 00007f7dabd70cc0
    07-23 11:35:46.014  1640  1640 F DEBUG   :     cs  0000000000000033  ss  000000000000002b
    07-23 11:35:46.014  1640  1640 F DEBUG   :     rip 00007f7dcaa49a67  rbp 0000000000000002  rsp 00007f7dadfbc048  eflags 0000000000000206
    07-23 11:35:46.018  1640  1640 F DEBUG   :
    07-23 11:35:46.018  1640  1640 F DEBUG   : backtrace:
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #00 pc 0000000000087a67  /system/lib64/libc.so (tgkill+7)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #1 pc 0000000000085b11  /system/lib64/libc.so (pthread_kill+65)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #2 pc 000000000002e841  /system/lib64/libc.so (raise+17)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #3 pc 00000000000288fd  /system/lib64/libc.so (abort+61)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #4 pc 00000000004ffd65  /system/lib64/libart.so (art::Runtime::Abort()+341)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #5 pc 0000000000178d71  /system/lib64/libart.so (art::LogMessage::~LogMessage()+2865)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #6 pc 0000000000172dad  /system/lib64/libart.so (art::Barrier::~Barrier()+813)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #7 pc 000000000053de1a  /system/lib64/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+394)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #8 pc 00000000004ffea4  /system/lib64/libart.so (art::Runtime::Abort()+660)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #9 pc 0000000000178d71  /system/lib64/libart.so (art::LogMessage::~LogMessage()+2865)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #10 pc 00000000002f00fd  /system/lib64/libart.so (art::IndirectReferenceTable::Add(unsigned int, art::mirror::Object*)+1005)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #11 pc 00000000003ee19a  /system/lib64/libart.so (art::JNI::CallObjectMethodV(_JNIEnv*, _jobject*, _jmethodID*, __va_list_tag*)+586)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #12 pc 00000000001abdf8  /system/lib64/libart.so (art::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, __va_list_tag*, art::Primitive::Type, art::InvokeType)+1736)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #13 pc 00000000001ae031  /system/lib64/libart.so (art::CheckJNI::CallObjectMethodV(_JNIEnv*, _jobject*, _jmethodID*, __va_list_tag*)+33)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #14 pc 000000000004555d  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonodroid.so (_JNIEnv::CallObjectMethod(_jobject*, _jmethodID*, ...)+157)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #15 pc 000000000003beb5  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonodroid.so (xamarin::android::internal::MonodroidRuntime::get_java_class_name_for_TypeManager(_jclass*)+69)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #16 pc 00000000001e8585  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #17 pc 00000000001e7020  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #18 pc 00000000001d8fb5  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #19 pc 00000000001d6961  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #20 pc 00000000000e5f19  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #21 pc 00000000002a96c6  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so (mono_runtime_invoke_checked+86)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #22 pc 00000000002b202e  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #23 pc 000000000026cb84  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #24 pc 000000000027615a  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #25 pc 00000000001e8618  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #26 pc 00000000001e7066  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #27 pc 00000000001d8fb5  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #28 pc 00000000001d6961  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #29 pc 00000000000e5f19  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #30 pc 00000000002a96c6  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so (mono_runtime_invoke_checked+86)
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #31 pc 00000000002c0713  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #32 pc 0000000000084eee  /system/lib64/libc.so (__pthread_start(void*)+46)
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #33 pc 00000000000296eb  /system/lib64/libc.so (__start_thread+11)
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #34 pc 000000000001ce55  /system/lib64/libc.so (__bionic_clone+53)
    07-23 11:35:46.179  1640  1640 F DEBUG   :
    07-23 11:35:46.179  1640  1640 F DEBUG   : Tombstone written to: /data/tombstones/tombstone_00

After some investigation, we think this was introduced in 35f41dc.

I could reproduce the issue in a simple test case:

    [Test]
    public void PutAndGetManyValues ()
    {
        for (int i = 0; i < Count; i++) {
            using var prefs = GetPreferences ();
            using var editor = prefs.Edit ();
            editor.PutString ("key" + i, "value" + i);
            editor.Apply ();
        }

        for (int i = 0; i < Count; i++) {
            using var prefs = GetPreferences ();
            Assert.AreEqual ("value" + i, prefs.GetString ("key" + i, null));
        }
    }

Which also crashed with:

    07-24 09:39:02.615  4623  4638 I NUnit   : SharedPreferencesTest
    07-24 09:39:02.615  4623  4638 I NUnit   : PutAndGetManyValues
    07-24 09:39:02.719  4623  4638 F art     : art/runtime/indirect_reference_table.cc:115] JNI ERROR (app bug): local reference table overflow (max=512)

I updated `TypeManager` to use a `try-finally` block, such as:

    JniObjectReference typeClass = default;
    JniObjectReference handleClass = default;
    try {
        //...
    } finally {
        JniObjectReference.Dispose (ref handleClass);
        JniObjectReference.Dispose (ref typeClass);
    }

And it appears the test case now passes on API 23 emulators. Hoping
this will also fix .NET MAUI.
dellis1972 pushed a commit that referenced this pull request Sep 24, 2024
…dotnet#9315)

Fixes: dotnet#9200

Context: 86260ed

If you use .NET resource files for localization, a'la:

 1. Create new .net MAUI project `dotnet new maui`
 2. Add `AppResources.resx`
 3. Add `AppResources.pt.resx`
 4. Add [Translation to a Page][0]
 5. Build the app in Release configuration: `dotnet build -c Release`
 6. Run the app from (5) 

If (5) is done *on macOS or Linux*, then (6) will run fine.

If (5) is done *on Windows*, then (6) will crash:

	W monodroid-assembly: Assembly 'pt-PT/Testnet9.resources' (hash 0x1cab5580a98905b0) not found
	W monodroid-assembly: open_from_bundles: failed to load bundled assembly pt-PT/Testnet9.resources
	W monodroid-assembly: Assembly 'pt-PT/Testnet9.resources' (hash 0x1cab5580a98905b0) not found
	W monodroid-assembly: open_from_bundles: failed to load bundled assembly pt-PT/Testnet9.resources
	F monodroid-assembly: Failed to look up image index for hash 0x7357acbda27bdba3
	F monodroid: Abort at /Users/runner/work/1/s/xamarin-android/src/native/monodroid/mono-image-loader.hh:120:5 ('static MonoImage *xamarin::android::internal::MonoImageLoader::stash_and_return(MonoImage *, MonoImageOpenStatus, hash_t)')
	F libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 8622 (nyname.testnet9), pid 8622 (nyname.testnet9)
	…
	I crash_dump64: performing dump of process 8622 (target tid = 8622)
	F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
	F DEBUG   : Build fingerprint: 'google/raven/raven:14/AP2A.240805.005.F1/12043167:user/release-keys'
	F DEBUG   : Revision: 'MP1.0'
	F DEBUG   : ABI: 'arm64'
	F DEBUG   : Timestamp: 2024-09-19 14:56:09.282050201-0400
	F DEBUG   : Process uptime: 1s
	F DEBUG   : Cmdline: com.companyname.testnet9
	F DEBUG   : pid: 8622, tid: 8622, name: nyname.testnet9  >>> com.companyname.testnet9 <<<
	F DEBUG   : uid: 10432
	F DEBUG   : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
	F DEBUG   : signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
	F DEBUG   : Abort message: 'Failed to look up image index for hash 0x7357acbda27bdba3'
	F DEBUG   :     x0  0000000000000000  x1  00000000000021ae  x2  0000000000000006  x3  0000007fe644e310
	F DEBUG   :     x4  2e722e302e6a716e  x5  2e722e302e6a716e  x6  2e722e302e6a716e  x7  7f7f7f7f7f7f7f7f
	F DEBUG   :     x8  00000000000000f0  x9  0000007af562a350  x10 0000000000000001  x11 0000007af567b170
	F DEBUG   :     x12 0000007fe644cc20  x13 00000000000000de  x14 0000007fe644de48  x15 0000003e2efa613a
	F DEBUG   :     x16 0000007af56e1fd0  x17 0000007af56cd560  x18 0000007b1573c000  x19 00000000000021ae
	F DEBUG   :     x20 00000000000021ae  x21 00000000ffffffff  x22 000000773e5ed5a8  x23 000000784cd6dc8c
	F DEBUG   :     x24 000000773e5ed5c0  x25 0000007b14e0aac0  x26 0000007fe644e428  x27 0000007b14e0aac0
	F DEBUG   :     x28 0000000000000001  x29 0000007fe644e390
	F DEBUG   :     lr  0000007af56648b8  sp  0000007fe644e2f0  pc  0000007af56648e4  pst 0000000000001000
	F DEBUG   : 8 total frames
	F DEBUG   : backtrace:
	F DEBUG   :       #00 pc 000000000005d8e4  /apex/com.android.runtime/lib64/bionic/libc.so (abort+164) (BuildId: 1d36f8ae6e0af6158793abea7d4f4f2b)
	F DEBUG   :       #1 pc 00000000000450bc  /data/app/~~UeL3IzhnnKWaWNC3QvJzLQ==/com.companyname.testnet9-JRe5kbYFfMvbdm6sggxl4Q==/lib/arm64/libmonodroid.so (xamarin::android::Helpers::abort_application(bool, std::__ndk1::source_location)+68) (BuildId: 2c6d565f407362f1538c0daa0faadd527d3f394d)
	F DEBUG   :       #2 pc 000000000001ffe4  /data/app/~~UeL3IzhnnKWaWNC3QvJzLQ==/com.companyname.testnet9-JRe5kbYFfMvbdm6sggxl4Q==/lib/arm64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::open_from_bundles(void*, _MonoAssemblyName*, char**, void*, _MonoError*)+5672) (BuildId: 2c6d565f407362f1538c0daa0faadd527d3f394d)
	F DEBUG   :       #3 pc 0000000000209de0  /data/app/~~UeL3IzhnnKWaWNC3QvJzLQ==/com.companyname.testnet9-JRe5kbYFfMvbdm6sggxl4Q==/lib/arm64/libmonosgen-2.0.so (BuildId: ed96d22c7f8696c1b93010ad15c389fcae5460db)
	F DEBUG   :       #4 pc 00000000002072cc  /data/app/~~UeL3IzhnnKWaWNC3QvJzLQ==/com.companyname.testnet9-JRe5kbYFfMvbdm6sggxl4Q==/lib/arm64/libmonosgen-2.0.so (mono_assembly_request_byname+972) (BuildId: ed96d22c7f8696c1b93010ad15c389fcae5460db)
	F DEBUG   :       #5 pc 0000000000204de4  /data/app/~~UeL3IzhnnKWaWNC3QvJzLQ==/com.companyname.testnet9-JRe5kbYFfMvbdm6sggxl4Q==/lib/arm64/libmonosgen-2.0.so (BuildId: ed96d22c7f8696c1b93010ad15c389fcae5460db)
	F DEBUG   :       #6 pc 0000000000236c8c  /data/app/~~UeL3IzhnnKWaWNC3QvJzLQ==/com.companyname.testnet9-JRe5kbYFfMvbdm6sggxl4Q==/lib/arm64/libmonosgen-2.0.so (BuildId: ed96d22c7f8696c1b93010ad15c389fcae5460db)
	F DEBUG   :       #7 pc 0000000000007ee4  <anonymous:7b0493d000>

In 86260ed (and earlier?), assemblies are not loaded "by name".
Instead, at build-time assembly names are *hashed*, and at runtime
the name of the assembly to load is also hashed, and we load the
assembly based on the assembly name hash; see e.g.
`AssemblyStoreIndexEntry::name_hash` from 86260ed.

Additionally, with resource assemblies we don't hash *just* the
assembly name, e.g. `Testnet9.resources.dll`, but also include the
"directory" containing the assembly, e.g. `pt/Testnet9.resources.dll`.

Of note is the directory separator character to use: the value hashed
at runtime is in `EmbeddedAssemblies::open_from_bundles()`:

	if (culture != nullptr && *culture != '\0') {
	    name.append_c (culture);
	    name.append (zip_path_separator);
	}
	name.append_c (asmname);

`zip_path_separator` is `/`, meaning that the compile-time hash
values *also* need to use `/` to be consistent.

The problem is that `/` *wasn't* consistently used to build the
compile-time hash values;
`MarshalMethodsNativeAssemblyGenerator.AddAssemblyImageCache()` used
`Path.Combine()`, which would use `\` on Windows, not `/`.

The result is that if the app was built on Windows, the compile-time
data would hash e.g. `pt\Testnet9.dll`, which would be a different
hash value than that produced by `pt/Testnet9.dll`.  This in turn
would result in a "lookup miss":

	F monodroid-assembly: Failed to look up image index for hash 0x7357acbda27bdba3

followed by an abort.

Fix this by updating `AddAssemblyImageCache()` to normalize on `/`.

[0]: https://learn.microsoft.com/dotnet/maui/fundamentals/localization?view=net-maui-8.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant