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,553 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2015, 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
|
||||
* @bug 4882798
|
||||
* @summary multi-thread test to exercise sync and contention for adds to transformer registry
|
||||
* @author Gabriel Adauto, Wily Technology
|
||||
*
|
||||
* @run build TransformerManagementThreadAddTests
|
||||
* @run shell MakeJAR.sh redefineAgent
|
||||
* @run main/othervm -javaagent:redefineAgent.jar TransformerManagementThreadAddTests TransformerManagementThreadAddTests
|
||||
*/
|
||||
import java.io.*;
|
||||
import java.lang.instrument.*;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.*;
|
||||
|
||||
public class TransformerManagementThreadAddTests extends ATestCaseScaffold
|
||||
{
|
||||
public static void
|
||||
main (String[] args)
|
||||
throws Throwable {
|
||||
ATestCaseScaffold test = new TransformerManagementThreadAddTests(args[0]);
|
||||
test.runTest();
|
||||
}
|
||||
|
||||
protected void
|
||||
doRunTest()
|
||||
throws Throwable {
|
||||
testMultiThreadAdds();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CONFIGURATION FOR TEST
|
||||
* ----------------------
|
||||
* Set these variables to different values to test the object that
|
||||
* manages the transformers.
|
||||
*
|
||||
* MIN_TRANS: the minimum number of transformers to add by a thread
|
||||
* MAX_TRANS: the maximum number of transformers to add by a thread
|
||||
* There will be a total of MAX_TRANS-MIN_TRANS+1 threads created.
|
||||
* Each thread will add between MIN_TRANS and MAX_TRANS transformers
|
||||
* to the manager.
|
||||
*
|
||||
* REMOVE_THREADS: the number of threads to run that spend their time
|
||||
* removing transformers
|
||||
*/
|
||||
protected static final int MIN_TRANS = 33;
|
||||
protected static final int MAX_TRANS = 45;
|
||||
protected static final int REMOVE_THREADS = 5;
|
||||
|
||||
protected static final boolean LOG_TRANSFORMATIONS = false;
|
||||
|
||||
/**
|
||||
* Field variables
|
||||
*/
|
||||
protected static final int TOTAL_THREADS = MAX_TRANS - MIN_TRANS + 1;
|
||||
|
||||
private byte[] fDummyClassBytes;
|
||||
// fCheckedTransformers is a Vector that is used to verify
|
||||
// that the transform() function is called in the same
|
||||
// order in which the transformers were added to the
|
||||
// TransformerManager. The test currently verifies that all
|
||||
// transformers for a specific worker thread are in
|
||||
// increasing order by index value.
|
||||
private Vector fCheckedTransformers;
|
||||
private Instrumentation fInstrumentation;
|
||||
private int fFinished;
|
||||
private ExecuteTransformersThread fExec;
|
||||
|
||||
// Need to use this for synchronization in subclass
|
||||
protected Vector fAddedTransformers;
|
||||
private String fDummyClassName;
|
||||
|
||||
/**
|
||||
* Constructor for TransformerManagementThreadAddTests.
|
||||
* @param name Name for the test
|
||||
*/
|
||||
public TransformerManagementThreadAddTests(String name)
|
||||
{
|
||||
super(name);
|
||||
|
||||
fCheckedTransformers = new Vector();
|
||||
fAddedTransformers = new Vector();
|
||||
|
||||
fDummyClassName = "DummyClass";
|
||||
String resourceName = "DummyClass.class";
|
||||
File f = new File(System.getProperty("test.classes", "."), resourceName);
|
||||
System.out.println("Reading test class from " + f);
|
||||
try
|
||||
{
|
||||
InputStream redefineStream = new FileInputStream(f);
|
||||
fDummyClassBytes = NamedBuffer.loadBufferFromStream(redefineStream);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
fail("Could not load the class: "+resourceName);
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
testMultiThreadAdds()
|
||||
{
|
||||
TransformerThread[] threads = new TransformerThread[TOTAL_THREADS];
|
||||
for (int i = MIN_TRANS; i <= MAX_TRANS; i++)
|
||||
{
|
||||
int index = i - MIN_TRANS;
|
||||
threads[index] = new TransformerThread("Trans"+prettyNum(index,2), i);
|
||||
}
|
||||
|
||||
ExecuteTransformersThread exec = new ExecuteTransformersThread();
|
||||
exec.start();
|
||||
for (int i = threads.length - 1; i >= 0; i--)
|
||||
{
|
||||
threads[i].start();
|
||||
}
|
||||
|
||||
// Effective Java - Item 48: Synchronize access to shared mutable data
|
||||
// Don't use a direct field getter.
|
||||
while (!exec.isDone())
|
||||
{
|
||||
// Effective Java - Item 51: Don't depend on the thread scheduler
|
||||
// Use sleep() instead of yield().
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
assertTrue(finalCheck());
|
||||
|
||||
if (LOG_TRANSFORMATIONS) {
|
||||
printTransformers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Instrumentation.
|
||||
* @return Instrumentation the data type with JPLIS calls
|
||||
*/
|
||||
public Instrumentation getInstrumentation()
|
||||
{
|
||||
return fInstrumentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the execution thread
|
||||
* @return ExecuteTransformersThread
|
||||
*/
|
||||
protected ExecuteTransformersThread getExecThread()
|
||||
{
|
||||
return fExec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the execution thread
|
||||
* @param exec The execution thread to set
|
||||
*/
|
||||
protected void setExecThread(ExecuteTransformersThread exec)
|
||||
{
|
||||
this.fExec = exec;
|
||||
}
|
||||
|
||||
// Effective Java - Item 48: Synchronize access to shared mutable data
|
||||
// Document a synchronized setter.
|
||||
protected synchronized void
|
||||
threadFinished(Thread t)
|
||||
{
|
||||
fFinished++;
|
||||
}
|
||||
|
||||
// Effective Java - Item 48: Synchronize access to shared mutable data
|
||||
// Provide synchronized getter.
|
||||
protected synchronized boolean
|
||||
threadsDone()
|
||||
{
|
||||
return fFinished == TOTAL_THREADS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method testCompleted.
|
||||
* @return boolean
|
||||
*/
|
||||
protected boolean
|
||||
testCompleted()
|
||||
{
|
||||
// Effective Java - Item 48: Synchronize access to shared mutable data
|
||||
// Don't use direct field getter.
|
||||
return getExecThread().isDone();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected boolean
|
||||
finalCheck()
|
||||
{
|
||||
if (LOG_TRANSFORMATIONS) {
|
||||
// log the list
|
||||
for (int x = 0; x < fCheckedTransformers.size(); x++ ) {
|
||||
System.out.println(x + "\t\t" + fCheckedTransformers.get(x));
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
|
||||
// check for multiples
|
||||
for (int x = 0; x < fCheckedTransformers.size(); x++ ) {
|
||||
Object current = fCheckedTransformers.get(x);
|
||||
for ( int y = x + 1; y < fCheckedTransformers.size(); y++) {
|
||||
Object running = fCheckedTransformers.get(y);
|
||||
if ( current.equals(running) ) {
|
||||
System.out.println(x + "\t" + y + " \t" + "FOUND DUPLICATE: " + current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 1; j < fCheckedTransformers.size(); j++) {
|
||||
ThreadTransformer transformer = (ThreadTransformer)fCheckedTransformers.get(j);
|
||||
for (int i = 0; i < j; i++) {
|
||||
ThreadTransformer currTrans = (ThreadTransformer)fCheckedTransformers.get(i);
|
||||
assertTrue(currTrans + " incorrectly appeared before " +
|
||||
transformer + " i=" + i + " j=" + j + " size=" +
|
||||
fCheckedTransformers.size(),
|
||||
!(
|
||||
currTrans.getThread().equals(transformer.getThread()) &&
|
||||
currTrans.getIndex() > transformer.getIndex()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected void
|
||||
setUp()
|
||||
throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
fFinished = 0;
|
||||
assertTrue(MIN_TRANS < MAX_TRANS);
|
||||
fInstrumentation = InstrumentationHandoff.getInstrumentationOrThrow();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected void
|
||||
tearDown()
|
||||
throws Exception
|
||||
{
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Method executeTransform.
|
||||
*/
|
||||
private void
|
||||
executeTransform()
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassDefinition cd = new ClassDefinition(DummyClass.class, fDummyClassBytes);
|
||||
|
||||
// When the ClassDefinition above is created for the first
|
||||
// time and every time redefineClasses() below is called,
|
||||
// the transform() function is called for each registered
|
||||
// transformer. We only want one complete set of calls to
|
||||
// be logged in the fCheckedTransformers Vector so we clear
|
||||
// any calls logged for ClassDefinition above and just use
|
||||
// the ones logged for redefineClasses() below.
|
||||
fCheckedTransformers.clear();
|
||||
|
||||
getInstrumentation().redefineClasses(new ClassDefinition[]{ cd });
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
fail("Could not find the class: "+DummyClass.class.getName());
|
||||
}
|
||||
catch (UnmodifiableClassException e)
|
||||
{
|
||||
fail("Could not modify the class: "+DummyClass.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method addTransformerToManager.
|
||||
* @param threadTransformer
|
||||
*/
|
||||
private void
|
||||
addTransformerToManager(ThreadTransformer threadTransformer)
|
||||
{
|
||||
getInstrumentation().addTransformer(threadTransformer);
|
||||
fAddedTransformers.add(threadTransformer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method checkInTransformer.
|
||||
* @param myClassFileTransformer
|
||||
*/
|
||||
private void
|
||||
checkInTransformer(ThreadTransformer transformer)
|
||||
{
|
||||
fCheckedTransformers.add(transformer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method createTransformer.
|
||||
* @param transformerThread
|
||||
* @param i
|
||||
* @return ThreadTransformer
|
||||
*/
|
||||
private ThreadTransformer
|
||||
createTransformer(TransformerThread thread, int index)
|
||||
{
|
||||
ThreadTransformer tt = null;
|
||||
|
||||
tt = new ThreadTransformer(thread, index);
|
||||
|
||||
return tt;
|
||||
}
|
||||
|
||||
|
||||
protected class
|
||||
ExecuteTransformersThread
|
||||
extends Thread
|
||||
{
|
||||
private boolean fDone = false;
|
||||
|
||||
// Effective Java - Item 48: Synchronize access to shared mutable data
|
||||
// Provide a synchronized getter.
|
||||
private synchronized boolean isDone() {
|
||||
return fDone;
|
||||
}
|
||||
|
||||
// Effective Java - Item 48: Synchronize access to shared mutable data
|
||||
// Provide a synchronized setter.
|
||||
private synchronized void setIsDone() {
|
||||
fDone = true;
|
||||
}
|
||||
|
||||
public void
|
||||
run()
|
||||
{
|
||||
while(!threadsDone())
|
||||
{
|
||||
executeTransform();
|
||||
}
|
||||
|
||||
// Do a final check for good measure
|
||||
executeTransform();
|
||||
// Effective Java - Item 48: Synchronize access to shared mutable data
|
||||
// Don't use direct field setter.
|
||||
setIsDone();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected class
|
||||
TransformerThread
|
||||
extends Thread
|
||||
{
|
||||
private final ThreadTransformer[] fThreadTransformers;
|
||||
|
||||
TransformerThread(String name, int numTransformers)
|
||||
{
|
||||
super(name);
|
||||
|
||||
fThreadTransformers = makeTransformers(numTransformers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method makeTransformers.
|
||||
* @param numTransformers
|
||||
* @return ThreadTransformer[]
|
||||
*/
|
||||
private ThreadTransformer[]
|
||||
makeTransformers(int numTransformers)
|
||||
{
|
||||
ThreadTransformer[] trans = new ThreadTransformer[numTransformers];
|
||||
|
||||
for (int i = 0; i < trans.length; i++)
|
||||
{
|
||||
trans[i] = createTransformer(TransformerThread.this, i);
|
||||
}
|
||||
|
||||
return trans;
|
||||
}
|
||||
|
||||
public void
|
||||
run()
|
||||
{
|
||||
for (int i = 0; i < fThreadTransformers.length; i++)
|
||||
{
|
||||
addTransformerToManager(fThreadTransformers[i]);
|
||||
}
|
||||
threadFinished(TransformerThread.this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ClassFileTransformer implementation that knows its thread
|
||||
*/
|
||||
protected class
|
||||
ThreadTransformer extends SimpleIdentityTransformer
|
||||
{
|
||||
private final String fName;
|
||||
private final int fIndex;
|
||||
private final Thread fThread;
|
||||
|
||||
/**
|
||||
* Constructor for ThreadTransformer.
|
||||
*/
|
||||
public ThreadTransformer(Thread thread, int index) {
|
||||
super();
|
||||
fThread = thread;
|
||||
fIndex = index;
|
||||
fName = "TT["+fThread.getName()+"]["+prettyNum(fIndex,3)+"]";
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return fName;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public byte[]
|
||||
transform(
|
||||
ClassLoader loader,
|
||||
String className,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain domain,
|
||||
byte[] classfileBuffer)
|
||||
{
|
||||
if ( className.equals(TransformerManagementThreadAddTests.this.fDummyClassName) ) {
|
||||
checkInTransformer(ThreadTransformer.this);
|
||||
}
|
||||
return super.transform( loader,
|
||||
className,
|
||||
classBeingRedefined,
|
||||
domain,
|
||||
classfileBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index.
|
||||
* @return int
|
||||
*/
|
||||
public int getIndex()
|
||||
{
|
||||
return fIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the thread.
|
||||
* @return Thread
|
||||
*/
|
||||
public Thread getThread()
|
||||
{
|
||||
return fThread;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* DEBUG STUFF
|
||||
*/
|
||||
private int NUM_SWITCHES;
|
||||
|
||||
/**
|
||||
* Method printTransformers.
|
||||
*/
|
||||
protected void printTransformers()
|
||||
{
|
||||
NUM_SWITCHES = 0;
|
||||
Iterator trans = fCheckedTransformers.iterator();
|
||||
ThreadTransformer old = null;
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
for (int i = 1; trans.hasNext(); i++)
|
||||
{
|
||||
ThreadTransformer t = (ThreadTransformer)trans.next();
|
||||
buf.append(t.toString());
|
||||
if (old != null)
|
||||
{
|
||||
if (!old.getThread().equals(t.getThread()))
|
||||
{
|
||||
NUM_SWITCHES++;
|
||||
buf.append("*");
|
||||
}
|
||||
else
|
||||
{ buf.append(" "); }
|
||||
}
|
||||
else
|
||||
{ buf.append(" "); }
|
||||
|
||||
if (i % 5 == 0)
|
||||
{
|
||||
buf.append("\n");
|
||||
}
|
||||
else
|
||||
{ buf.append(" "); }
|
||||
|
||||
old = t;
|
||||
}
|
||||
System.out.println(buf);
|
||||
System.out.println("\nNumber of transitions from one thread to another: "+NUM_SWITCHES);
|
||||
}
|
||||
|
||||
protected String
|
||||
prettyNum(int n, int numSize)
|
||||
{
|
||||
StringBuffer num = new StringBuffer(Integer.toString(n));
|
||||
int size = num.length();
|
||||
for (int i = 0; i < numSize - size; i++)
|
||||
{
|
||||
num.insert(0, "0");
|
||||
}
|
||||
|
||||
return num.toString();
|
||||
}
|
||||
/**
|
||||
* END DEBUG STUFF
|
||||
*/
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue