ajalt / mordant

Multiplatform text styling for Kotlin command-line applications
https://ajalt.github.io/mordant/
Apache License 2.0
957 stars 34 forks source link

After using GraalVM's native-image to static link, the program fails to run #112

Closed XhstormR closed 11 months ago

XhstormR commented 1 year ago

build.gradle.kts:

....

  graalvmNative {
      binaries.all {
          resources.autodetect()
          buildArgs("--static") // Tell native-image to use static link
      }
  }

....

Environment:

clikt: com.github.ajalt.clikt:clikt:4.2.0

bash-5.1# native-image --version
native-image 20.0.2 2023-07-18
GraalVM Runtime Environment GraalVM CE 20.0.2+9.1 (build 20.0.2+9-jvmci-23.0-b15)
Substrate VM GraalVM CE 20.0.2+9.1 (build 20.0.2+9, serial gc)

Log:

bash-5.1# /app/build/native/nativeCompile/sast
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'isatty': sast: undefined symbol: isatty
        at com.sun.jna.Function.<init>(Function.java:252)
        at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:620)
        at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:596)
        at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:582)
        at com.sun.jna.Library$Handler.invoke(Library.java:248)
        at jdk.proxy4/jdk.proxy4.$Proxy48.isatty(Unknown Source)
        at com.github.ajalt.mordant.internal.LinuxMppImpls.stdinInteractive(JnaMppImplsLinux.kt:46)
        at com.github.ajalt.mordant.internal.MppImplKt.stdinInteractive(MppImpl.kt:104)
        at com.github.ajalt.mordant.terminal.TerminalDetection.detectTerminal(TerminalDetection.kt:17)
        at com.github.ajalt.mordant.terminal.StdoutTerminalInterface.<init>(StdoutTerminalInterface.kt:17)
        at com.github.ajalt.mordant.terminal.Terminal.<init>(Terminal.kt:56)
        at com.github.ajalt.mordant.terminal.Terminal.<init>(Terminal.kt:45)
        at com.github.ajalt.clikt.core.Context$Builder.<init>(Context.kt:227)
        at com.github.ajalt.clikt.core.Context$Companion.build$clikt(Context.kt:312)
        at com.github.ajalt.clikt.core.CliktCommand.createContext(CliktCommand.kt:141)
        at com.github.ajalt.clikt.core.CliktCommand.parse(CliktCommand.kt:456)
        at com.github.ajalt.clikt.core.CliktCommand.parse$default(CliktCommand.kt:455)
        at com.github.ajalt.clikt.core.CliktCommand.main(CliktCommand.kt:475)
        at com.github.ajalt.clikt.core.CliktCommand.main(CliktCommand.kt:482)
        at io.github.xhstormr.sast.cli.MainKt.main(Main.kt:47)
root@60ebed6655c8:/app/build/native/nativeCompile# ./sast
[ [ SubstrateSegfaultHandler caught a segfault in thread 0x0000000002a6a640 ] ]
siginfo: si_signo: 11, si_code: 1, si_addr: 0x0000000000000000

Current timestamp: 1691723918185

General purpose register values:
  RAX 0x0000000000000000 
  RBX 0x0000000002a6a640 is a thread
  RCX 0x00000000ffffffff is an unknown value
  RDX 0x00007f20b13ed37f is an unknown value
  RBP 0x00007ffcc4911710 points into the stack for thread 0x0000000002a6a640
  RSI 0x0000000000000101 is an unknown value
  RDI 0x0000000000000000 
  RSP 0x00007ffcc49116b0 points into the stack for thread 0x0000000002a6a640
  R8  0x0000000002a6da10 is an unknown value
  R9  0x00007f20b13e3050 is an unknown value
  R10 0x00007f20b11c8bb8 is an unknown value
  R11 0x00007f20b1249700 is an unknown value
  R12 0x0000000000000000 
  R13 0x00007ffcc4911738 points into the stack for thread 0x0000000002a6a640
  R14 0x0000000000000101 is an unknown value
  R15 0x0000000002a6a640 is a thread
  EFL 0x0000000000010246 is an unknown value
  RIP 0x00007f20b124977c is an unknown value

Printing Instructions (ip=0x00007f20b124977c):
  0x00007f20b124975c: 0x2b 0x14 0x25 0x28 0x00 0x00 0x00 0x75 0x30 0x48 0x83 0xc4 0x38 0xc3 0x66 0x0f
  0x00007f20b124976c: 0x1f 0x44 0x00 0x00 0x48 0x8b 0x80 0x88 0x03 0x00 0x00 0x48 0x8b 0x54 0x24 0x38
  0x00007f20b124977c: 0x48 0x8b 0x00 0x48 0x8b 0x4c 0x24 0x28 0x64 0x48 0x2b 0x0c 0x25 0x28 0x00 0x00
  0x00007f20b124978c: 0x00 0x75 0x06 0x48 0x83 0xc4 0x38 0xff 0xe0 0xe8 0x86 0x5f 0x0a 0x00 0x66 0x0f

Top of stack (sp=0x00007ffcc49116b0):
  0x00007ffcc49116b0: 0x0000005c00000000 0x00007f20b20457e8
  0x00007ffcc49116c0: 0x00007f20b2a9d130 0x00007f20b2045d90
  0x00007ffcc49116d0: 0x0000000002a6a640 0x518459ec90b49800
  0x00007ffcc49116e0: 0x0000000000000032 0x00007f20b13ed37f
  0x00007ffcc49116f0: 0x00007f20b20461a8 0x00000000006ee2d7
  0x00007ffcc4911700: 0x00007ffcc4911738 0x00007f20b2200000
  0x00007ffcc4911710: 0x00007f20b20461c8 0x00000000006ee2ea
  0x00007ffcc4911720: 0x00007f20b2045c00 0x00000000009e3091
  0x00007ffcc4911730: 0x00007f20b2200000 0x00000000006ee2d7
  0x00007ffcc4911740: 0x00007ffcc4911720 0x0000000000000000
  0x00007ffcc4911750: 0x00000001006488b0 0x00007f20b13ed330
  0x00007ffcc4911760: 0xffffffff00000001 0x00000000006f9415
  0x00007ffcc4911770: 0x0000000000000000 0x0000000000000000
  0x00007ffcc4911780: 0x000000003f400000 0x0000000000000000
  0x00007ffcc4911790: 0x0000000000000000 0x0000000000000000
  0x00007ffcc49117a0: 0x0000000045db1099 0x00007f20b2045c70
  0x00007ffcc49117b0: 0x00007f20b27cb518 0x00007f20b262cb10
  0x00007ffcc49117c0: 0xffffffffffe30fc0 0x00007f20b20457c0
  0x00007ffcc49117d0: 0x00007f20b2844770 0x00007f20b27c5a20
  0x00007ffcc49117e0: 0x00007f20b2030fc0 0x00007f20b2200000
  0x00007ffcc49117f0: 0x00007f20b2045658 0x00007f20b262d110
  0x00007ffcc4911800: 0x00007f20b2a6a2e0 0x00000000006d65f7
  0x00007ffcc4911810: 0x0000000040400000 0x0000000000000000
  0x00007ffcc4911820: 0x0000000000000000 0x00007f20b262bb90
  0x00007ffcc4911830: 0x00007f20b2b39508 0x00007f20b25c7798
  0x00007ffcc4911840: 0x00007f20b262d110 0x00007f20b2030398
  0x00007ffcc4911850: 0x00000000fffffffe 0x00000000006e999d
  0x00007ffcc4911860: 0x00007f20b2a69820 0x00007f20b28488b0
  0x00007ffcc4911870: 0x0000000000000005 0x00007f20b2030398
  0x00007ffcc4911880: 0x00007f20b262d110 0x00007f20b2b39508
  0x00007ffcc4911890: 0x00007f20b25c7798 0x00000000004630a5
  0x00007ffcc49118a0: 0x00007f20b29ce3d8 0x00000000007c1ab7

Top frame info:
  Does not look like a Java Frame. Use JavaFrameAnchors to find LastJavaSP:
  Found matching Anchor:0x00007ffcc4911738
  LastJavaSP 0x00007ffcc4911720
  LastJavaIP 0x00000000006ee2d7

Threads:
  0x00007f20a4000b80 STATUS_IN_NATIVE (ALLOW_SAFEPOINT) "process reaper" - 0x00007f20b2038bb0, daemon, stack(0x00007f20b2fcd000,0x00007f20b2ffa000)
  0x00007f20ac000b80 STATUS_IN_NATIVE (ALLOW_SAFEPOINT) "Reference Handler" - 0x00007f20b2997000, daemon, stack(0x00007f20b1801000,0x00007f20b2000000)
  0x0000000002a6a640 STATUS_IN_JAVA (PREVENT_VM_FROM_REACHING_SAFEPOINT) "main" - 0x00007f20b2996f48, stack(0x00007ffcc4114000,0x00007ffcc4913000)

VM thread locals for the failing thread 0x0000000002a6a640:
  0 (8 bytes): JNIThreadLocalEnvironment.jniFunctions = (bytes) 
    0x0000000002a6a640: 0x00007f20b27b4010
  8 (8 bytes): StackOverflowCheckImpl.stackBoundaryTL = (Word) 1 (0x0000000000000001)
  16 (4 bytes): Safepoint.safepointRequested = (int) 2147414831 (0x7ffef32f)
  20 (4 bytes): StatusSupport.statusTL = (int) 1 (0x00000001)
  24 (32 bytes): ThreadLocalAllocation.regularTLAB = (bytes) 
    0x0000000002a6a658: 0x00007f20b2000000 0x00007f20b2100000
    0x0000000002a6a668: 0x00007f20b20461f0 0x0000000000000000
  56 (8 bytes): PlatformThreads.currentThread = (Object) java.lang.Thread (0x00007f20b2996f48)
  64 (8 bytes): JavaFrameAnchors.lastAnchor = (Word) 140723606329144 (0x00007ffcc4911738)
  72 (8 bytes): PlatformThreads.currentVThreadId = (long) 1 (0x0000000000000001)
  80 (8 bytes): AccessControlContextStack = (Object) java.util.ArrayDeque (0x00007f20b2018898)
  88 (8 bytes): ExceptionUnwind.currentException = (Object) null
  96 (8 bytes): IdentityHashCodeSupport.hashCodeGeneratorTL = (Object) java.util.SplittableRandom (0x00007f20b201a728)
  104 (8 bytes): IsolatedCompileClient.currentClient = (Object) null
  112 (8 bytes): IsolatedCompileContext.currentContext = (Object) null
  120 (8 bytes): JNIObjectHandles.handles = (Object) com.oracle.svm.core.handles.ThreadLocalHandles (0x00007f20b2001220)
  128 (8 bytes): JNIThreadLocalPendingException.pendingException = (Object) null
  136 (8 bytes): JNIThreadLocalPinnedObjects.pinnedObjectsListHead = (Object) null
  144 (8 bytes): JNIThreadOwnedMonitors.ownedMonitors = (Object) null
  152 (8 bytes): NoAllocationVerifier.openVerifiers = (Object) null
  160 (8 bytes): ThreadingSupportImpl.activeTimer = (Object) null
  168 (8 bytes): SubstrateDiagnostics.threadOnlyAttachedForCrashHandler = (bytes) 
    0x0000000002a6a6e8: 0x0000000000000000
  176 (8 bytes): ThreadLocalAllocation.allocatedBytes = (Word) 0 (0x0000000000000000)
  184 (8 bytes): VMThreads.IsolateTL = (Word) 139778404122624 (0x00007f20b2200000)
  192 (8 bytes): VMThreads.OSThreadHandleTL = (Word) 44471232 (0x0000000002a693c0)
  200 (8 bytes): VMThreads.OSThreadIdTL = (Word) 44471232 (0x0000000002a693c0)
  208 (8 bytes): VMThreads.StackBase = (Word) 140723606335488 (0x00007ffcc4913000)
  216 (8 bytes): VMThreads.StackEnd = (Word) 140723597950976 (0x00007ffcc4114000)
  224 (8 bytes): VMThreads.StartedByCurrentIsolate = (bytes) 
    0x0000000002a6a720: 0x0000000000000000
  232 (8 bytes): VMThreads.nextTL = (Word) 0 (0x0000000000000000)
  240 (8 bytes): VMThreads.unalignedIsolateThreadMemoryTL = (Word) 44475920 (0x0000000002a6a610)
  248 (4 bytes): ActionOnExitSafepointSupport.actionTL = (int) 0 (0x00000000)
  252 (4 bytes): ActionOnTransitionToJavaSupport.actionTL = (int) 0 (0x00000000)
  256 (4 bytes): ImplicitExceptions.implicitExceptionsAreFatal = (int) 0 (0x00000000)
  260 (4 bytes): StackOverflowCheckImpl.yellowZoneStateTL = (int) 2130640638 (0x7efefefe)
  264 (4 bytes): StatusSupport.safepointBehaviorTL = (int) 1 (0x00000001)
  268 (4 bytes): ThreadingSupportImpl.currentPauseDepth = (int) 0 (0x00000000)

No VMOperation in progress

The 15 most recent VM operation status changes (oldest first):

Counters:

Java frame anchors for the failing thread 0x0000000002a6a640:
  Anchor 0x00007ffcc4911738 LastJavaSP 0x00007ffcc4911720 LastJavaIP 0x00000000006ee2d7

Stacktrace for the failing thread 0x0000000002a6a640:
  SP 0x00007ffcc49116b0 IP 0x00007f20b124977c  IP is not within Java code. Trying frame anchor of last Java frame instead.
  SP 0x00007ffcc4911720 IP 0x00000000006ee2d7  [image code] com.sun.jna.Native.open(Native Method)
  SP 0x00007ffcc4911770 IP 0x00000000006f9415  [image code] com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:480)
  SP 0x00007ffcc4911810 IP 0x00000000006d65f7  [image code] com.sun.jna.Library$Handler.<init>(Library.java:197)
  SP 0x00007ffcc4911860 IP 0x00000000006e999d  [image code] com.sun.jna.Native.load(Native.java:622)
  SP 0x00007ffcc49118a0 IP 0x00000000004630a5  [image code] com.sun.jna.Native.load(Native.java:596)
  SP 0x00007ffcc49118a0 IP 0x00000000004630a5  [image code] com.github.ajalt.mordant.internal.LinuxMppImpls.<init>(JnaMppImplsLinux.kt:44)
  SP 0x00007ffcc49118d0 IP 0x0000000000463d65  [image code] com.github.ajalt.mordant.internal.MppImplKt.<clinit>(MppImpl.kt:97)
  SP 0x00007ffcc4911900 IP 0x000000000055b66b  [image code] com.oracle.svm.core.classinitialization.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:407)
  SP 0x00007ffcc4911910 IP 0x000000000055a065  [image code] com.oracle.svm.core.classinitialization.ClassInitializationInfo.doInitialize(ClassInitializationInfo.java:323)
  SP 0x00007ffcc4911950 IP 0x000000000055a5e7  [image code] com.oracle.svm.core.classinitialization.ClassInitializationInfo.initialize(ClassInitializationInfo.java:272)
  SP 0x00007ffcc4911c10 IP 0x00000000005289bc  [image code] com.github.ajalt.mordant.terminal.TerminalDetection.isJediTerm(TerminalDetection.kt:143)
  SP 0x00007ffcc4911c20 IP 0x0000000000528885  [image code] com.github.ajalt.mordant.terminal.TerminalDetection.isIntellijRunActionConsole(TerminalDetection.kt:169)
  SP 0x00007ffcc4911c30 IP 0x0000000000527495  [image code] com.github.ajalt.mordant.terminal.TerminalDetection.detectTerminal(TerminalDetection.kt:16)
  SP 0x00007ffcc4911c90 IP 0x0000000000523b88  [image code] com.github.ajalt.mordant.terminal.StdoutTerminalInterface.<init>(StdoutTerminalInterface.kt:17)
  SP 0x00007ffcc4911c90 IP 0x0000000000523b88  [image code] com.github.ajalt.mordant.terminal.Terminal.<init>(Terminal.kt:56)
  SP 0x00007ffcc4911cc0 IP 0x0000000000523d55  [image code] com.github.ajalt.mordant.terminal.Terminal.<init>(Terminal.kt:45)
  SP 0x00007ffcc4911ce0 IP 0x000000000041409c  [image code] com.github.ajalt.clikt.core.Context$Builder.<init>(Context.kt:227)
  SP 0x00007ffcc4911d20 IP 0x0000000000414587  [image code] com.github.ajalt.clikt.core.Context$Companion.build$clikt(Context.kt:312)
  SP 0x00007ffcc4911d80 IP 0x00000000004106a5  [image code] com.github.ajalt.clikt.core.CliktCommand.createContext(CliktCommand.kt:141)
  SP 0x00007ffcc4911db0 IP 0x0000000000411584  [image code] com.github.ajalt.clikt.core.CliktCommand.parse(CliktCommand.kt:456)
  SP 0x00007ffcc4911dd0 IP 0x00000000004114ce  [image code] com.github.ajalt.clikt.core.CliktCommand.parse$default(CliktCommand.kt:455)
  SP 0x00007ffcc4911dd0 IP 0x00000000004114ce  [image code] com.github.ajalt.clikt.core.CliktCommand.main(CliktCommand.kt:475)
  SP 0x00007ffcc4911df0 IP 0x0000000000411469  [image code] com.github.ajalt.clikt.core.CliktCommand.main(CliktCommand.kt:482)
  SP 0x00007ffcc4911e10 IP 0x00000000007466aa  [image code] io.github.xhstormr.sast.cli.MainKt.main(Main.kt:47)
  SP 0x00007ffcc4911e30 IP 0x000000000054d91f  [image code] com.oracle.svm.core.JavaMainWrapper.runCore0(JavaMainWrapper.java:178)
  SP 0x00007ffcc4911e50 IP 0x000000000054d605  [image code] com.oracle.svm.core.JavaMainWrapper.runCore(JavaMainWrapper.java:136)
  SP 0x00007ffcc4911e50 IP 0x000000000054d605  [image code] com.oracle.svm.core.JavaMainWrapper.doRun(JavaMainWrapper.java:233)
  SP 0x00007ffcc4911e80 IP 0x0000000000581b6b  [image code] com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:219)
  SP 0x00007ffcc4911e80 IP 0x0000000000581b6b  [image code] com.oracle.svm.core.code.IsolateEnterStub.JavaMainWrapper_run_3148eece06270530b6e0d4d60311411342c82698(IsolateEnterStub.java:0)

