javacffijnr

JNR-FFI crash after calling c function copying struct


I am trying to interface with a C library libzbc using jnr-ffi. The first function call zbc_open works and returns a pointer to a open device. Then the next call to zbc_get_device_info causes a JVM crash.

What is the cause? How to solve it? I think the error is somewhere in the interface of zbc or my passing parameters but searching for any documentation for JNR yielded no helpful results in google.The crash happens too if i omit the array part in the structure.

I am using the project of jnr-fuse as a starting point because my goal is to write a FUSE filesystem.

Crash log at pastebin

C functions:

void zbc_set_log_level( char *log_level )   
int zbc_open (const char *filename, int flags, struct zbc_device **dev)
void zbc_get_device_info( struct zbc_device *dev, struct zbc_device_info * info)    

C structure zbc_device_info:

enum zbc_dev_type   zbd_type
enum zbc_dev_model  zbd_model
char    zbd_vendor_id [ZBC_DEVICE_INFO_LENGTH]
uint32_t    zbd_flags
uint64_t    zbd_sectors
uint32_t    zbd_lblock_size
uint64_t    zbd_lblocks
uint32_t    zbd_pblock_size
uint64_t    zbd_pblocks
uint64_t    zbd_max_rw_sectors
uint32_t    zbd_opt_nr_open_seq_pref
uint32_t    zbd_opt_nr_non_seq_write_seq_pref
uint32_t    zbd_max_nr_open_seq_req

JNR interface:

public interface zbc{
        public void zbc_set_log_level(String level);
        public int zbc_open(String filename,int flags, PointerByReference p);
        public void zbc_get_device_info(Pointer dev,zbc_device_info info);
    }

public static class zbc_device_info extends Struct {
    int zbd_type;
    int zbd_model;
    byte zbd_vendor_id[]=new byte[32];
    u_int32_t zbd_flags;
    u_int64_t zbd_sectors;
    u_int32_t zbd_lblock_size;
    u_int64_t zbd_lblocks;
    u_int32_t zbd_pblock_size;
    u_int64_t zbd_pblocks;
    u_int64_t zbd_max_rw_sectors;
    u_int32_t zbd_opt_nr_open_seq_pref;
    u_int32_t zbd_opt_nr_non_seq_write_seq_pref;
    u_int32_t zbd_max_nr_open_seq_pref;

    protected zbc_device_info(Runtime runtime) {
        super(runtime);

    }

}

The main function:

public static void main(String[] args) {
    zbc z = LibraryLoader.create(zbc.class).load("zbc");
    Runtime runtime=Runtime.getRuntime(z);

    z.zbc_set_log_level("debug");
    PointerByReference pr = new PointerByReference();
    int ret=z.zbc_open("/temp/test.img", IO_RDWR,pr);
    zbc_device_info info=new zbc_device_info(runtime);

    z.zbc_get_device_info(pr.getValue(),info);
}

JVM crash:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fa794300c70, pid=29106, tid=0x00007fa7bd4a4700
#
# JRE version: OpenJDK Runtime Environment (8.0_131-b11) (build 1.8.0_131-8u131-b11-2ubuntu1.16.04.3-b11)
# Java VM: OpenJDK 64-Bit Server VM (25.131-b11 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [jffi6917022509387828651.so+0x5c70]  jffi_releaseArrays+0x60
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/mmmm/jnr-fuse/hs_err_pid29106.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

Solution

  • The declaration of Struct is incorrect. The fields are not declared. Try to use the following declaration:

    package com.github.goto1134.libzbc;
    
    import jnr.ffi.Runtime;
    import jnr.ffi.Struct;
    import jnr.ffi.util.EnumMapper.IntegerEnum;
    
    public class zbc_device_info
            extends Struct {
        public static final int ZBC_DEVICE_INFO_LENGTH = 32;
    
    
        public final Enum<zbc_dev_type> zbd_type = new Enum<>(zbc_dev_type.class);
        public final Enum<zbc_dev_model> zbd_model = new Enum<>(zbc_dev_model.class);
        public final UTF8String zbd_vendor_id = new UTF8String(ZBC_DEVICE_INFO_LENGTH);
        public final Unsigned32 zbd_flags = new Unsigned32();
        public final Unsigned64 zbd_sectors = new Unsigned64();
        public final Unsigned32 zbd_lblock_size = new Unsigned32();
        public final Unsigned64 zbd_lblocks = new Unsigned64();
        public final Unsigned32 zbd_pblock_size = new Unsigned32();
        public final Unsigned64 zbd_pblocks = new Unsigned64();
        public final Unsigned64 zbd_max_rw_sectors = new Unsigned64();
        public final Unsigned32 zbd_opt_nr_open_seq_pref = new Unsigned32();
        public final Unsigned32 zbd_opt_nr_non_seq_write_seq_pref = new Unsigned32();
        public final Unsigned32 zbd_max_nr_open_seq_req = new Unsigned32();
    
    
        protected zbc_device_info(Runtime runtime) {
            super(runtime);
        }
    
        public enum zbc_dev_type
                implements IntegerEnum {
    
            /**
             * Unknown drive type.
             */
            ZBC_DT_UNKNOWN(0x00),
    
            /**
             * Zoned block device (for kernels supporting ZBC/ZAC).
             */
            ZBC_DT_BLOCK(0x01),
    
            /**
             * SCSI device.
             */
            ZBC_DT_SCSI(0x02),
    
            /**
             * ATA device.
             */
            ZBC_DT_ATA(0x03),
    
            /**
             * Fake device (emulation mode).
             */
            ZBC_DT_FAKE(0x04);
    
            private final int value;
    
            zbc_dev_type(int value) {
    
                this.value = value;
            }
    
            @Override
            public int intValue() {
                return value;
            }
        }
    
        public enum zbc_dev_model
                implements IntegerEnum {
    
            /**
             * Unknown drive model.
             */
            ZBC_DM_DRIVE_UNKNOWN(0x00),
    
            /**
             * Host-aware drive model: the device type/signature is 0x00
             * and the ZONED field of the block device characteristics VPD
             * page B1h is 01b.
             */
            ZBC_DM_HOST_AWARE(0x01),
    
            /**
             * Host-managed drive model: the device type/signature is 0x14/0xabcd.
             */
            ZBC_DM_HOST_MANAGED(0x02),
    
            /**
             * Drive-managed drive model: the device type/signature is 0x00
             * and the ZONED field of the block device characteristics VPD
             * page B1h is 10b.
             */
            ZBC_DM_DEVICE_MANAGED(0x03),
    
            /**
             * Standard block device: the device type/signature is 0x00
             * and the ZONED field of the block device characteristics VPD
             * page B1h is 00b.
             */
            ZBC_DM_STANDARD(0x04);
    
            private final int value;
    
            zbc_dev_model(int value) {
    
                this.value = value;
            }
    
            @Override
            public int intValue() {
                return value;
            }
        }
    }
    

    In hs logs there is a call stack that made the program crash. Can you provide it?