JDK-6934977 : (bf) MappedByteBuffer.load can SIGBUS if file is truncated
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 7
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2010-03-15
  • Updated: 2011-03-08
  • Resolved: 2011-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b105Fixed
Related Reports
Relates :  
Relates :  
Description
OPERATING SYSTEM
----------------
Linux

LICENSEE PROBLEM DESCRIPTION
-------------------
The problem described by CR 6244515 ("Unsafe operations that access invalid memory are not handled gracefully") is not resolved on Linux, contrary to the information in that CR.

A simple testcase is provided below, which does the following:

1. Create a test file
2. Open a FileChannel to the test file
3. Create a MappedByteBuffer from the FileChannel
4. Attempt to truncate the file via FileChannel.truncate()
5. Attempt to call load() on the MappedByteBuffer created in step 3

The situation presented by the testcase is handled gracefully on Solaris and Windows, but causes a crash on Linux (which is very similar to the crash observed on Solaris
with the 5.0 JDK).

Note that this does not appear to be a regression, as the problem is reproducible on Linux with ALL Java 6 SDKs. In fact it seems that the issue was never fixed properly. The problem is also seen with Java 7 (tested b69).

Here are the results on Windows, Solaris and Linux, all with 1.6.0_16:

Windows
-------
Creating test file...done
Creating mapped buffer from test file...done
Attempting to truncate the file...Exception in thread "main" java.io.IOException: The requested operation cannot be performed on a file with a user-mapped section open
        at sun.nio.ch.FileChannelImpl.truncate0(Native Method)
        at sun.nio.ch.FileChannelImpl.truncate(FileChannelImpl.java:338)
        at TruncateTest.main(TruncateTest.java:22)

Solaris
-------
Creating test file...done
Creating mapped buffer from test file...done
Attempting to truncate the file...done
Attempting to load mapped buffer...Exception in thread "main" java.io.IOException: Bad address
        at java.nio.MappedByteBuffer.load0(Native Method)
        at java.nio.MappedByteBuffer.load(MappedByteBuffer.java:127)
        at TruncateTest.main(TruncateTest.java:26)

Linux
-----
Creating test file...done
Creating mapped buffer from test file...done
Attempting to truncate the file...done
Attempting to load mapped buffer...
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGBUS (0x7) at pc=0xb53257f0, pid=13023, tid=3075017616
#
# JRE version: 6.0_16-b01
# Java VM: Java HotSpot(TM) Client VM (14.2-b01 mixed mode linux-x86 )
# Problematic frame:
# C  [libnio.so+0x47f0]  Java_java_nio_MappedByteBuffer_load0+0x70
#
# An error report file with more information is saved as:
# /home/xxxxxxxx/test/hs_err_pid13023.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Aborted

TESTCASE SOURCE
---------------
import java.nio.*;
import java.io.*;
import java.nio.channels.*;

public class TruncateTest {
    public static void main(String args[]) throws IOException {

        // Write a test file
        System.out.print("Creating test file...");
        BufferedWriter out = new BufferedWriter(new FileWriter("testfile"));
        for (int i=0; i<1000; i++) {
           out.write("This is a test file. ");
        }
        System.out.println("done");

        // Map the file
        System.out.print("Creating mapped buffer from test file...");
        FileChannel fc = new java.io.RandomAccessFile("testfile", "rw").getChannel();
        MappedByteBuffer buf = fc.map(FileChannel.MapMode.READ_WRITE, 0L, fc.size());
        System.out.println("done");

        // Truncate the file
        System.out.print("Attempting to truncate the file...");
        fc.truncate(512);
        System.out.println("done");

        // Now try to load from the MappedByteBuffer
        System.out.println("Attempting to load mapped buffer...");
        buf.load();
        System.out.println("done");
    }
}

Comments
EVALUATION The issue here is that the load method is touching each page in a native method rather rather than using the Unsafe API. This means the sig handler doesn't know to unwind the stack.
16-03-2010