undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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 id=NormalDeflation
|
||||
* @summary A collection of small tests using synchronized, wait, notify to try
|
||||
* and achieve good cheap coverage of UseObjectMonitorTable.
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+UseObjectMonitorTable
|
||||
* UseObjectMonitorTableTest
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test id=ExtremeDeflation
|
||||
* @summary Run the same tests but with deflation running constantly.
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:GuaranteedAsyncDeflationInterval=1
|
||||
* -XX:+UseObjectMonitorTable
|
||||
* UseObjectMonitorTableTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
import java.lang.Runnable;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class UseObjectMonitorTableTest {
|
||||
static final ThreadFactory TF = Executors.defaultThreadFactory();
|
||||
|
||||
static class WaitNotifyTest implements Runnable {
|
||||
static final int ITERATIONS = 10_000;
|
||||
static final int THREADS = 10;
|
||||
final WaitNotifySyncChannel startLatchChannel = new WaitNotifySyncChannel();
|
||||
final WaitNotifySyncChannel endLatchChannel = new WaitNotifySyncChannel();
|
||||
int count = 0;
|
||||
|
||||
static class WaitNotifyCountDownLatch {
|
||||
int latch;
|
||||
WaitNotifyCountDownLatch(int count) {
|
||||
latch = count;
|
||||
}
|
||||
synchronized void await() {
|
||||
while (latch != 0) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("WaitNotifyTest: Unexpected interrupt", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
synchronized void countDown() {
|
||||
if (latch != 0) {
|
||||
latch--;
|
||||
if (latch == 0) {
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static class WaitNotifySyncChannel extends WaitNotifyCountDownLatch {
|
||||
WaitNotifyCountDownLatch object;
|
||||
WaitNotifySyncChannel() { super(0); }
|
||||
synchronized void send(WaitNotifyCountDownLatch object, int count) {
|
||||
await();
|
||||
latch = count;
|
||||
this.object = object;
|
||||
notifyAll();
|
||||
}
|
||||
synchronized WaitNotifyCountDownLatch receive() {
|
||||
while (latch == 0) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("WaitNotifyTest: Unexpected interrupt", e);
|
||||
}
|
||||
}
|
||||
countDown();
|
||||
return object;
|
||||
}
|
||||
}
|
||||
synchronized int getCount() {
|
||||
return count;
|
||||
}
|
||||
synchronized void increment() {
|
||||
count++;
|
||||
}
|
||||
public void run() {
|
||||
System.out.println("WaitNotifyTest started.");
|
||||
for (int t = 0; t < THREADS; t++) {
|
||||
TF.newThread(() -> {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
startLatchChannel.receive().await();
|
||||
increment();
|
||||
endLatchChannel.receive().countDown();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
WaitNotifyCountDownLatch startLatch = new WaitNotifyCountDownLatch(1);
|
||||
WaitNotifyCountDownLatch endLatch = new WaitNotifyCountDownLatch(THREADS);
|
||||
int count = getCount();
|
||||
if (count != i * THREADS) {
|
||||
throw new RuntimeException("WaitNotifyTest: Invalid Count " + count +
|
||||
" pre-iteration " + i);
|
||||
}
|
||||
startLatchChannel.send(startLatch, 10);
|
||||
startLatch.countDown();
|
||||
endLatchChannel.send(endLatch, 10);
|
||||
endLatch.await();
|
||||
}
|
||||
int count = getCount();
|
||||
if (count != ITERATIONS * THREADS) {
|
||||
throw new RuntimeException("WaitNotifyTest: Invalid Count " + count);
|
||||
}
|
||||
System.out.println("WaitNotifyTest passed.");
|
||||
}
|
||||
}
|
||||
|
||||
static class RandomDepthTest implements Runnable {
|
||||
static final int THREADS = 10;
|
||||
static final int ITERATIONS = 10_000;
|
||||
static final int MAX_DEPTH = 20;
|
||||
static final int MAX_RECURSION_COUNT = 10;
|
||||
static final double RECURSION_CHANCE = .25;
|
||||
final Random random = Utils.getRandomInstance();
|
||||
final Locker lockers[] = new Locker[MAX_DEPTH];
|
||||
final CyclicBarrier syncBarrier = new CyclicBarrier(THREADS + 1);
|
||||
int count = 0;
|
||||
|
||||
class Locker {
|
||||
final int depth;
|
||||
Locker(int depth) {
|
||||
this.depth = depth;
|
||||
}
|
||||
synchronized int getCount() {
|
||||
if (depth == MAX_DEPTH) {
|
||||
return count;
|
||||
}
|
||||
return lockers[depth].getCount();
|
||||
}
|
||||
synchronized void increment(int recursion_count) {
|
||||
if (recursion_count != MAX_RECURSION_COUNT &&
|
||||
random.nextDouble() < RECURSION_CHANCE) {
|
||||
this.increment(recursion_count + 1);
|
||||
return;
|
||||
}
|
||||
if (depth == MAX_DEPTH) {
|
||||
count++;
|
||||
return;
|
||||
}
|
||||
lockers[depth + random.nextInt(MAX_DEPTH - depth)].increment(recursion_count);
|
||||
}
|
||||
synchronized Locker create() {
|
||||
if (depth != MAX_DEPTH) {
|
||||
lockers[depth] = (new Locker(depth + 1)).create();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
int getCount() {
|
||||
return lockers[0].getCount();
|
||||
}
|
||||
void increment() {
|
||||
lockers[random.nextInt(MAX_DEPTH)].increment(0);
|
||||
}
|
||||
void create() {
|
||||
lockers[0] = (new Locker(1)).create();
|
||||
}
|
||||
void syncPoint() {
|
||||
try {
|
||||
syncBarrier.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("RandomDepthTest: Unexpected interrupt", e);
|
||||
} catch (BrokenBarrierException e) {
|
||||
throw new RuntimeException("RandomDepthTest: Unexpected broken barrier", e);
|
||||
}
|
||||
}
|
||||
public void run() {
|
||||
System.out.println("RandomDepthTest started.");
|
||||
for (int t = 0; t < THREADS; t++) {
|
||||
TF.newThread(() -> {
|
||||
syncPoint();
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
increment();
|
||||
}
|
||||
syncPoint();
|
||||
}).start();
|
||||
}
|
||||
create();
|
||||
syncPoint();
|
||||
syncPoint();
|
||||
int count = getCount();
|
||||
if (count != THREADS * ITERATIONS) {
|
||||
throw new RuntimeException("RandomDepthTest: Invalid Count " + count);
|
||||
}
|
||||
System.out.println("RandomDepthTest passed.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Stream.of(
|
||||
TF.newThread(new WaitNotifyTest()),
|
||||
TF.newThread(new RandomDepthTest())
|
||||
).map(t -> {
|
||||
t.start();
|
||||
return t;
|
||||
}).forEach(t -> {
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("UseObjectMonitorTableTest: Unexpected interrupt", e);
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println("UseObjectMonitorTableTest passed.");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue