Skip to content

App crashes when using SHA1.Create() under NativeAOT #10463

Description

@jonpryor

Android framework version

net10.0-android (Preview)

Affected platform version

.NET 10 Preview 7, bf02f562

Description

Invoking e.g. SHA1.Create() results in app abort.

Steps to Reproduce

Build and run the attached sample:

Scratch.net10-android-sha1-create.zip

unzip Scratch.net10-android-sha1-create.zip
cd Scratch.net10-android-sha1-create
dotnet build -c Release -p:PublishAot=true -t:Install,StartAndroidActivity -bl

Did you find any workaround?

No response

Relevant log output

F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
F DEBUG   : Build fingerprint: 'google/sdk_gphone_x86_64/generic_x86_64:9/PSR1.180720.075/5124027:user/release-keys'
F DEBUG   : Revision: '0'
F DEBUG   : ABI: 'x86_64'
F DEBUG   : pid: 7535, tid: 7535, name: oid_sha1_create  >>> com.companyname.Scratch.net10_android_sha1_create <<<
F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
F DEBUG   : Cause: null pointer dereference
F DEBUG   :     rax db81d752a45cc4b6  rbx 0000000000000066  rcx 000077fd520a4548  rdx 000077fcc4b14ee8
F DEBUG   :     r8  0000000000000020  r9  0000000073ac6f46  r10 00007fff0c6388a0  r11 00007fff0c638840
F DEBUG   :     r12 00007fff0c638c40  r13 000077fcb8176c70  r14 0000000000000014  r15 0000000000000066
F DEBUG   :     rdi 0000000000000000  rsi 000077fcc4b14ee0
F DEBUG   :     rbp 00007fff0c638810  rsp 00007fff0c6387f0  rip 000077fcb7f438a7
F DEBUG   : 
F DEBUG   : backtrace:
F DEBUG   :     #00 pc 00000000001de8a7  /data/app/com.companyname.Scratch.net10_android_sha1_create-tB7ZFDmB1pRssGB3H-teOA==/split_config.x86_64.apk (offset 0x1ce000)

Activity

  1. jonpryor commented on Sep 2, 2025

    @jonpryor
    ContributorAuthor

    App startup needs to invoke AndroidCryptoNative_InitLibraryOnLoad, defined in libSystem.Security.Cryptography.Native.Android.a.

    Question: how do we do that?

  2. jonpryor commented on Sep 2, 2025

    @jonpryor
    ContributorAuthor
  3. jonpryor commented on Sep 2, 2025

    @jonpryor
    ContributorAuthor

    The binlog contains:

    Target "SetupOSSpecificProps:
    Added Item(s): 
        DirectPInvoke=
            System.Native
            System.Globalization.Native
            System.IO.Compression.Native
            System.Security.Cryptography.Native.Android
    

    System.Security.Cryptography.Native.Android presumably meaning libSystem.Security.Cryptography.Native.Android.a, which contains AndroidCryptoNative_InitLibraryOnLoad.

    This is later transformed within the WriteIlcRspFileForCompilation target into ilc parameters:

    Added Item(s): 
        IlcArg=
            --directpinvoke:System.Native
            --directpinvoke:System.Globalization.Native
            --directpinvoke:System.IO.Compression.Native
            --directpinvoke:System.Security.Cryptography.Native.Android
    

    Which become part of a .ilc.rsp file.

    What I find interesting are two things:

    First, the regulating .o file contains no symbols from libSystem.Security.Cryptography.Native.Android.a. This suggests that libSystem.Security.Cryptography.Native.Android.a isn't actually being used.

    Second, I'm not sure how ilc is supposed to find libSystem.Security.Cryptography.Native.Android.a. There is no real "tying" of System.Security.Cryptography.Native.Android to a filesystem location for libSystem.Security.Cryptography.Native.Android.a. That is, libSystem.Security.Cryptography.Native.Android.a is:

    $HOME/.nuget/packages/microsoft.netcore.app.runtime.nativeaot.android-arm64/10.0.0-rc.2.25420.109/runtimes/android-arm64/native/libSystem.Security.Cryptography.Native.Android.a
    

    but of the values within .ilc.rsp that contain absolute paths:

    -r:$HOME/.nuget/packages/microsoft.netcore.app.runtime.nativeaot.android-x64/10.0.0-rc.2.25420.109/runtimes/android-x64/native/System.Private.CoreLib.dll
    -r:$HOME/.nuget/packages/microsoft.netcore.app.runtime.nativeaot.android-x64/10.0.0-rc.2.25420.109/runtimes/android-x64/native/System.Private.Reflection.Execution.dll
    -r:$HOME/.nuget/packages/microsoft.netcore.app.runtime.nativeaot.android-x64/10.0.0-rc.2.25420.109/runtimes/android-x64/native/System.Private.StackTraceMetadata.dll
    -r:$HOME/.nuget/packages/microsoft.netcore.app.runtime.nativeaot.android-x64/10.0.0-rc.2.25420.109/runtimes/android-x64/native/System.Private.TypeLoader.dll
    …
    --descriptor:…/dotnet/android/bin/Debug/lib/packs/Microsoft.Android.Sdk.Darwin/36.0.0/PreserveLists/Java.Interop.xml
    --descriptor:…/dotnet/android/bin/Debug/lib/packs/Microsoft.Android.Sdk.Darwin/36.0.0/PreserveLists/Mono.Android.Runtime.xml
    --descriptor:…/dotnet/android/bin/Debug/lib/packs/Microsoft.Android.Sdk.Darwin/36.0.0/PreserveLists/Mono.Android.xml
    --descriptor:…/dotnet/android/bin/Debug/lib/packs/Microsoft.Android.Sdk.Darwin/36.0.0/PreserveLists/System.Runtime.InteropServices.xml
    --descriptor:…/dotnet/android/bin/Debug/lib/packs/Microsoft.Android.Sdk.Darwin/36.0.0/PreserveLists/System.Runtime.xml
    

    None look like a straightforward way to find libSystem.Security.Cryptography.Native.Android.a, unless you wanted to do various ../../../… path probing logic against the various -r values.

    Looking at ilc --help output, I'm not sure I see anything that screams "path to .a to include in output". How is --directpinvoke supposed to work?

  4. MichalStrehovsky commented on Sep 2, 2025

    @MichalStrehovsky
    Member

    DirectPInvoke just means "when I have a DllImport to the specified library!symbol, don't generate code that tries to dlopen/dlsym this at runtime; instead generate a symbol reference and let the linker (native linker, not "our IL linker") deal with it.

    I think what you need is in dotnet/runtime#108513 that didn't merge yet?

  5. jonpryor commented on Sep 3, 2025

    @jonpryor
    ContributorAuthor

    @MichalStrehovsky wrote:

    DirectPInvoke just means "when I have a DllImport to the specified library!symbol, don't generate code that tries to dlopen/dlsym this at runtime; instead generate a symbol reference and let the linker (native linker, not "our IL linker") deal with it.

    This is enlightening, and answers a conceptual question I had.


    It is thus possible to workaround this issue:

    Firstly, .NET 10 Preview 7 cannot be used. .NET 10 RC1 or later is required. A newer .NET 10 is required so that libSystem.Security.Cryptography.Native.Android.a exists and is used at build time, instead of libSystem.Security.Cryptography.Native.OpenSsl.so, which cannot work on Android.

    If you don't mind building dotnet/android, use dotnet/android@3ed06827 or later.

    Using a custom dotnet/android build in turn requires a custom NuGet.config file so that various dependencies can be found.

    Additionally, AndroidCryptoNative_InitLibraryOnLoad() must be invoked. This requires three separate changes:

    1. Add a P/Invoke to System.Security.Cryptography.Native.Android!AndroidCryptoNative_InitLibraryOnLoad

    2. Add an Application subclass which invokes AndroidCryptoNative_InitLibraryOnLoad().

    3. Update the .csproj to add a @(DirectPInvoke) which tells ilc
      "when you see a P/Invoke to AndroidCryptoNative_InitLibraryOnLoad, turn it into a function invocation."

      <ItemGroup>
        <DirectPInvoke Include="System.Security.Cryptography.Native.Android!AndroidCryptoNative_InitLibraryOnLoad" />
      </ItemGroup>

      The syntax is LIBRARY!SYMBOL, and LIBRARY must match the P/Invoke library declaration, and
      SYMBOL must match the P/Invoke method name.

    The above three steps correspond to the following patch to Scratch.net10-android-sha1-create.zip:

    diff --git a/MainActivity.cs b/MainActivity.cs
    index 634ae50..936e3be 100644
    --- a/MainActivity.cs
    +++ b/MainActivity.cs
    @@ -1,5 +1,9 @@
    +using System.Runtime.InteropServices;
     using System.Security.Cryptography;
     
    +using Android.Runtime;
    +using Java.Interop;
    +
     namespace Scratch.net10_android_sha1_create;
     
     [Activity(Label = "@string/app_name", MainLauncher = true)]
    @@ -15,4 +19,29 @@ public class MainActivity : Activity
             // Set our view from the "main" layout resource
             SetContentView(Resource.Layout.activity_main);
         }
    -}
    \ No newline at end of file
    +}
    +
    +[Application]
    +public class MyApp : Application
    +{
    +    public MyApp(IntPtr handle, JniHandleOwnership transfer)
    +        : base(handle, transfer)
    +    {
    +    }
    +
    +    public override void OnCreate()
    +    {
    +        base.OnCreate();
    +        IntPtr invocationPointer;
    +        JniEnvironment.References.GetJavaVM(out invocationPointer);
    +        UnsafeNativeMethods.AndroidCryptoNative_InitLibraryOnLoad(
    +            javaVM: invocationPointer,
    +            reserved: IntPtr.Zero);
    +    }
    +}
    +
    +static class UnsafeNativeMethods
    +{
    +    [DllImport("System.Security.Cryptography.Native.Android", CallingConvention = CallingConvention.Cdecl)]
    +    internal static extern void AndroidCryptoNative_InitLibraryOnLoad(IntPtr javaVM, IntPtr reserved);
    +}
    diff --git a/Scratch.net10-android-sha1-create.csproj b/Scratch.net10-android-sha1-create.csproj
    index b816b61..51b728a 100644
    --- a/Scratch.net10-android-sha1-create.csproj
    +++ b/Scratch.net10-android-sha1-create.csproj
    @@ -22,4 +22,7 @@
         -->
         <TrimMode>full</TrimMode>
       </PropertyGroup>
    +  <ItemGroup>
    +    <DirectPInvoke Include="System.Security.Cryptography.Native.Android!AndroidCryptoNative_InitLibraryOnLoad" />
    +  </ItemGroup>
     </Project>
    \ No newline at end of file

    With those changes in place, Publish and run the app:

    …/dotnet-local.sh publish -c Release -p:PublishAot=true -t:Install,StartAndroidActivity -bl
    

    You know it works properly when AndroidCryptoNative_InitLibraryOnLoad is present in the native library:

    % nm bin/Release/net10.0-android/android-arm64/native/Scratch.net10-android-sha1-create.so | grep AndroidCryptoNative_InitLibraryOnLoad
    00000000001d34f0 t AndroidCryptoNative_InitLibraryOnLoad
    000000000027ef10 t Scratch_net10_android_sha1_create_Scratch_net10_android_sha1_create_UnsafeNativeMethods__AndroidCryptoNative_InitLibraryOnLoad
    0000000000010a2b r _lsda0Scratch_net10_android_sha1_create_Scratch_net10_android_sha1_create_UnsafeNativeMethods__AndroidCryptoNative_InitLibraryOnLoad
  6. 9 remaining items

  7. jonpryor commented on Oct 20, 2025

    @jonpryor
    ContributorAuthor

    This has been fixed in .NET 10 RC2, in that the workaround is no longer required.

  8. locked and limited conversation to collaborators on Nov 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: App RuntimeIssues in `libmonodroid.so`.needs-triageIssues that need to be assigned.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions