Skip to content
This repository has been archived by the owner on Aug 27, 2022. It is now read-only.

Commit

Permalink
8246282: [REDO] JDK-8245121 (bf) XBuffer.put(Xbuffer src) can give un…
Browse files Browse the repository at this point in the history
…expected result when storage overlaps

Reviewed-by: psandoz, alanb
  • Loading branch information
Brian Burkhalter committed Jun 4, 2020
1 parent dd016c3 commit 9cadf1a
Show file tree
Hide file tree
Showing 5 changed files with 467 additions and 71 deletions.
41 changes: 2 additions & 39 deletions src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
@@ -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
Expand Down Expand Up @@ -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();
Expand Down
28 changes: 3 additions & 25 deletions src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
@@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
6 changes: 5 additions & 1 deletion src/java.base/share/classes/java/nio/StringCharBuffer.java
@@ -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
Expand Down Expand Up @@ -145,6 +145,10 @@ ByteOrder charRegionOrder() {
return null;
}

boolean isAddressable() {
return false;
}

public boolean equals(Object ob) {
if (this == ob)
return true;
Expand Down
86 changes: 80 additions & 6 deletions src/java.base/share/classes/java/nio/X-Buffer.java.template
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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]

/**
Expand Down

0 comments on commit 9cadf1a

Please sign in to comment.