VM mutexes:
  mutex "referencePendingList" is unlocked.
  mutex "thread" is unlocked.
  mutex "mainVMOperationControlWorkQueue" is unlocked.

AOT compiled code is mapped at 0x0000000000403000 - 0x0000000000f0e09f

Heap settings and statistics:
  Supports isolates: true
  Heap base: 0x00007f20b2200000
  Object reference size: 8
  Aligned chunk size: 1048576
  Incremental collections: 0
  Complete collections: 0

Native image heap boundaries:
  ReadOnly Primitives: 0x00007f20b2301030 - 0x00007f20b25ba4c0
  ReadOnly References: 0x00007f20b25ba4c0 - 0x00007f20b27b31e8
  ReadOnly Relocatables: 0x00007f20b27b4000 - 0x00007f20b289be20
  Writable Primitives: 0x00007f20b289c000 - 0x00007f20b292fe58
  Writable References: 0x00007f20b292fe58 - 0x00007f20b2bc7508
  Writable Huge: 0x00007f20b2c00038 - 0x00007f20b2c5bbc8
  ReadOnly Huge: 0x00007f20b2c5c038 - 0x00007f20b2f372f0

Heap:
  Young generation: 
    Eden: 
      edenSpace:
        aligned: 0/0 unaligned: 0/0
    Survivors: 
      Survivor-1 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-1 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-2 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-2 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-3 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-3 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-4 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-4 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-5 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-5 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-6 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-6 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-7 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-7 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-8 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-8 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-9 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-9 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-10 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-10 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-11 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-11 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-12 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-12 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-13 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-13 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-14 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-14 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-15 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-15 To:
        aligned: 0/0 unaligned: 0/0
  Old generation: 
    oldFromSpace:
      aligned: 0/0 unaligned: 0/0
    oldToSpace:
      aligned: 0/0 unaligned: 0/0

  Unused:
    aligned: 0/0

Segfault detected, aborting process. Use '-XX:-InstallSegfaultHandler' to disable the segfault handler at run time and create a core dump instead. Rebuild with '-R:-InstallSegfaultHandler' to disable the handler permanently at build time.
XhstormR commented 1 year ago

may be related to this https://github.com/oracle/graal/issues/3359

com.sun.jna.NativeLibrary#getInstance(java.lang.String, java.util.Map<java.lang.String,?>)

image
hubvd commented 1 year ago

I had the same issue and I found a solution.

https://github.com/hubvd/odoo-tools/commit/74e1bc98be8a1fd00810474c489512b240025204

By utilizing the @Substitute annotation, we can effectively swap out the existing JNA implementation with the org.graalvm.nativeimage.c package. I only ported LinuxMppImpls, but MacosMppImpls and Win32MppImpls should also be substituted.

I also removed the JNA dependency and the native image metadata since we don't need it anymore. This isn't strictly needed though, it is only done in order to have a smaller binary.

Maybe this could be integrated in mordant directly.

ajalt commented 1 year ago

@hubvd looks cool, thanks for sharing! I'd definitely accept a PR if you want to integrate it into mordant.

hubvd commented 1 year ago

I'll try to do that this week :smiley:

azenla commented 12 months ago

Thanks for looking into this, my programming language pork (https://github.com/GayPizzaSpecifications/pork) utilizes Graal for native compilation and clikt for the frontend. My workaround currently is to add a mintool project which doesn't use clikt for simple use cases.