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

C int to java Boolean convertion for >1 values #123

Open
goto1134 opened this issue Jun 2, 2017 · 12 comments · May be fixed by #138
Open

C int to java Boolean convertion for >1 values #123

goto1134 opened this issue Jun 2, 2017 · 12 comments · May be fixed by #138

Comments

@goto1134
Copy link
Contributor

goto1134 commented Jun 2, 2017

I tried to use predicate

int isalnum ( int c );

It checks whether c is either a decimal digit or an uppercase or lowercase letter. It returns different values for different types, 1 for uppercase, 2 for lowercase, 3 for digit.

As soon as it as a predicate, I would like to declare boolean result for it, but if I do so, the predicate returns true only for uppercase letters.

I think, the boolean convertion from native should be changed.

@headius
Copy link
Member

headius commented Jun 6, 2017

So you are proposing that specifying boolean as the type should do conversion based on the C standard: nonzero is true?

It seems reasonable to me, though in similar cases in the other jnr libraries, we've eventually had to add the int version.

Note that we haven't added these to jnr-posix because there are Java equivalents that behave mostly the same, but do produce boolean values.

@headius
Copy link
Member

headius commented Jun 6, 2017

So poking around to see where this conversion happens I found two locations:

https://github.com/jnr/jnr-ffi/blob/master/src/main/java/jnr/ffi/provider/jffi/DefaultInvokerFactory.java#L509

This looks like the default boolean invoker logic, but it uses != 0 to indicate true, which doesn't seem to match what you're seeing.

https://github.com/jnr/jnr-ffi/blob/master/src/main/java/jnr/ffi/provider/jffi/DefaultInvokerFactory.java#L867

This has the logic you're seeing (!= 1 is false) but as far as my IDE can tell it's not used.

I'm going to step debug and figure out what's up.

@headius
Copy link
Member

headius commented Jun 6, 2017

Hmmm...I wrote a test to see if I could find this behavior, but my test passes as written:

    @Test public void testBooleanFromInt() throws Exception {
        assertEquals(false, testboolean.ret_int32_t(0));
        assertEquals(true, testboolean.ret_int32_t(-1));
        assertEquals(true, testboolean.ret_int32_t(1));
        assertEquals(true, testboolean.ret_int32_t(2));
    }

I will push this test to master and see if there's some behavioral difference on Linux versus OS X.

@headius
Copy link
Member

headius commented Jun 6, 2017

@headius
Copy link
Member

headius commented Jun 6, 2017

@goto1134 Can you provide an example, perhaps via a small git repo, that demonstrates your issue? I expected my test case to fail but it appears to have passed on both OS X and Linux.

@goto1134
Copy link
Contributor Author

goto1134 commented Jun 6, 2017

@headius look at https://github.com/goto1134/jnr-std-c-test . There are CharTypeIntTest and CharTypeBooleanTest. You'll need windows machine to run this.

@goto1134
Copy link
Contributor Author

@headius
I ran tests on my Windows x64 computer and here are results:

image

@goto1134
Copy link
Contributor Author

@headius Do you have any idea about what could go wrong?

@goto1134
Copy link
Contributor Author

UPD: test works with jnr.ffi.asm.enabled=false, but failes when using AsmLibraryLoader

@goto1134
Copy link
Contributor Author

Here is compile dump for loading testBoolean library:

// class version 50.0 (50)
// access flags 0x11
public final class jnr/ffi/NumberTest$TestBoolean$jnr$ffi$0 extends jnr/ffi/provider/jffi/AbstractAsmLibraryInterface  implements jnr/ffi/NumberTest$TestBoolean  {


  // access flags 0x12
  private final Lcom/kenai/jffi/CallContext; callContext_1

  // access flags 0x12
  private final J functionAddress_1

