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

Я пишу файловую систему Fuse в 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 в локальную FS, как правило, при втором вызове метода read (для второго блока данных 128kByte)

 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 ***

1 ответ

Решение

Хорошо, это была глупая ошибка на самом деле...

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

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

Работает с:

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

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

Другие вопросы по тегам