Файловая система Fuse в java - ошибка JVM удваивается или повреждена

Я пишу Fuse-Filesystem в java, используя библиотеку jnr-fuse (https://github.com/SerCeMan/jnr-fuse), который внутренне использует JNR для собственного доступа.

Файловая система работает как внешний интерфейс для корзины Amazon S3, в основном позволяя пользователю монтировать свою корзину как обычное устройство хранения.

При переработке моего метода чтения я столкнулся со следующей ошибкой JVM:

*** Error in `/usr/local/bin/jdk1.8.0_65/bin/java': double free or corruption (!prev): 0x00007f3758953d80 ***

Ошибка всегда возникает при попытке скопировать файл из файловой системы fuse в локальную ФС, как правило, при втором вызове метода чтения (для второго блока данных размером 128 КБ).

 cp /tmp/fusetest/benchmark/benchmarkFile.large /tmp

Рассматриваемый метод чтения:

public int read(String path, Pointer buf, @size_t long size, @off_t long offset, FuseFileInfo fi) {
    LOGGER.debug("Reading file {}, offset = {}, read length = {}", path, offset, size);
    S3fsNodeInfo nodeInfo;
    try {
        nodeInfo = this.dbHelper.getNodeInfo(S3fsPath.fromUnixPath(path));
    } catch (FileNotFoundException ex) {
        LOGGER.error("Read called on non-existing node: {}", path);
        return -ErrorCodes.ENOENT();
    }
    try {
        // *** important part start
        InputStream is = this.s3Helper.getInputStream(nodeInfo.getPath(), offset, size);
        byte[] data = new byte[is.available()];
        int numRead = is.read(data, 0, (int) size);
        LOGGER.debug("Got {} bytes from stream, putting to buffer", numRead);
        buf.put(offset, data, 0, numRead);
        return numRead;
        // *** important part end
    } catch (IOException ex) {
        LOGGER.error("Error while reading file {}", path, ex);
        return -ErrorCodes.EIO();
    }
}

Используемый входной поток на самом деле представляет собой ByteArrayInputStream в буфере, который я использую для сокращения связи HTTP с S3. Сейчас я запускаю fuse в однопоточном режиме, чтобы избежать проблем, связанных с параллелизмом.

Интересно, что у меня уже была рабочая версия без внутреннего кэширования, но в остальном она была точно такой же, как показано здесь.

К сожалению, я не очень разбираюсь во внутренностях JVM, поэтому я не уверен, как разобраться в этом - обычная отладка ничего не дает, поскольку фактическая ошибка, похоже, происходит на конце C.

Вот полный консольный вывод операции чтения, запущенной приведенной выше командой:

2016-02-29 02:08:45,652 DEBUG s3fs.fs.CacheEnabledS3fs [main] - Reading file /benchmark/benchmarkFile.large, offset = 0, read length = 131072
unique: 7, opcode: READ (15), nodeid: 3, insize: 80, pid: 8297
read[0] 131072 bytes from 0 flags: 0x8000
2016-02-29 02:08:46,024 DEBUG s3fs.fs.CachedS3Helper [main] - Getting data from cache - path = /benchmark/benchmarkFile.large, offset = 0, length = 131072
2016-02-29 02:08:46,025 DEBUG s3fs.fs.CachedS3Helper [main] - Path /benchmark/benchmarkFile.large not yet in cache, add it
2016-02-29 02:08:57,178 DEBUG s3fs.fs.CachedS3Helper [main] - Path /benchmark/benchmarkFile.large found in cache!
   read[0] 131072 bytes from 0
   unique: 7, success, outsize: 131088
2016-02-29 02:08:57,179 DEBUG s3fs.fs.CachedS3Helper [main] - Starting actual cache read for path /benchmark/benchmarkFile.large
2016-02-29 02:08:57,179 DEBUG s3fs.fs.CachedS3Helper [main] - Reading data from cache block 0, blockOffset = 0, length = 131072
2016-02-29 02:08:57,179 DEBUG s3fs.fs.CacheEnabledS3fs [main] - Got 131072 bytes from stream, putting to buffer
2016-02-29 02:08:57,180 DEBUG s3fs.fs.CacheEnabledS3fs [main] - Reading file /benchmark/benchmarkFile.large, offset = 131072, read length = 131072
unique: 8, opcode: READ (15), nodeid: 3, insize: 80, pid: 8297
read[0] 131072 bytes from 131072 flags: 0x8000
2016-02-29 02:08:57,570 DEBUG s3fs.fs.CachedS3Helper [main] - Getting data from cache - path = /benchmark/benchmarkFile.large, offset = 131072, length = 131072
2016-02-29 02:08:57,570 DEBUG s3fs.fs.CachedS3Helper [main] - Path /benchmark/benchmarkFile.large found in cache!
2016-02-29 02:08:57,570 DEBUG s3fs.fs.CachedS3Helper [main] - Starting actual cache read for path /benchmark/benchmarkFile.large
2016-02-29 02:08:57,571 DEBUG s3fs.fs.CachedS3Helper [main] - Reading data from cache block 0, blockOffset = 131072, length = 131072
2016-02-29 02:08:57,571 DEBUG s3fs.fs.CacheEnabledS3fs [main] - Got 131072 bytes from stream, putting to buffer
   read[0] 131072 bytes from 131072
   unique: 8, success, outsize: 131088
*** Error in `/usr/local/bin/jdk1.8.0_65/bin/java': double free or corruption (!prev): 0x00007fcaa8b30c80 ***

person Michael Langowski    schedule 29.02.2016    source источник


Ответы (1)


Ладно, это была действительно глупая ошибка...

buf.put(offset, data, 0, numRead);

это конечно бред - переданный параметр смещения означает смещение в читаемом файле, а не в буфере.

Работает с:

buf.put(0, data, 0, numRead);

Довольно загадочная ошибка просто означает, что я пытаюсь записать области памяти, в которые мне не нужно писать в этом случае. Любопытно, однако, почему это сообщение об ошибке, а не segfault, который я обычно ожидаю здесь.

person Michael Langowski    schedule 29.02.2016
comment
Сообщение об ошибке предполагает, что память, которую вы топтаете, представляет собой кучу, структурированную как список блоков. Это правильно отображенная память, поэтому вы не получите segfault, но диспетчер кучи обнаружит, что вы перезаписали его метаданные, связанные с предыдущим блоком. - person Jeffrey Bosboom; 09.03.2016