Skip to content

Commit 6445ee4

Browse files
author
Brian Burkhalter
committed
5041655: (ch) FileLock: negative param and overflow issues
Reviewed-by: alanb
1 parent 7feabee commit 6445ee4

File tree

9 files changed

+247
-45
lines changed

9 files changed

+247
-45
lines changed

src/java.base/share/classes/java/nio/channels/AsynchronousFileChannel.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -425,10 +425,13 @@ public static AsynchronousFileChannel open(Path file, OpenOption... options)
425425
* required then a region starting at zero, and no smaller than the
426426
* expected maximum size of the file, should be locked. The two-argument
427427
* {@link #lock(Object,CompletionHandler)} method simply locks a region
428-
* of size {@link Long#MAX_VALUE}. If a lock that overlaps the requested
429-
* region is already held by this Java virtual machine, or this method has
430-
* been invoked to lock an overlapping region and that operation has not
431-
* completed, then this method throws {@link OverlappingFileLockException}.
428+
* of size {@link Long#MAX_VALUE}. If the {@code position} is non-negative
429+
* and the {@code size} is zero, then a lock of size
430+
* {@code Long.MAX_VALUE - position} is returned. If a lock that
431+
* overlaps the requested region is already held by this Java virtual
432+
* machine, or this method has been invoked to lock an overlapping region
433+
* and that operation has not completed, then this method throws
434+
* {@link OverlappingFileLockException}.
432435
*
433436
* <p> Some operating systems do not support a mechanism to acquire a file
434437
* lock in an asynchronous manner. Consequently an implementation may
@@ -454,7 +457,10 @@ public static AsynchronousFileChannel open(Path file, OpenOption... options)
454457
* non-negative
455458
* @param size
456459
* The size of the locked region; must be non-negative, and the sum
457-
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
460+
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative.
461+
* A value of zero means to lock all bytes from the specified
462+
* starting position to the end of the file, regardless of whether
463+
* the file is subsequently extended or truncated
458464
* @param shared
459465
* {@code true} to request a shared lock, in which case this
460466
* channel must be open for reading (and possibly writing);
@@ -532,7 +538,10 @@ public final <A> void lock(A attachment,
532538
* non-negative
533539
* @param size
534540
* The size of the locked region; must be non-negative, and the sum
535-
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
541+
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative.
542+
* A value of zero means to lock all bytes from the specified
543+
* starting position to the end of the file, regardless of whether
544+
* the file is subsequently extended or truncated
536545
* @param shared
537546
* {@code true} to request a shared lock, in which case this
538547
* channel must be open for reading (and possibly writing);
@@ -586,15 +595,20 @@ public final Future<FileLock> lock() {
586595
* either having acquired a lock on the requested region or having failed to
587596
* do so. If it fails to acquire a lock because an overlapping lock is held
588597
* by another program then it returns {@code null}. If it fails to acquire
589-
* a lock for any other reason then an appropriate exception is thrown.
598+
* a lock for any other reason then an appropriate exception is thrown. If
599+
* the {@code position} is non-negative and the {@code size} is zero, then a
600+
* lock of size {@code Long.MAX_VALUE - position} is returned.
590601
*
591602
* @param position
592603
* The position at which the locked region is to start; must be
593604
* non-negative
594605
*
595606
* @param size
596607
* The size of the locked region; must be non-negative, and the sum
597-
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
608+
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative.
609+
* A value of zero means to lock all bytes from the specified
610+
* starting position to the end of the file, regardless of whether
611+
* the file is subsequently extended or truncated
598612
*
599613
* @param shared
600614
* {@code true} to request a shared lock,

src/java.base/share/classes/java/nio/channels/FileChannel.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,9 @@ public abstract MappedByteBuffer map(MapMode mode, long position, long size)
996996
* required then a region starting at zero, and no smaller than the
997997
* expected maximum size of the file, should be locked. The zero-argument
998998
* {@link #lock()} method simply locks a region of size {@link
999-
* Long#MAX_VALUE}.
999+
* Long#MAX_VALUE}. If the {@code position} is non-negative and the
1000+
* {@code size} is zero, then a lock of size
1001+
* {@code Long.MAX_VALUE - position} is returned.
10001002
*
10011003
* <p> Some operating systems do not support shared locks, in which case a
10021004
* request for a shared lock is automatically converted into a request for
@@ -1014,7 +1016,10 @@ public abstract MappedByteBuffer map(MapMode mode, long position, long size)
10141016
*
10151017
* @param size
10161018
* The size of the locked region; must be non-negative, and the sum
1017-
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
1019+
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative.
1020+
* A value of zero means to lock all bytes from the specified
1021+
* starting position to the end of the file, regardless of whether
1022+
* the file is subsequently extended or truncated
10181023
*
10191024
* @param shared
10201025
* {@code true} to request a shared lock, in which case this
@@ -1123,7 +1128,9 @@ public final FileLock lock() throws IOException {
11231128
* required then a region starting at zero, and no smaller than the
11241129
* expected maximum size of the file, should be locked. The zero-argument
11251130
* {@link #tryLock()} method simply locks a region of size {@link
1126-
* Long#MAX_VALUE}.
1131+
* Long#MAX_VALUE}. If the {@code position} is non-negative and the
1132+
* {@code size} is zero, then a lock of size
1133+
* {@code Long.MAX_VALUE - position} is returned.
11271134
*
11281135
* <p> Some operating systems do not support shared locks, in which case a
11291136
* request for a shared lock is automatically converted into a request for
@@ -1141,7 +1148,10 @@ public final FileLock lock() throws IOException {
11411148
*
11421149
* @param size
11431150
* The size of the locked region; must be non-negative, and the sum
1144-
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
1151+
* {@code position}&nbsp;+&nbsp;{@code size} must be non-negative.
1152+
* A value of zero means to lock all bytes from the specified
1153+
* starting position to the end of the file, regardless of whether
1154+
* the file is subsequently extended or truncated
11451155
*
11461156
* @param shared
11471157
* {@code true} to request a shared lock,

src/java.base/share/classes/java/nio/channels/FileLock.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -269,14 +269,36 @@ public final boolean isShared() {
269269
* @param size
270270
* The size of the lock range
271271
*
272-
* @return {@code true} if, and only if, this lock and the given lock
273-
* range overlap by at least one byte
272+
* @return {@code true} if this lock and the given lock range overlap
273+
* by at least one byte; {@code false} if {@code size} is
274+
* negative or the lock range does not overlap this lock
274275
*/
275276
public final boolean overlaps(long position, long size) {
276-
if (position + size <= this.position)
277-
return false; // That is below this
278-
if (this.position + this.size <= position)
279-
return false; // This is below that
277+
if (size < 0)
278+
return false;
279+
280+
// Test whether this is below that
281+
try {
282+
if (Math.addExact(this.position, this.size) <= position)
283+
return false;
284+
} catch (ArithmeticException ignored) {
285+
// the sum of this.position and this.size overflows the range of
286+
// long hence their mathematical sum is greater than position
287+
}
288+
289+
// if size == 0 then the specified lock range is unbounded and
290+
// cannot be below the range of this lock
291+
if (size > 0) {
292+
// Test whether that is below this
293+
try {
294+
if (Math.addExact(position, size) <= this.position)
295+
return false;
296+
} catch (ArithmeticException ignored) {
297+
// the sum of position and size overflows the range of long
298+
// hence their mathematical sum is greater than this.position
299+
}
300+
}
301+
280302
return true;
281303
}
282304

src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1271,6 +1271,8 @@ public FileLock lock(long position, long size, boolean shared)
12711271
throw new NonReadableChannelException();
12721272
if (!shared && !writable)
12731273
throw new NonWritableChannelException();
1274+
if (size == 0)
1275+
size = Long.MAX_VALUE - Math.max(0, position);
12741276
FileLockImpl fli = new FileLockImpl(this, position, size, shared);
12751277
FileLockTable flt = fileLockTable();
12761278
flt.add(fli);
@@ -1316,6 +1318,8 @@ public FileLock tryLock(long position, long size, boolean shared)
13161318
throw new NonReadableChannelException();
13171319
if (!shared && !writable)
13181320
throw new NonWritableChannelException();
1321+
if (size == 0)
1322+
size = Long.MAX_VALUE - Math.max(0, position);
13191323
FileLockImpl fli = new FileLockImpl(this, position, size, shared);
13201324
FileLockTable flt = fileLockTable();
13211325
flt.add(fli);

src/java.base/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -181,8 +181,10 @@ <A> Future<FileLock> implLock(final long position,
181181
if (!shared && !writing)
182182
throw new NonWritableChannelException();
183183

184+
long len = (size != 0) ? size : Long.MAX_VALUE - Math.max(0, position);
185+
184186
// add to lock table
185-
final FileLockImpl fli = addToFileLockTable(position, size, shared);
187+
final FileLockImpl fli = addToFileLockTable(position, len, shared);
186188
if (fli == null) {
187189
Throwable exc = new ClosedChannelException();
188190
if (handler == null)
@@ -203,7 +205,7 @@ public void run() {
203205
try {
204206
begin();
205207
do {
206-
n = nd.lock(fdObj, true, position, size, shared);
208+
n = nd.lock(fdObj, true, position, len, shared);
207209
} while ((n == FileDispatcher.INTERRUPTED) && isOpen());
208210
if (n != FileDispatcher.LOCKED || !isOpen()) {
209211
throw new AsynchronousCloseException();
@@ -248,6 +250,9 @@ public FileLock tryLock(long position, long size, boolean shared)
248250
if (!shared && !writing)
249251
throw new NonWritableChannelException();
250252

253+
if (size == 0)
254+
size = Long.MAX_VALUE - Math.max(0, position);
255+
251256
// add to lock table
252257
FileLockImpl fli = addToFileLockTable(position, size, shared);
253258
if (fli == null)

src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -299,8 +299,10 @@ <A> Future<FileLock> implLock(final long position,
299299
if (!shared && !writing)
300300
throw new NonWritableChannelException();
301301

302+
long len = (size != 0) ? size : Long.MAX_VALUE - Math.max(0, position);
303+
302304
// add to lock table
303-
FileLockImpl fli = addToFileLockTable(position, size, shared);
305+
FileLockImpl fli = addToFileLockTable(position, len, shared);
304306
if (fli == null) {
305307
Throwable exc = new ClosedChannelException();
306308
if (handler == null)
@@ -332,6 +334,9 @@ public FileLock tryLock(long position, long size, boolean shared)
332334
if (!shared && !writing)
333335
throw new NonWritableChannelException();
334336

337+
if (size == 0)
338+
size = Long.MAX_VALUE - Math.max(0, position);
339+
335340
// add to lock table
336341
final FileLockImpl fli = addToFileLockTable(position, size, shared);
337342
if (fli == null)

test/jdk/java/nio/channels/AsynchronousFileChannel/Basic.java

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -22,18 +22,37 @@
2222
*/
2323

2424
/* @test
25-
* @bug 4607272 6822643 6830721 6842687
25+
* @bug 4607272 5041655 6822643 6830721 6842687
2626
* @summary Unit test for AsynchronousFileChannel
2727
* @key randomness
2828
*/
2929

30-
import java.nio.file.*;
31-
import java.nio.channels.*;
32-
import java.nio.ByteBuffer;
3330
import java.io.File;
3431
import java.io.IOException;
35-
import java.util.*;
36-
import java.util.concurrent.*;
32+
import java.nio.ByteBuffer;
33+
import java.nio.channels.AsynchronousCloseException;
34+
import java.nio.channels.AsynchronousFileChannel;
35+
import java.nio.channels.ClosedChannelException;
36+
import java.nio.channels.CompletionHandler;
37+
import java.nio.channels.FileLock;
38+
import java.nio.channels.NonWritableChannelException;
39+
import java.nio.channels.OverlappingFileLockException;
40+
import java.nio.file.Path;
41+
import java.nio.file.StandardOpenOption;
42+
import java.util.ArrayList;
43+
import java.util.EnumSet;
44+
import java.util.List;
45+
import java.util.Random;
46+
import java.util.Set;
47+
import java.util.concurrent.CancellationException;
48+
import java.util.concurrent.CountDownLatch;
49+
import java.util.concurrent.ExecutionException;
50+
import java.util.concurrent.Executors;
51+
import java.util.concurrent.ExecutorService;
52+
import java.util.concurrent.Future;
53+
import java.util.concurrent.ThreadFactory;
54+
import java.util.concurrent.TimeoutException;;
55+
import java.util.concurrent.TimeUnit;
3756
import java.util.concurrent.atomic.AtomicReference;
3857
import static java.nio.file.StandardOpenOption.*;
3958

@@ -176,7 +195,12 @@ static void testLocking(Path file) throws IOException {
176195
// test 1 - acquire lock and check that tryLock throws
177196
// OverlappingFileLockException
178197
try {
179-
fl = ch.lock().get();
198+
long pos = rand.nextInt(Integer.MAX_VALUE);
199+
fl = ch.lock(pos, 0, false).get();
200+
long expectedSize = Long.MAX_VALUE - pos;
201+
if(fl.size() != expectedSize)
202+
throw new RuntimeException("Lock size " + fl.size() +
203+
" != " + expectedSize + " for position " + pos);
180204
} catch (ExecutionException x) {
181205
throw new RuntimeException(x);
182206
} catch (InterruptedException x) {
@@ -192,7 +216,12 @@ static void testLocking(Path file) throws IOException {
192216
fl.release();
193217

194218
// test 2 - acquire try and check that lock throws OverlappingFileLockException
195-
fl = ch.tryLock();
219+
long pos = rand.nextInt(Integer.MAX_VALUE);
220+
fl = ch.tryLock(pos, 0, false);
221+
long expectedSize = Long.MAX_VALUE - pos;
222+
if(fl.size() != expectedSize)
223+
throw new RuntimeException("Lock size " + fl.size() + " != " +
224+
expectedSize + " for position " + pos);
196225
if (fl == null)
197226
throw new RuntimeException("Unable to acquire lock");
198227
try {

test/jdk/java/nio/channels/FileChannel/Lock.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -22,12 +22,19 @@
2222
*/
2323

2424
/* @test
25-
* @bug 4429043 4493595 6332756 6709457 7146506
25+
* @bug 4429043 4493595 5041655 6332756 6709457 7146506
2626
* @summary Test FileChannel file locking
2727
*/
2828

29-
import java.io.*;
30-
import java.nio.channels.*;
29+
import java.io.BufferedReader;
30+
import java.io.File;
31+
import java.io.FileOutputStream;
32+
import java.io.InputStreamReader;
33+
import java.io.RandomAccessFile;
34+
import java.nio.channels.FileChannel;
35+
import java.nio.channels.FileLock;
36+
import java.nio.channels.OverlappingFileLockException;
37+
import java.util.Random;
3138
import static java.nio.file.StandardOpenOption.*;
3239

3340
/**
@@ -126,12 +133,23 @@ static void test1(File blah, String str) throws Exception {
126133
static void test2(File blah, boolean b) throws Exception {
127134
try (RandomAccessFile raf = new RandomAccessFile(blah, "rw")) {
128135
FileChannel channel = raf.getChannel();
129-
FileLock lock;
130-
if (b)
131-
lock = channel.lock();
132-
else
133-
lock = channel.tryLock();
134-
lock.release();
136+
try (FileLock lock = b ? channel.lock() : channel.tryLock()) {
137+
}
138+
139+
Random rnd = new Random(System.currentTimeMillis());
140+
long position = rnd.nextInt(Integer.MAX_VALUE);
141+
long expectedSize = Long.MAX_VALUE - position;
142+
143+
for (boolean shared : new boolean[] {false, true}) {
144+
try (FileLock lock = b ? channel.lock(position, 0, false) :
145+
channel.tryLock(position, 0, false)) {
146+
if(lock.size() != expectedSize)
147+
throw new RuntimeException("Lock size " + lock.size() +
148+
" != " + expectedSize +
149+
" for position " + position + " of " +
150+
(shared ? "exclusive" : "shared") + " lock");
151+
}
152+
}
135153
}
136154
}
137155

0 commit comments

Comments
 (0)