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

Undefined behaviour when calling ioctl() multiple times #1632

Open
Gieted opened this issue Oct 18, 2024 · 5 comments
Open

Undefined behaviour when calling ioctl() multiple times #1632

Gieted opened this issue Oct 18, 2024 · 5 comments

Comments

@Gieted
Copy link

Gieted commented Oct 18, 2024

JNA version: 5.15.0
JVM: GraalVM CE 17.0.9+9.1 (build 17.0.9+9-jvmci-23.0-b22)
OS: macOS 14.7
CPU: Apple M1 (64-bit)

public interface LibC extends Library {
    LibC libC = Native.load("c", LibC.class);
    int TIOCGWINSZ = 0x40087468; // this is definitely correct, I've checked it with C
    
    int ioctl(int fd, int request, winsize winsize);  
}

public static int getWindowSize() {
    val ttysize = new winsize();

    val returnCode = libC.ioctl(0, TIOCGWINSZ, ttysize);
    if (returnCode != 0) {
        throw new RuntimeException("There was a problem calling ioctl(): " + returnCode);
    }

    return ttysize.ws_col;
}

 for (int i = 0; i < 100; i++) {
      System.out.println(getWindowSize());
}

running this code results in either:

  1. ioctl() returning -1
  2. SIGSEGV
  3. Illegal instruction: 4
  4. Heap corruption detected
@matthiasblaesing
Copy link
Member

Please specify:

  • The C definition of winsize?
  • The C definition of LibC/ioctl?
  • The java definition of winsize?
  • Which language is used here? It is not java, unless this code was never executed (there is no val keyword)

I'm missing the reasoning/proof, that this is a bug in JNA. I have yet to see segfaults not caused by issues in the bindings.

@Gieted
Copy link
Author

Gieted commented Oct 18, 2024

"val" comes from Lombok, you can replace it with "var" and it will work.

/*
 * Window/terminal size structure.  This information is stored by the kernel
 * in order to provide a consistent interface, but is not used by the kernel.
 */
struct winsize {
	unsigned short  ws_row;         /* rows, in characters */
	unsigned short  ws_col;         /* columns, in characters */
	unsigned short  ws_xpixel;      /* horizontal size, pixels */
	unsigned short  ws_ypixel;      /* vertical size, pixels */
};

int     ioctl(int, unsigned long, ...);
@Structure.FieldOrder(value = {"ws_row", "ws_col", "ws_xpixel", "ws_ypixel"})
class winsize extends Structure {
    public short ws_row;
    public short ws_col;
    public short ws_xpixel;
    public short ws_ypixel;
}

I've also tried changing "request" type to long and defining constant as long TIOCGWINSZ = 0x40087468L;, but it's still the same.

My reasoning for it being an issue is JNA related, is that for non-crash case, GetLastError() returns [14] Bad address, which to my understanding cannot happen because of a typo in bindings.

@Gieted
Copy link
Author

Gieted commented Oct 18, 2024

Sorry for a confusion earlier, I've just discovered that I wasn't using Temurin JDK, but GraalVM. In fact the issue doesn't seem to occur when using Temurin. Are there any known issues related to JNA not being compatible with GraalVM?

@dbwiddis
Copy link
Contributor

dbwiddis commented Oct 18, 2024

int ioctl(int, unsigned long, ...);

Second argument is a long but you've defined int TIOCGWINSZ = 0x40087468;. I think widening should happen automatically in Java but I'm not sure if this could be a problem? Can you try declaring it as a long?

Also you say you've validated the value in C, but according to this page the value is 0x5413. That seems to indicate it comes from an ffi library. I'm not very familiar with this, but is it possible you need to use a different constant with ffi that you do with native?

@Gieted
Copy link
Author

Gieted commented Oct 18, 2024

@dbwiddis LibC Constants can have different values for each platform, the best way to get correct value is to write a simple C program that prints it.

As I said in my last comment the issue seems to be with GraalVM (regular JIT, not the AOT compiled version). I'm not sure how JNA works after the hood, but it might be that GraalVM has more agrresive GC that frees the allocated memory before JNA call finishes.

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

No branches or pull requests

3 participants