Usage of global scope by Linker is unsafe for pointers to `static` data in loaded library

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Sep 23 11:50:54 UTC 2024


Filed:
https://bugs.openjdk.org/browse/JDK-8340641

Cheers
Maurizio

On 23/09/2024 10:47, Maurizio Cimadamore wrote:
>
> Hi,
> the problem you describe here is that the caller _knows_ (e.g. by 
> reading the API javadoc) that a pointer returned by a native library 
> call points to static data and has, therefore, the same lifetime as 
> the library itself.
>
> The linker cannot know this. The linker only sees a call that returns 
> a pointer - the pointer can have any size and any lifetime. It is up 
> to the caller to "sanitize" that call, by overriding the global 
> lifetime with a more appropriate one (e.g. the one used to load the 
> library). But there's no way for the Linker to "guess" - maybe the 
> native function does a malloc, and returns a pointer to it - the 
> lifetime could also be much smaller than that of the native library. 
> For this reason, changing the default downcall behavior is not an 
> option: while the interpretation you suggest might be ok for functions 
> returning data, it is certainly not ok for all the other functions.
>
> To override the lifetime, the MemorySegment::reinterpret method can be 
> used. It is true that reinterpret accepts and Arena, and I think your 
> main issue is that, at the point when the call is made, you don't have 
> this Arena. The reason as to why reinterpret wants an Arena and not a 
> Scope is explained here: 
> https://github.com/openjdk/panama-foreign/pull/812. The problem is 
> that we don't have a way (at least for now) to set the lifetime of a 
> memory segment w/o _also_ altering its thread confinement. That is, a 
> client might expect that setting a scope on a segment might leave all 
> the other segment properties unchanged, but that's not the case: the 
> segment confinement is also changed.
>
> As an alternative, we could also have a linker option to mark 
> downcalls that return pointers to static data (so that the downcall 
> will reassign the scope of the returned segment as you desire). While 
> this might be effective, if you don't control the creation of the 
> downcall method handle, it will not be a good/general solution (but 
> maybe it's enough?)
>
> Maurizio
>
>
>
>
>
>
>
> On 21/09/2024 16:54, 
> some-java-user-99206970363698485155 at vodafonemail.de wrote:
>>
>> Hello,
>>
>> as mentioned in the Javadoc, for downcalls and upcalls Linker uses 
>> the global scope for the result respectively the arguments. This is 
>> problematic for pointers to `static` data in C because it leads to 
>> unsafe code.
>> Specifically, consider this case:
>>
>>  1. Load a library using SymbolLookup
>>  2. Obtain the address of a function in that library
>>  3. Call that function using Linker; the function returns a pointer
>>     to `static` data
>>  4. Use the function result
>>
>> If I understand it correctly that pointer to the `static` data 
>> actually points within the data of the loaded library (and not some 
>> newly allocated heap memory). But I am not that familiar with C, so 
>> please correct me if I am wrong.
>>
>> The problem is now if you accidentally unload the library by closing 
>> the Arena which was used for loading it, either explicitly or by the 
>> garbage collector in case of Arena.ofAuto(), while the function 
>> result is still is use.
>> Because the Linker used the global scope, if you use the `static` 
>> data returned by the function it will crash the JVM because it is not 
>> detected that the original Arena had been closed, and the library had 
>> been unloaded.
>>
>>
>> What makes this worse is that if you are just given a SymbolLookup, 
>> or even a MemorySegment obtained from it, you don't have access to 
>> the original Arena used to load the library, so you cannot even 
>> manually fix this unsafety this by using `MemorySegment#reinterpet` 
>> to change the Arena.
>>
>>
>> Maybe it would therefore be safer if Linker for downcalls used the 
>> scope of the given function pointer MemorySegment, instead of the 
>> global scope. What do you think?
>> For upcall arguments I am not sure if there is a way to fix this 
>> unsafety.
>>
>>
>> If the behavior for downcalls cannot be changed, could you then 
>> please at least add a 'restricted' `MemorySegment#withScope(Scope)` 
>> (maybe with additional 'cleanup' argument) or similar, so that you 
>> can manually change the scope of the downcall result, without needing 
>> a reference to the original Arena (which is currently required for 
>> `MemorySegment#reinterpet`)?
>> Though personally I would prefer if the default downcall behavior was 
>> changed, because manually having to change the scope of the downcall 
>> result every time is error-prone and easy to forget.
>>
>>
>> Kind regards 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20240923/aa8a05fd/attachment.htm>


More information about the panama-dev mailing list