zero-length segments

Michael Zucchi notzed at gmail.com
Thu Jan 20 22:50:28 UTC 2022


Morning all,

After a long break i've started experimenting with the foreign abi to 
replace jni.  One tool i'm working on is a vulkan binding generator that 
works directly from the xml specification and generates a 'nice' api 
(particularly focusing on constructors for all the hundreds of 
configuration structures needed for vulkan, plus the dynamic function 
tables), and another tool generates high-level and potentially object 
oriented api's from c header files, for this one I use a gcc plugin to 
extract the structures and functions and i'm trying opencl and ffmpeg as 
test cases (and to update some projects i maintain, zcl and jjmpeg).  
I'm not using jextract because I want to create the high level api 
directly and provide much more control on the created classes, and also 
because i've got the time and nothing better to do with it.

In general it looks pretty good after so much work, but i've come across 
one oddity which adds complexity to the java code for no obvious 
reason.  Is there any specific reason you cannot create zero length 
memory segments *in some cases*?

e.g. something like this comes up often in C:

struct blob {
    size_t data_size;
    uint8_t *data;
}

 From java at some point you want to get a MemorySegment to access 
blob.data.  It might be through a high level api such as:

   class blob {
     MemorySegment getData() {
         return MemorySegment.ofAddress(...);
     }
  }

If the memory was allocated in the native code (quite common) this 
obvious java-side implementation just isn't possible with the current 
MemorySegment implementation as it will fail in an unexpected (and imho 
unreasonable) way if size is 0.  You'd either need to wrap MemorySegment 
in some other structure which hides this detail with it's own special 
case code (seems redundant), return a null (apparently evil these days, 
and kinda messy anyway), or expose the detail by ensuring the callee 
checks size>0 before calling getData() (yikes).

One notes that it is inconsistent with the rest of the api:

works: 
segmentAllocator.allocate(MemoryLayout.structLayout().withBitAlignment(8))
works:  segmentAllocator.allocateArray(JAVA_BYTE, 0);
works: segmentAllocator.allocate(0);
works:  segment.asSlice(offset, 0);
works: MemorySegment.ofArray(new byte[0]);
works: MemorySegment.ofByteBuffer(ByteBuffer.allocateDirect(0));
(you get the idea ...)

doesn't: 
MemorySegment.allocateNative(MemoryLayout.structLayout().withBitAlignment(8), 
scope);
doesn't: MemorySegment.allocateNative(0, 1, scope);
doesn't: MemorySegment.ofAddress(addr, 0, scope);

With the last one being the only way to wrap sized-allocations from 
native memory(?)  there seems to be no workaround possible.

Both java and c specifically define zero-length allocations as valid 
everywhere else because it simplifies a lot of code, and even the 
foreign-abi does for every other case, so why not here too?

Cheers,
  Z


More information about the panama-dev mailing list