FFM API: questions about reinterpret and MemorySegment
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Wed Oct 2 10:11:10 UTC 2024
Hi, some replies below:
On 01/10/2024 20:40, Anastasiya Lisitskaya wrote:
> Hi,
>
> I'm trying to use the FFM API (jdk 22) to call my C++ method and I
> need to pass a text(java String) and receive a text response. While
> implementing this, I encountered several issues:
>
> 1.
>
> What are the best practices for defining |newSize| for use in the
> |reinterpret(long newSize)| method? Can I use constants like
> |Long.MAX_VALUE| or |Integer.MAX_VALUE| as |newSize|, or could
> that cause some problems?
>
If the size of the returned string (I assume it's a char*) is known,
then use that size. Otherwise, use Long.MAX_VALUE.
MemorySegment::getString will read the string bytes up to the null
terminator.
> 1.
>
> When I tried to use in-heap |MemorySegment| with the
> |Linker.Option.critical(true)| and passed
> |MemorySegment.ofArray(text.getBytes())|, I started getting extra
> symbol like SOH in the response. What am I doing wrong? (Sample
> snippets listed below). Changing newSize value in reinterpret(long
> newSize) doesn't help
>
> 1.
> If I inline MemorySegment.ofArray(text.getBytes()) into
> invokeExact, I expected : "мое все 123 аи92", but got:
>
> uncaught exception:
> address -> 0x60000120d710
> what() -> "util/charset/wide.h:366: failed to decode UTF-8
> string at pos 25 in string "\xD0\x9C\xD0\xBE\xD1\x91
> \xD0\xB2\xD1\x81\xD1\x91 123 \xD0\x90\xD0\23092\1\xCF\xFD\xBD_""
> type -> yexception
>
> I'm definitely doing something wrong. Please help me figure it out and
> understand. Thanks!
I think your problem is that the segment you are creating has no NULL
terminator in the end?
E.g. you take a Java string, get its byte array, and turn the byte array
into a segment.
To work with string safely, I suggest you use String-accepting
allocation/accessor methods. Either Arena::allocateFrom(String), or
MemorySegment::setString. Those will add the required terminator.
I think even your first example looks incorrect (where you use
`allocateFrom(JAVA_BYTE, text.getBytes()`), but you are probably saved
there by the fact that malloc allocated a bigger chunk of memory and a
zero just happens to be at the end of the string bytes?
You can't pass the byte array of a Java string to a C/C++ function
expecting a null-terminated string w/o performing some sort of copy and
adding the required trailing terminator. Some C/C++ APIs might work with
unterminated strings, in which case they will probably accept a size -
e.g. how many characters are expected in the char*. But this doesn't
seem to be the case here.
Hope this helps
Maurizio
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20241002/904006d3/attachment-0001.htm>
More information about the panama-dev
mailing list