提交 8dc88011 编写于 作者: A alanb

6934977: (bf) MappedByteBuffer.load can SIGBUS if file is truncated

6799037: (fs) MappedByteBuffer.load crash with unaligned file-mapping (sol)
Reviewed-by: chegar, forax
上级 7408cbaa
......@@ -596,6 +596,9 @@ class Bits { // package-private
return pageSize;
}
static int pageCount(long size) {
return (int)(size + (long)pageSize() - 1L) / pageSize();
}
private static boolean unaligned;
private static boolean unalignedKnown = false;
......
......@@ -25,6 +25,8 @@
package java.nio;
import sun.misc.Unsafe;
/**
* A direct byte buffer whose content is a memory-mapped region of a file.
......@@ -93,6 +95,22 @@ public abstract class MappedByteBuffer
throw new UnsupportedOperationException();
}
// Returns the distance (in bytes) of the buffer from the page aligned address
// of the mapping. Computed each time to avoid storing in every direct buffer.
private long mappingOffset() {
int ps = Bits.pageSize();
long offset = address % ps;
return (offset >= 0) ? offset : (ps + offset);
}
private long mappingAddress(long mappingOffset) {
return address - mappingOffset;
}
private long mappingLength(long mappingOffset) {
return (long)capacity() + mappingOffset;
}
/**
* Tells whether or not this buffer's content is resident in physical
* memory.
......@@ -115,7 +133,9 @@ public abstract class MappedByteBuffer
checkMapped();
if ((address == 0) || (capacity() == 0))
return true;
return isLoaded0(((DirectByteBuffer)this).address(), capacity());
long offset = mappingOffset();
long length = mappingLength(offset);
return isLoaded0(mappingAddress(offset), length, Bits.pageCount(length));
}
/**
......@@ -132,7 +152,20 @@ public abstract class MappedByteBuffer
checkMapped();
if ((address == 0) || (capacity() == 0))
return this;
load0(((DirectByteBuffer)this).address(), capacity(), Bits.pageSize());
long offset = mappingOffset();
long length = mappingLength(offset);
load0(mappingAddress(offset), length);
// touch each page
Unsafe unsafe = Unsafe.getUnsafe();
int ps = Bits.pageSize();
int count = Bits.pageCount(length);
long a = mappingAddress(offset);
for (int i=0; i<count; i++) {
unsafe.getByte(a);
a += ps;
}
return this;
}
......@@ -156,14 +189,15 @@ public abstract class MappedByteBuffer
*/
public final MappedByteBuffer force() {
checkMapped();
if ((address == 0) || (capacity() == 0))
return this;
force0(((DirectByteBuffer)this).address(), capacity());
if ((address != 0) && (capacity() != 0)) {
long offset = mappingOffset();
force0(mappingAddress(offset), mappingLength(offset));
}
return this;
}
private native boolean isLoaded0(long address, long length);
private native int load0(long address, long length, int pageSize);
private native boolean isLoaded0(long address, long length, int pageCount);
private native void load0(long address, long length);
private native void force0(long address, long length);
}
......@@ -32,14 +32,11 @@
#include <stddef.h>
#include <stdlib.h>
JNIEXPORT jboolean JNICALL
Java_java_nio_MappedByteBuffer_isLoaded0(JNIEnv *env, jobject obj,
jlong address, jlong len)
Java_java_nio_MappedByteBuffer_isLoaded0(JNIEnv *env, jobject obj, jlong address,
jlong len, jint numPages)
{
jboolean loaded = JNI_TRUE;
jint pageSize = sysconf(_SC_PAGESIZE);
jint numPages = (len + pageSize - 1) / pageSize;
int result = 0;
int i = 0;
void *a = (void *) jlong_to_ptr(address);
......@@ -55,9 +52,9 @@ Java_java_nio_MappedByteBuffer_isLoaded0(JNIEnv *env, jobject obj,
}
result = mincore(a, (size_t)len, vec);
if (result != 0) {
free(vec);
if (result == -1) {
JNU_ThrowIOExceptionWithLastError(env, "mincore failed");
free(vec);
return JNI_FALSE;
}
......@@ -72,23 +69,15 @@ Java_java_nio_MappedByteBuffer_isLoaded0(JNIEnv *env, jobject obj,
}
JNIEXPORT jint JNICALL
JNIEXPORT void JNICALL
Java_java_nio_MappedByteBuffer_load0(JNIEnv *env, jobject obj, jlong address,
jlong len, jint pageSize)
jlong len)
{
int pageIncrement = pageSize / sizeof(int);
int numPages = (len + pageSize - 1) / pageSize;
int *ptr = (int *)jlong_to_ptr(address);
int i = 0;
int j = 0;
int result = madvise((caddr_t)ptr, len, MADV_WILLNEED);
/* touch every page */
for (i=0; i<numPages; i++) {
j += *((volatile int *)ptr);
ptr += pageIncrement;
char *a = (char *)jlong_to_ptr(address);
int result = madvise((caddr_t)a, (size_t)len, MADV_WILLNEED);
if (result == -1) {
JNU_ThrowIOExceptionWithLastError(env, "madvise failed");
}
return j;
}
......@@ -96,13 +85,9 @@ JNIEXPORT void JNICALL
Java_java_nio_MappedByteBuffer_force0(JNIEnv *env, jobject obj, jlong address,
jlong len)
{
jlong pageSize = sysconf(_SC_PAGESIZE);
unsigned long lAddress = address;
jlong offset = lAddress % pageSize;
void *a = (void *) jlong_to_ptr(lAddress - offset);
int result = msync(a, (size_t)(len + offset), MS_SYNC);
if (result != 0) {
void* a = (void *)jlong_to_ptr(address);
int result = msync(a, (size_t)len, MS_SYNC);
if (result == -1) {
JNU_ThrowIOExceptionWithLastError(env, "msync failed");
}
}
......@@ -31,8 +31,8 @@
#include <stdlib.h>
JNIEXPORT jboolean JNICALL
Java_java_nio_MappedByteBuffer_isLoaded0(JNIEnv *env, jobject obj,
jlong address, jlong len)
Java_java_nio_MappedByteBuffer_isLoaded0(JNIEnv *env, jobject obj, jlong address,
jlong len, jint numPages)
{
jboolean loaded = JNI_FALSE;
/* Information not available?
......@@ -43,22 +43,11 @@ Java_java_nio_MappedByteBuffer_isLoaded0(JNIEnv *env, jobject obj,
return loaded;
}
JNIEXPORT jint JNICALL
JNIEXPORT void JNICALL
Java_java_nio_MappedByteBuffer_load0(JNIEnv *env, jobject obj, jlong address,
jlong len, jint pageSize)
jlong len)
{
int *ptr = (int *) jlong_to_ptr(address);
int pageIncrement = pageSize / sizeof(int);
jlong numPages = (len + pageSize - 1) / pageSize;
int i = 0;
int j = 0;
/* touch every page */
for (i=0; i<numPages; i++) {
j += *((volatile int *)ptr);
ptr += pageIncrement;
}
return j;
// no madvise available
}
JNIEXPORT void JNICALL
......
......@@ -22,7 +22,7 @@
*/
/* @test
* @bug 4462336
* @bug 4462336 6799037
* @summary Simple MappedByteBuffer tests
* @run main/othervm Basic
*/
......@@ -52,6 +52,12 @@ public class Basic {
mbb.force();
if (!mbb.isReadOnly())
throw new RuntimeException("Incorrect isReadOnly");
// repeat with unaligned position in file
mbb = fc.map(FileChannel.MapMode.READ_ONLY, 1, 10);
mbb.load();
mbb.isLoaded();
mbb.force();
fc.close();
fis.close();
......
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 6934977
* @summary Test MappedByteBuffer operations after mapped bye buffer becomes
* inaccessible
* @run main/othervm Truncate
*/
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.concurrent.Callable;
public class Truncate {
static final long INITIAL_FILE_SIZE = 32000L;
static final long TRUNCATED_FILE_SIZE = 512L;
public static void main(String[] args) throws Exception {
File blah = File.createTempFile("blah", null);
blah.deleteOnExit();
final FileChannel fc = new RandomAccessFile(blah, "rw").getChannel();
fc.position(INITIAL_FILE_SIZE).write(ByteBuffer.wrap("THE END".getBytes()));
final MappedByteBuffer mbb =
fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size());
boolean truncated;
try {
fc.truncate(TRUNCATED_FILE_SIZE);
truncated = true;
} catch (IOException ioe) {
// probably on Windows where a file cannot be truncated when
// there is a file mapping.
truncated = false;
}
if (truncated) {
// Test 1: access region that is no longer accessible
execute(new Callable<Void>() {
public Void call() {
mbb.get((int)TRUNCATED_FILE_SIZE + 1);
mbb.put((int)TRUNCATED_FILE_SIZE + 2, (byte)123);
return null;
}
});
// Test 2: load buffer into memory
execute(new Callable<Void>() {
public Void call() throws IOException {
mbb.load();
return null;
}
});
}
fc.close();
}
// Runs the given task in its own thread. If operating correcting the
// the thread will terminate with an InternalError as the mapped buffer
// is inaccessible.
static void execute(final Callable<?> c) {
Runnable r = new Runnable() {
public void run() {
try {
Object ignore = c.call();
} catch (Exception ignore) {
}
}
};
Thread t = new Thread(r);
t.start();
try { t.join(); } catch (InterruptedException ignore) { }
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册