  // access flags 0x11
  public final ret_int32_t(I)Z
    GETSTATIC jnr/ffi/provider/jffi/AbstractAsmLibraryInterface.ffi : Lcom/kenai/jffi/Invoker;
    ALOAD 0
    GETFIELD jnr/ffi/NumberTest$TestBoolean$jnr$ffi$0.callContext_1 : Lcom/kenai/jffi/CallContext;
    ALOAD 0
    GETFIELD jnr/ffi/NumberTest$TestBoolean$jnr$ffi$0.functionAddress_1 : J
    ALOAD 0
    GETFIELD jnr/ffi/NumberTest$TestBoolean$jnr$ffi$0.callContext_1 : Lcom/kenai/jffi/CallContext;
    INVOKESTATIC jnr/ffi/provider/jffi/AsmRuntime.newHeapInvocationBuffer (Lcom/kenai/jffi/CallContext;)Lcom/kenai/jffi/HeapInvocationBuffer;
    DUP
    ILOAD 1
    INVOKEVIRTUAL com/kenai/jffi/HeapInvocationBuffer.putInt (I)V
    INVOKEVIRTUAL com/kenai/jffi/Invoker.invokeInt (Lcom/kenai/jffi/CallContext;JLcom/kenai/jffi/HeapInvocationBuffer;)I
    ICONST_1
    IAND
    IRETURN
    MAXSTACK = 7
    MAXLOCALS = 2

  // access flags 0x1
  public <init>(Ljnr/ffi/Runtime;Ljnr/ffi/provider/jffi/NativeLibrary;[Ljava/lang/Object;)V
    ALOAD 0
    ALOAD 1
    ALOAD 2
    INVOKESPECIAL jnr/ffi/provider/jffi/AbstractAsmLibraryInterface.<init> (Ljnr/ffi/Runtime;Ljnr/ffi/provider/jffi/NativeLibrary;)V
    ALOAD 0
    ALOAD 3
    ICONST_0
    AALOAD
    CHECKCAST com/kenai/jffi/CallContext
    PUTFIELD jnr/ffi/NumberTest$TestBoolean$jnr$ffi$0.callContext_1 : Lcom/kenai/jffi/CallContext;
    ALOAD 0
    ALOAD 3
    ICONST_1
    AALOAD
    CHECKCAST java/lang/Long
    INVOKEVIRTUAL java/lang/Long.longValue ()J
    PUTFIELD jnr/ffi/NumberTest$TestBoolean$jnr$ffi$0.functionAddress_1 : J
    RETURN
    MAXSTACK = 3
    MAXLOCALS = 4
}

@goto1134
Copy link
Contributor Author

As I see, the problem is here

    INVOKEVIRTUAL com/kenai/jffi/HeapInvocationBuffer.putInt (I)V
    INVOKEVIRTUAL com/kenai/jffi/Invoker.invokeInt (Lcom/kenai/jffi/CallContext;JLcom/kenai/jffi/HeapInvocationBuffer;)I
    ICONST_1
    IAND
    IRETURN

Constant 1 is pushed on the stack and then bitwise AND operation is performed with function value and 0x1.

@goto1134 goto1134 linked a pull request Aug 25, 2017 that will close this issue
@aploese
Copy link
Contributor

aploese commented Dec 4, 2018

@goto1134 Can you provide an example, perhaps via a small git repo, that demonstrates your issue? I expected my test case to fail but it appears to have passed on both OS X and Linux.

Its happen on the linux arm platform.
You can force it on linux by using the DummyStubCompiler in jnr/ffi/provider/jffi/StubCompiler.java
here is the diff:
`diff --git a/src/main/java/jnr/ffi/provider/jffi/StubCompiler.java b/src/main/java/jnr/ffi/provider/jffi/StubCompiler.java
index 7edcfdf7..fc57bba5 100644
--- a/src/main/java/jnr/ffi/provider/jffi/StubCompiler.java
+++ b/src/main/java/jnr/ffi/provider/jffi/StubCompiler.java
@@ -47,7 +47,9 @@ abstract class StubCompiler {
break;
case X86_64:
if (Platform.getPlatform().getOS() != Platform.OS.WINDOWS) {

  •                    return new X86_64StubCompiler(runtime);        //currently supporting only A64
    
  •    return new DummyStubCompiler();
    
  •    //TODO set real stub compiler
    

+// return new X86_64StubCompiler(runtime); //currently supporting only A64
}
break;
case AARCH64:
@@ -114,8 +116,8 @@ abstract class StubCompiler {
new Assembler(CPU.X86_32);
return true;
case X86_64:

  •                new Assembler(CPU.X86_64);
    
  •                return true;
    
  •                //TODO + return true new Assembler(CPU.X86_64);
    
  •                return false;
               case AARCH64:
                   new Assembler_A64(CPU_A64.A64);
                   return true;
    

`
in NumberUtils.java look for comment: Ensure only 0x0 and 0x1 values are used for boolean too...

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 a pull request may close this issue.

3 participants