mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8246282: [REDO] JDK-8245121 (bf) XBuffer.put(Xbuffer src) can give unexpected result when storage overlaps
Reviewed-by: psandoz, alanb
This commit is contained in:
parent
dd016c34dd
commit
9cadf1a004
5 changed files with 467 additions and 71 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2020, 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
|
||||
|
@ -409,44 +409,7 @@ class Direct$Type$Buffer$RW$$BO$
|
|||
public $Type$Buffer put($Type$Buffer src) {
|
||||
#if[rw]
|
||||
checkSegment();
|
||||
if (src instanceof Direct$Type$Buffer$BO$) {
|
||||
if (src == this)
|
||||
throw createSameBufferException();
|
||||
Direct$Type$Buffer$RW$$BO$ sb = (Direct$Type$Buffer$RW$$BO$)src;
|
||||
|
||||
int spos = sb.position();
|
||||
int slim = sb.limit();
|
||||
assert (spos <= slim);
|
||||
int srem = (spos <= slim ? slim - spos : 0);
|
||||
|
||||
int pos = position();
|
||||
int lim = limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
if (srem > rem)
|
||||
throw new BufferOverflowException();
|
||||
try {
|
||||
UNSAFE.copyMemory(sb.ix(spos), ix(pos), (long)srem << $LG_BYTES_PER_VALUE$);
|
||||
} finally {
|
||||
Reference.reachabilityFence(sb);
|
||||
Reference.reachabilityFence(this);
|
||||
}
|
||||
sb.position(spos + srem);
|
||||
position(pos + srem);
|
||||
} else if (src.hb != null) {
|
||||
|
||||
int spos = src.position();
|
||||
int slim = src.limit();
|
||||
assert (spos <= slim);
|
||||
int srem = (spos <= slim ? slim - spos : 0);
|
||||
|
||||
put(src.hb, src.offset + spos, srem);
|
||||
src.position(spos + srem);
|
||||
|
||||
} else {
|
||||
super.put(src);
|
||||
}
|
||||
super.put(src);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2020, 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
|
||||
|
@ -47,7 +47,7 @@ class Heap$Type$Buffer$RW$
|
|||
// Cached array base offset
|
||||
private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset($type$[].class);
|
||||
|
||||
// Cached array base offset
|
||||
// Cached array index scale
|
||||
private static final long ARRAY_INDEX_SCALE = UNSAFE.arrayIndexScale($type$[].class);
|
||||
|
||||
// For speed these fields are actually declared in X-Buffer;
|
||||
|
@ -244,29 +244,7 @@ class Heap$Type$Buffer$RW$
|
|||
public $Type$Buffer put($Type$Buffer src) {
|
||||
#if[rw]
|
||||
checkSegment();
|
||||
if (src instanceof Heap$Type$Buffer) {
|
||||
if (src == this)
|
||||
throw createSameBufferException();
|
||||
Heap$Type$Buffer sb = (Heap$Type$Buffer)src;
|
||||
int pos = position();
|
||||
int sbpos = sb.position();
|
||||
int n = sb.limit() - sbpos;
|
||||
if (n > limit() - pos)
|
||||
throw new BufferOverflowException();
|
||||
System.arraycopy(sb.hb, sb.ix(sbpos),
|
||||
hb, ix(pos), n);
|
||||
sb.position(sbpos + n);
|
||||
position(pos + n);
|
||||
} else if (src.isDirect()) {
|
||||
int n = src.remaining();
|
||||
int pos = position();
|
||||
if (n > limit() - pos)
|
||||
throw new BufferOverflowException();
|
||||
src.get(hb, ix(pos), n);
|
||||
position(pos + n);
|
||||
} else {
|
||||
super.put(src);
|
||||
}
|
||||
super.put(src);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2020, 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
|
||||
|
@ -145,6 +145,10 @@ class StringCharBuffer // package-private
|
|||
return null;
|
||||
}
|
||||
|
||||
boolean isAddressable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(Object ob) {
|
||||
if (this == ob)
|
||||
return true;
|
||||
|
|
|
@ -30,6 +30,7 @@ package java.nio;
|
|||
#if[char]
|
||||
import java.io.IOException;
|
||||
#end[char]
|
||||
import java.lang.ref.Reference;
|
||||
#if[streamableType]
|
||||
import java.util.Spliterator;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
@ -116,7 +117,7 @@ import jdk.internal.util.ArraysSupport;
|
|||
* obvious. It is therefore recommended that direct buffers be allocated
|
||||
* primarily for large, long-lived buffers that are subject to the underlying
|
||||
* system's native I/O operations. In general it is best to allocate direct
|
||||
* buffers only when they yield a measureable gain in program performance.
|
||||
* buffers only when they yield a measurable gain in program performance.
|
||||
*
|
||||
* <p> A direct byte buffer may also be created by {@link
|
||||
* java.nio.channels.FileChannel#map mapping} a region of a file
|
||||
|
@ -922,7 +923,10 @@ public abstract class $Type$Buffer
|
|||
* dst.put(src.get()); </pre>
|
||||
*
|
||||
* except that it first checks that there is sufficient space in this
|
||||
* buffer and it is potentially much more efficient.
|
||||
* buffer and it is potentially much more efficient. If this buffer and
|
||||
* the source buffer share the same backing array or memory, then the
|
||||
* result will be as if the source elements were first copied to an
|
||||
* intermediate location before being written into this buffer.
|
||||
*
|
||||
* @param src
|
||||
* The source buffer from which $type$s are to be read;
|
||||
|
@ -945,11 +949,67 @@ public abstract class $Type$Buffer
|
|||
throw createSameBufferException();
|
||||
if (isReadOnly())
|
||||
throw new ReadOnlyBufferException();
|
||||
int n = src.remaining();
|
||||
if (n > remaining())
|
||||
|
||||
int srcPos = src.position();
|
||||
int n = src.limit() - srcPos;
|
||||
int pos = position();
|
||||
if (n > limit() - pos)
|
||||
throw new BufferOverflowException();
|
||||
for (int i = 0; i < n; i++)
|
||||
put(src.get());
|
||||
|
||||
Object srcBase = src.base();
|
||||
|
||||
#if[char]
|
||||
if (src.isAddressable()) {
|
||||
#else[char]
|
||||
assert srcBase != null || src.isDirect();
|
||||
#end[char]
|
||||
|
||||
Object base = base();
|
||||
assert base != null || isDirect();
|
||||
|
||||
long srcAddr = src.address + ((long)srcPos << $LG_BYTES_PER_VALUE$);
|
||||
long addr = address + ((long)pos << $LG_BYTES_PER_VALUE$);
|
||||
long len = (long)n << $LG_BYTES_PER_VALUE$;
|
||||
|
||||
#if[!byte]
|
||||
if (this.order() == src.order()) {
|
||||
#end[!byte]
|
||||
try {
|
||||
UNSAFE.copyMemory(srcBase,
|
||||
srcAddr,
|
||||
base,
|
||||
addr,
|
||||
len);
|
||||
} finally {
|
||||
Reference.reachabilityFence(src);
|
||||
Reference.reachabilityFence(this);
|
||||
}
|
||||
#if[!byte]
|
||||
} else {
|
||||
try {
|
||||
UNSAFE.copySwapMemory(srcBase,
|
||||
srcAddr,
|
||||
base,
|
||||
addr,
|
||||
len,
|
||||
(long)1 << $LG_BYTES_PER_VALUE$);
|
||||
} finally {
|
||||
Reference.reachabilityFence(src);
|
||||
Reference.reachabilityFence(this);
|
||||
}
|
||||
}
|
||||
#end[!byte]
|
||||
|
||||
position(pos + n);
|
||||
src.position(srcPos + n);
|
||||
#if[char]
|
||||
} else { // src.isAddressable() == false
|
||||
assert StringCharBuffer.class.isInstance(src);
|
||||
for (int i = 0; i < n; i++)
|
||||
put(src.get());
|
||||
}
|
||||
#end[char]
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1437,6 +1497,20 @@ public abstract class $Type$Buffer
|
|||
*/
|
||||
public abstract boolean isDirect();
|
||||
|
||||
#if[char]
|
||||
/**
|
||||
* Tells whether this buffer has addressable memory, e.g., a Java array or
|
||||
* a native address. This method returns {@code true}. Subclasses such as
|
||||
* {@code StringCharBuffer}, which wraps a {@code CharSequence}, should
|
||||
* override this method to return {@code false}.
|
||||
*
|
||||
* @return {@code true} if, and only, this buffer has addressable memory
|
||||
*/
|
||||
boolean isAddressable() {
|
||||
return true;
|
||||
}
|
||||
#end[char]
|
||||
|
||||
#if[!char]
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue