jline / jline3

JLine is a Java library for handling console input.
Other
1.48k stars 218 forks source link

Jni provider fails on linux #896

Closed jvalkeal closed 10 months ago

jvalkeal commented 1 year ago

I'm still debugging this issue on my side but I wanted to throw this out here if it immediately rings a bell.

When trying to use 3.24.1 I'm getting into trouble with tests(where I don't have a proper tty). I get jni and exec and then jni fails with newTerminal with

java: symbol lookup error: /tmp/jlinenative-3.24.1-e342cc4f6f2aa9de-libjlinenative.so: undefined symbol: openpty

jline-error-1

If I run my cli in a real terminal and attach debugger, I have jni, jansi, jna and exec but jni doesn't fail with sysTerminal and I get PosixSysTerminal.

jline-error-2

I'm on Ubuntu 18.04.6 LTS in this system.

jvalkeal commented 1 year ago

So it looks to be CLibrary.openpty() in LinuxNativePty.open() which throws that hard error if org.jline:jline-terminal-jna is in a classpath. If jna is not in a classpath then newTerminal throws NoClassDefFoundError and JLine catches that and moves on.

gnodet commented 1 year ago

Not sure to understand, is the problem with the JNI provider or the JNA provider ? Or are those two different problems ?

jvalkeal commented 1 year ago

I'm a bit rusty with this jni stuff so give me some rope here. Looks like when this /tmp/jlinenative-3.24.1-e342cc4f6f2aa9de-libjlinenative.so is extracted and used this call

https://github.com/jline/jline3/blob/bf698ba5fe46e190616dce9284c92e8e49079c15/terminal-jni/src/main/java/org/jline/terminal/impl/jni/linux/LinuxNativePty.java#L46-L51

doesn't work. Looking ldd:

$ ldd /tmp/jlinenative-3.24.1-e342cc4f6f2aa9de-libjlinenative.so
    linux-vdso.so.1 (0x00007fff87b3c000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc9d0365000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fc9d0959000)

I don't see it linking to libutil where I think openpty is. If I do:

export LD_PRELOAD=/lib/x86_64-linux-gnu/libutil.so.1

before build then the error goes away.

jvalkeal commented 1 year ago

Quickest way to see this in JLine itself is to force system to false and run demo. Felix sets system to true so I had to tweak a code.

$ git diff
diff --git a/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java b/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java
index 64708c7d..a08d5ea0 100644
--- a/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java
+++ b/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java
@@ -148,7 +148,7 @@ public final class TerminalBuilder {
     private String type;
     private Charset encoding;
     private int codepage;
-    private Boolean system;
+    private Boolean system = false;
     private SystemOutput systemOutput;
     private String provider;
     private String providers;
@@ -179,7 +179,7 @@ public final class TerminalBuilder {
     }

     public TerminalBuilder system(boolean system) {
-        this.system = system;
+        // this.system = system;
         return this;
     }
13:07 $ ./build demo
Launching Gogo JLine...
Classpath: /home/jvalkealahti/repos/jvalkeal/jline3/demo/target/classes:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-terminal-jni-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-terminal-jansi-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-console-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-remote-telnet-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-terminal-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-builtins-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-style-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-remote-ssh-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-terminal-jna-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-terminal-ffm-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-reader-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-native-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/jline-groovy-3.24.2-SNAPSHOT.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/org.apache.felix.gogo.runtime-1.1.6.jar:/home/jvalkealahti/repos/jvalkeal/jline3/demo/target/lib/org.apache.felix.gogo.jline-1.1.8.jar
java: symbol lookup error: /tmp/jlinenative-3.24.2-349cf11782093e50-libjlinenative.so: undefined symbol: openpty

In my issue above I used custom streams(for doing testing), so it ended up calling:

https://github.com/jline/jline3/blob/bf698ba5fe46e190616dce9284c92e8e49079c15/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java#L485-L486

gnodet commented 1 year ago

Sorry for the delay. The thing I'm wondering about, is how to change the makefile so that the libraries are linked with libutil...

dattasid commented 11 months ago

You may need to load required libraries explicitly whenever you use Linker.nativeLinker() . Linker.defaultLookup() behaves differently depending on architecture, I dont think it is reliable.