[foreign-memaccess/abi] where do unsafe operations live

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Tue Oct 22 12:53:00 UTC 2019


On 22/10/2019 13:45, Jorn Vernee wrote:
> On 22/10/2019 14:14, Maurizio Cimadamore wrote:
>>
>> On 22/10/2019 12:49, Jorn Vernee wrote:
>>> This sounds like a decent idea, but I'm wondering if having the 
>>> class be named ForeignUnsafe isn't already enough of a deterrent? 
>>> The barrier of having a single `requires` in a module-info file 
>>> doesn't seem much higher? I think if we just take away the need for 
>>> --add-exports, then the barrier is already pretty low, and we need 
>>> to make sure users understand if they are interacting with a safe or 
>>> unsafe API. Maybe we could do something with an @UnsafeAPI 
>>> annotation here (which IDEs/javac could warn about)? Or some javadoc 
>>> note like "This api is _unsafe_. It's use could result in putting 
>>> the VM in an invalid state, leading possibly to VM crashes".
>>
>> I agree, but I think that moving the unsafe stuff in its own module 
>> is a precondition to what you describe. Note that a module will have 
>> its own javadoc, where we can document that users can depend on this 
>> at their own risk (and if the module is marked with some annotation, 
>> we could issue a mandatory warning when importing it).
>>
>> While ForeignUnsafe might be a scary name as it is, I believe that 
>> users should have an option to decide on which module they want to 
>> depend on. There has to be a way to say "give me only the safe stuff, 
>> please" and if I accidentally refer to the unsafe stuff, a compiler 
>> error should be issued. I think that's valuable to have.
> Wanting to get a warning is a fair use case. But, maybe a module for 4 
> methods (currently) is a bit overkill... I think to get a warning an 
> annotation would have the same effect? You'd get a warning unless you 
> suppress it. Plus you'd be able to put the methods "where they 
> belong", e.g. ofNull seems more at home on MemoryAddress itself. But, 
> having such an annotation might need a JEP of it's own?

This defo needs a JEP. I don't think a warning alone is enough of a bar.

Perhaps, error  by default and something like --enable-unsafe. But so 
that --enable-unsafe only needs to be specified by code actively using 
the unsafe API points, not by all the code transitively using it.

>>
>>>
>>> Also, it seems a given that calling native code is unsafe. After 
>>> all, anything can happen in native code. So, would all of SystemABI 
>>> be in the unsafe module as well? 
>> True - but calling JNI code can be considered equally unsafe.
>>> I think it would be more descriptive to have a separate 
>>> jdk.incubator.foreign.abi module in that case, which is documented 
>>> to contain unsafe APIs. Basically, I'm wondering if there exists a 
>>> more useful/descriptive classification than just "safe" <-> "unsafe" 
>>> for that particular case.
>>
>> I think there are two things happening here, for which the term 
>> unsafe might be used:
>>
>> - calling native code can result in pretty much anything. That is 
>> already the case with JNI and I don't think SystemABI is any worse 
>> than that. Since calling JNI methods doesn't require any particular 
>> dance, I'd be concerned if, to create a native method handle, we 
>> forced users through some unsafe conundrum (also note, if a client  
>> really want to protect against this, a security manager could guard 
>> library lookups and SystemABI calls)
>>
>> - creating a pointer out of thin air _without_ even invoking a native 
>> method is something fundamentally new. And it is also unsafe, since 
>> you can just use the memory access API to dereference it and crash 
>> bang the VM.
>>
>> So I don't think the two cases are created equal - at least not in 
>> the measure of how Java has always dealt with JNI.
> For _calling_ a `native` method, you don't need to do anything extra, 
> but the same applies with SystemABI, where you can just call the 
> returned MethodHandle.
>
> JNI requires a whole lot more ceremony to get going. You actually have 
> to go write and compile a C/C++ glue-code library. You have to leave 
> the safety of Java to get it working! For SystemABI we don't have to 
> leave Java, so maybe we should have some warning for users that start 
> linking native methods (e.g. it is possible to get the descriptors 
> wrong. Since that metadata is not typically available in a DLL, we can 
> not check if what the user passes is correct).
>
> I just think it's weird to have a line drawn between the safe | 
> unsafe, and have SystemABI seemingly be on the "safe" side of that 
> line. That's why I think that safe| unsafe might not be the best 
> classification for grouping APIs together. It seems that APIs should 
> be grouped into modules/packages based on their functionality. And the 
> safe/unsafe bits should be marked through some other means.

If we had a nimble(r) mechanism to define unsafe API points which is not 
a pain to developers I agree on all counts.

Maurizio

>
> Jorn
>
>>
>>>
>>> Jorn
>>>
>>> On 18/10/2019 19:44, Maurizio Cimadamore wrote:
>>>> Hi,
>>>> As I was using foreign-memaccess and foreign-abi in anger, it 
>>>> occurred to me that the current layout of the incubating module is 
>>>> a bit limiting in case the user wants to perform some unsafe 
>>>> operations.
>>>>
>>>> Right now, unsafe operations are defined in the class 
>>>> 'ForeignUnsafe' which lives in the (non-exported) 
>>>> jdk.incubating.foreign.unsafe package.
>>>>
>>>> Since the package is not exported, users that want to access unsafe 
>>>> stuff need to add a manual --add-exports option.
>>>>
>>>> This is fine, and, in fact, it was intended to have something that 
>>>> required an explicit opt-in, given that these are unsafe operations.
>>>>
>>>> That said, let's look at the situation from the perspective of a 
>>>> library writer: if I write a Java bindings, it is very likely that 
>>>> I might want to create MemoryAddress from longs, and the likes. But 
>>>> if I do that, I need to break into the jdk.incubating.foreign 
>>>> module, and _require that all my clients do the same_!
>>>>
>>>> I think this is excessively punitive. It's a good idea to have a 
>>>> sharp separation between "safe" and "unsafe" parts of the API - and 
>>>> it is also good if the "unsafe" parts of the API live in modules 
>>>> that are non-resolvable by default (e.g. you need to "require" them 
>>>> explicitly, or they won't be available).
>>>>
>>>> But if somebody is packaging a library in a module, it is kind of 
>>>> sad that there's no way for the library writer to depend on the 
>>>> 'unsafe' module, if he so wishes (and free the library clients from 
>>>> having to make this explicitly).
>>>>
>>>> All things considered, I think that a better structure would be to 
>>>> have _two_ modules:
>>>>
>>>> * jdk.incubating.foreign - usual, safe portion of the API
>>>> * jdk.incubating.foreign.unsafe - unsafe portion of the foreign API 
>>>> (requires jdk.incubating.foreign)
>>>>
>>>> This way, a library developer can just say "requires 
>>>> jdk.incubating.foreign.unsafe" and be done. The library clients 
>>>> will have to do nothing, assuming their module path is set up 
>>>> correctly.
>>>>
>>>> Thoughts?
>>>>
>>>> Maurizio
>>>>


More information about the panama-dev mailing list