6941130: Semaphore should throw if number of permits overflows or underflows
Summary: Check if release could make number of permits negative
Reviewed-by: dl, dholmes
--- a/jdk/src/share/classes/java/util/concurrent/Semaphore.java Tue Apr 06 15:45:21 2010 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/Semaphore.java Wed Apr 07 12:30:49 2010 -0700
@@ -191,8 +191,11 @@
protected final boolean tryReleaseShared(int releases) {
for (;;) {
- int p = getState();
- if (compareAndSetState(p, p + releases))
+ int current = getState();
+ int next = current + releases;
+ if (next < current) // overflow
+ throw new Error("Maximum permit count exceeded");
+ if (compareAndSetState(current, next))
return true;
}
}
@@ -201,6 +204,8 @@
for (;;) {
int current = getState();
int next = current - reductions;
+ if (next > current) // underflow
+ throw new Error("Permit count underflow");
if (compareAndSetState(current, next))
return;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/Semaphore/PermitOverflow.java Wed Apr 07 12:30:49 2010 -0700
@@ -0,0 +1,102 @@
+/*
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/licenses/publicdomain
+ */
+
+/*
+ * @test
+ * @bug 6941130
+ * @summary Numeric overflow/underflow of permits causes Error throw
+ */
+
+import java.util.concurrent.Semaphore;
+
+public class PermitOverflow {
+
+ public static void main(String[] args) throws Throwable {
+ for (boolean fair : new boolean[] { true, false }) {
+ Semaphore sem = new Semaphore(Integer.MAX_VALUE - 1, fair);
+ if (sem.availablePermits() != Integer.MAX_VALUE - 1)
+ throw new RuntimeException();
+ try {
+ sem.release(2);
+ throw new RuntimeException();
+ } catch (Error expected) {
+ }
+ sem.release(1);
+ if (sem.availablePermits() != Integer.MAX_VALUE)
+ throw new RuntimeException();
+ try {
+ sem.release(1);
+ throw new RuntimeException();
+ } catch (Error expected) {
+ }
+ try {
+ sem.release(Integer.MAX_VALUE);
+ throw new RuntimeException();
+ } catch (Error expected) {
+ }
+ }
+
+ class Sem extends Semaphore {
+ public Sem(int permits, boolean fair) {
+ super(permits, fair);
+ }
+ public void reducePermits(int reduction) {
+ super.reducePermits(reduction);
+ }
+ }
+
+ for (boolean fair : new boolean[] { true, false }) {
+ Sem sem = new Sem(Integer.MIN_VALUE + 1, fair);
+ if (sem.availablePermits() != Integer.MIN_VALUE + 1)
+ throw new RuntimeException();
+ try {
+ sem.reducePermits(2);
+ throw new RuntimeException();
+ } catch (Error expected) {
+ }
+ sem.reducePermits(1);
+ if (sem.availablePermits() != Integer.MIN_VALUE)
+ throw new RuntimeException();
+ try {
+ sem.reducePermits(1);
+ throw new RuntimeException();
+ } catch (Error expected) {
+ }
+ try {
+ sem.reducePermits(Integer.MAX_VALUE);
+ throw new RuntimeException();
+ } catch (Error expected) {
+ }
+ }
+ }
+}