[foreign] Improve error reporting when Java signature and native function layout don't match.
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Wed Sep 26 14:42:44 UTC 2018
I'll start the paperwork for [1]. I'll probably change it slightly to
still use a constructor, so that there are less clashes with the ongoing
direct invoker patch which also touches the same area. But what you did
was sensible of course.
Regarding the other suggestions:
1) that looks sensible; right now we return a nullPointer() which as a
References.ofVoid, so that's why you get the UOE. We could create a
References.ofNull to be used specifically for nullPointer()
2) Yes, I'm aware of this issue; I think at this stage we don't want to
make metadata changes - for when we will ready to rediscuss metadata
again (soon!) I think we need to go for a more radical change here, as I
don't think that pushing all symbol declarations on a toplevel
annotation is helpful here. So stay tuned for more. Also, I have the
feeling that now that the parser has improved, we could tackle this
usability issue in another way - that is, by parsing the following grammar:
declarations ::= declaration [declarations]
declaration ::= symbolName '=' layout |
symbolName '=' function
symbolName ::= Ident
In the past, when I tried to do this I faced issues with the scanner
sometimes consuming token I didn't want, but then I completely revamped
the code for parsing annotations (and other productions too), and this
might improve things. It might be worth another try.
Thanks
Maurizio
On 25/09/18 19:33, Jorn Vernee wrote:
> Hi Maurizio,
> Thanks for looking at the patch.
>
> I have made the check simpler as you suggested [1]. Doing carrier <->
> layout checks in LayoutType makes sense to me.
>
> If you appreciate this kind of contribution I had 2 more things I ran
> into;
>
> 1.) When a native function returns `null`, it seems that this value is
> always boxed using `References#ofVoid`, and when you de-reference it
> you get an UOE without a message. I'm not sure if boxing as Void is
> intentional, but either way it would be nice if it gave a reason like
> 'can not de-reference null pointer'.
>
> 2.) The way NativeHeader#declarations is parsed makes it so that a
> faulty layout string like `exit(i32)v` (should be `exit=(i32)v`) is
> silently ignored, and you get an AbstractMethodError when invoking the
> method. Part of the problem I think, is that the parser splits the
> declarations string by `=`, and then goes from there. I'm thinking a
> more robust approach would be to make NativeHeader#declarations a
> String[] instead of a String, and then try to parse exactly 1
> declaration for each element. What do you think?
>
> I could try and make patches for those later this week.
>
> Jorn
>
> [1] : https://gist.github.com/JornVernee/2fb68d70bad1aa807b50b77840117b27
>
> Maurizio Cimadamore schreef op 2018-09-25 18:43:
>> Hi Jorn,
>> your patch looks good, but I think I would like it to just limit
>> things at a basic arity check (and void vs. non void check) in the
>> function. Given how we treat native types (layout + carrier), how
>> carriers are assigned to layouts is up to the method signature - if
>> somebody really wants to see a pointer as a float, so be it, although
>> I agree it looks silly.
>>
>> More generally, I think that if we go down the path of enforcing more
>> checks, we probably want to enforce carrier vs. layout compatibility
>> in a different place - that is LayoutType. That is the natural place
>> where to rule out ill-formed combinations.
>>
>> So there are two checks here: one is the one you needed, which checks
>> that a method signature is compatible with its function layout (same
>> arity, same varargness, same kind of return). The other is a more in
>> depth check performed on LayoutType, which I think is rather
>> orthogonal w.r.t. former. I'd suggest to go ahead with the first.
>>
>> Makes sense?
>>
>> Maurizio
>>
>>
>>
>> On 25/09/18 14:27, Jorn Vernee wrote:
>>> Hello,
>>>
>>> Thanks for accepting my last contribution!
>>>
>>> During testing I was running into an exception like this:
>>>
>>> Exception in thread "main"
>>> java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for
>>> length 0
>>> at
>>> java.base/jdk.internal.foreign.NativeInvoker.invokeNormal(NativeInvoker.java:216)
>>> at
>>> java.base/jdk.internal.foreign.NativeInvoker.invoke(NativeInvoker.java:200)
>>> at
>>> com.github.jdnl.Main$MyLib$Impl/0x000000010009c440.exit(Unknown Source)
>>> at com.github.jdnl.Main.main(Main.java:17)
>>>
>>> The cause turned out to be a mismatch between the Java method
>>> signature and the native function layout:
>>>
>>> @NativeHeader(declarations =
>>> "exit=()v" // missing param
>>> )
>>> interface MyLib {
>>> void exit(int code);
>>> }
>>>
>>> Since this exception is pretty cryptic, I'd like to contribute a
>>> patch that adds an explicit check for this to NativeInvoker, which
>>> does some basic verification that the two signatures match. With the
>>> patch I get this error instead (note the last 'Caused by'):
>>>
>>> Exception in thread "main" java.lang.RuntimeException: Failed to
>>> generate implementation for class interface com.github.jdnl.Main$MyLib
>>> at
>>> java.base/jdk.internal.foreign.LibrariesHelper.generateImpl(LibrariesHelper.java:65)
>>> at
>>> java.base/jdk.internal.foreign.LibrariesHelper$3.computeValue(LibrariesHelper.java:132)
>>> at
>>> java.base/jdk.internal.foreign.LibrariesHelper$3.computeValue(LibrariesHelper.java:124)
>>> at
>>> java.base/java.lang.ClassValue.getFromHashMap(ClassValue.java:226)
>>> at
>>> java.base/java.lang.ClassValue.getFromBackup(ClassValue.java:208)
>>> at java.base/java.lang.ClassValue.get(ClassValue.java:114)
>>> at
>>> java.base/jdk.internal.foreign.LibrariesHelper.getHeaderImplClass(LibrariesHelper.java:155)
>>> at
>>> java.base/jdk.internal.foreign.LibrariesHelper.bind(LibrariesHelper.java:241)
>>> at
>>> java.base/jdk.internal.foreign.LibrariesHelper.bind(LibrariesHelper.java:260)
>>> at java.base/java.foreign.Libraries.bind(Libraries.java:61)
>>> at com.github.jdnl.Main.main(Main.java:17)
>>> Caused by: java.lang.RuntimeException: Failed to generate method
>>> public abstract void com.github.jdnl.Main$MyLib.exit(int)
>>> at
>>> java.base/jdk.internal.foreign.BinderClassGenerator.generateMembers(BinderClassGenerator.java:153)
>>> at
>>> java.base/jdk.internal.foreign.HeaderImplGenerator.generateMembers(HeaderImplGenerator.java:103)
>>> at
>>> java.base/jdk.internal.foreign.BinderClassGenerator.generate(BinderClassGenerator.java:103)
>>> at
>>> java.base/jdk.internal.foreign.LibrariesHelper.lambda$generateImpl$0(LibrariesHelper.java:62)
>>> at java.base/java.security.AccessController.doPrivileged(Native
>>> Method)
>>> at
>>> java.base/jdk.internal.foreign.LibrariesHelper.generateImpl(LibrariesHelper.java:61)
>>> ... 10 more
>>> Caused by: java.lang.IllegalArgumentException: Java method
>>> signature and native layout not compatible: public abstract void
>>> com.github.jdnl.Main$MyLib.exit(int) : ()v
>>> at
>>> java.base/jdk.internal.foreign.NativeInvoker.of(NativeInvoker.java:127)
>>> at
>>> java.base/jdk.internal.foreign.HeaderImplGenerator.generateFunctionMethod(HeaderImplGenerator.java:130)
>>> at
>>> java.base/jdk.internal.foreign.HeaderImplGenerator.generateMethodImplementation(HeaderImplGenerator.java:121)
>>> at
>>> java.base/jdk.internal.foreign.BinderClassGenerator.generateMembers(BinderClassGenerator.java:150)
>>> ... 15 more
>>>
>>> And it is thrown when binding the interface, while the original
>>> exception was thrown when invoking the method.
>>>
>>> I have kept the implementation fairly permissive, so things like
>>> binding `void m(Pointer<?> p)` to `(u64)v` (converting a pointer to
>>> an integer) should still be allowed, but maybe a stricter approach
>>> is preferable? I have added a test to verify that it catches some
>>> basic mistakes like missing parameters or return types.
>>>
>>> Diff:
>>> https://gist.github.com/JornVernee/2fb68d70bad1aa807b50b77840117b27
>>>
>>> I saw an RFR and JBS bug was made for my last contribution (thanks
>>> Sundar!), so I've not added 'RFR' to the subject line this time.
>>>
>>> Regards,
>>> Jorn
More information about the panama-dev
mailing list