Skip to content

Commit

Permalink
add classloader isolation for type qualifier validators
Browse files Browse the repository at this point in the history
git-svn-id: https://findbugs.googlecode.com/svn/trunk@12870 eae3c2d3-9b19-0410-a86e-396b6ccb6ab3
  • Loading branch information
billpugh committed Oct 14, 2010
1 parent b8fe3d2 commit 4a9eaf4
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 17 deletions.
Expand Up @@ -25,6 +25,7 @@

import org.apache.bcel.Constants;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.ConstantPushInstruction;
import org.apache.bcel.generic.FieldInstruction;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InvokeInstruction;
Expand All @@ -47,15 +48,15 @@

/**
* Forward type qualifier dataflow analysis.
*
*
* @author David Hovemeyer
*/
public class ForwardTypeQualifierDataflowAnalysis extends TypeQualifierDataflowAnalysis {
private final DepthFirstSearch dfs;

/**
* Constructor.
*
*
* @param dfs
* DepthFirstSearch on the analyzed method
* @param xmethod
Expand All @@ -78,7 +79,7 @@ public ForwardTypeQualifierDataflowAnalysis(DepthFirstSearch dfs, XMethod xmetho

/*
* (non-Javadoc)
*
*
* @see
* edu.umd.cs.findbugs.ba.DataflowAnalysis#getBlockOrder(edu.umd.cs.findbugs
* .ba.CFG)
Expand All @@ -89,7 +90,7 @@ public BlockOrder getBlockOrder(CFG cfg) {

/*
* (non-Javadoc)
*
*
* @see edu.umd.cs.findbugs.ba.DataflowAnalysis#isForwards()
*/
public boolean isForwards() {
Expand All @@ -98,7 +99,7 @@ public boolean isForwards() {

/*
* (non-Javadoc)
*
*
* @see edu.umd.cs.findbugs.ba.jsr305.TypeQualifierDataflowAnalysis#
* registerSourceSinkLocations()
*/
Expand All @@ -121,8 +122,11 @@ private void registerInstructionSources() throws DataflowAnalysisException {
// Model field loads
registerFieldLoadSource(location);
} else if (instruction instanceof LDC) {
// Model field loads
// Model constant values
registerLDCValueSource(location);
} else if (instruction instanceof ConstantPushInstruction) {
// Model constant values
registerConstantPushSource(location);
}
}
}
Expand All @@ -138,6 +142,16 @@ private void registerLDCValueSource(Location location) throws DataflowAnalysisEx
registerTopOfStackSource(SourceSinkType.CONSTANT_VALUE, location, w, false, constantValue);
}

private void registerConstantPushSource(Location location) throws DataflowAnalysisException {

ConstantPushInstruction instruction = (ConstantPushInstruction) location.getHandle().getInstruction();
Number constantValue = instruction.getValue();
if (!typeQualifierValue.canValidate(constantValue))
return;
When w = typeQualifierValue.validate(constantValue);

registerTopOfStackSource(SourceSinkType.CONSTANT_VALUE, location, w, false, constantValue);
}
private void registerReturnValueSource(Location location) throws DataflowAnalysisException {
// Nothing to do if called method does not return a value
InvokeInstruction inv = (InvokeInstruction) location.getHandle().getInstruction();
Expand Down Expand Up @@ -219,7 +233,7 @@ private void registerParameterSources() {

/*
* (non-Javadoc)
*
*
* @see edu.umd.cs.findbugs.ba.jsr305.TypeQualifierDataflowAnalysis#
* propagateAcrossPhiNode
* (edu.umd.cs.findbugs.ba.jsr305.TypeQualifierValueSet,
Expand Down
Expand Up @@ -19,11 +19,13 @@

package edu.umd.cs.findbugs.ba.jsr305;

import java.security.Permission;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.annotation.meta.TypeQualifierValidator;
import javax.annotation.meta.When;
Expand Down Expand Up @@ -51,7 +53,7 @@
* example, if Foo is a type qualifier annotation having an int value, then
* Foo(0), Foo(1), etc. are all different type qualifiers which must be checked
* separately.
*
*
* @author William Pugh
*/
public class TypeQualifierValue {
Expand Down Expand Up @@ -127,6 +129,10 @@ private TypeQualifierValue(ClassDescriptor typeQualifier, @CheckForNull Object v
try {
Global.getAnalysisCache().getClassAnalysis(ClassData.class, checkerName);
// found it.
// System.out.println(checkerName);
SecurityManager m = System.getSecurityManager();
if (m == null)
System.setSecurityManager(new ValidationSecurityManager());
Class c = validatorLoader.loadClass(checkerName.getDottedClassName());
if (TypeQualifierValidator.class.isAssignableFrom(c)) {
Class<? extends TypeQualifierValidator> checkerClass = c.asSubclass(TypeQualifierValidator.class);
Expand Down Expand Up @@ -173,18 +179,48 @@ public boolean canValidate(Object constantValue) {
return true;
}

private static final InheritableThreadLocal<AtomicBoolean> performingValidation
= new InheritableThreadLocal<AtomicBoolean>() {
@Override protected synchronized AtomicBoolean initialValue() {
return new AtomicBoolean();
}

};

static final class ValidationSecurityManager extends SecurityManager {
@Override
public void checkPermission(Permission perm) {
// System.out.println("Checking " + perm);
if (performingValidation.get().get())
throw new SecurityException("not permissions granted while performing JSR-305 validation");
}
@Override
public void checkPermission(Permission perm, Object context) {
if (performingValidation.get().get())
throw new SecurityException("not permissions granted while performing JSR-305 validation");
}
}


public When validate(Object constantValue) {
if (validator == null)
throw new IllegalStateException("No validator");
IAnalysisCache analysisCache = Global.getAnalysisCache();
Profiler profiler = analysisCache.getProfiler();
profiler.start(validator.getClass());
AtomicBoolean performing = performingValidation.get();
try {
if (!performing.compareAndSet(false, true)) {
throw new IllegalStateException("recursive validation");
}
return validator.forConstantValue(null, constantValue);
} catch (Exception e) {
AnalysisContext.logError("Error executing custom validator for " + typeQualifier + " " + constantValue, e);
return When.UNKNOWN;
} finally {
if (!performing.compareAndSet(true, false)) {
throw new IllegalStateException("performingValidation not set when validation completes");
}
profiler.end(validator.getClass());

}
Expand All @@ -193,7 +229,7 @@ public When validate(Object constantValue) {
/**
* Given a ClassDescriptor/value pair, return the interned
* TypeQualifierValue representing that pair.
*
*
* @param desc
* a ClassDescriptor denoting a type qualifier annotation
* @param value
Expand All @@ -214,7 +250,7 @@ TypeQualifierValue getValue(ClassDescriptor desc, Object value) {

/**
* Get Collection of all known TypeQualifierValues.
*
*
* @return Collection of all known TypeQualifierValues
*/
public static Collection<TypeQualifierValue> getAllKnownTypeQualifiers() {
Expand All @@ -224,7 +260,7 @@ public static Collection<TypeQualifierValue> getAllKnownTypeQualifiers() {
/**
* Get the "complementary" TypeQualifierValues for given exclusive type
* qualifier.
*
*
* @param tqv
* a type qualifier (which must be exclusive)
* @return Collection of complementary exclusive type qualifiers
Expand Down Expand Up @@ -252,7 +288,7 @@ public static Collection<TypeQualifierValue> getComplementaryExclusiveTypeQualif
* Determine whether or not given TypeQualifierValue has multiple variants.
* I.e., if Color is a type qualifier having values RED, GREEN, and BLUE,
* then there are 3 variants, Color(RED), Color(GREEN), and COLOR(BLUE).
*
*
* @param tqv
* a TypeQualifierValue
* @return true if there are multiple variants of this type qualifier, false
Expand All @@ -270,7 +306,7 @@ public static boolean hasMultipleVariants(TypeQualifierValue tqv) {

/**
* Get the ClassDescriptor which specifies the type qualifier annotation.
*
*
* @return ClassDescriptor which specifies the type qualifier annotation
*/
public ClassDescriptor getTypeQualifierClassDescriptor() {
Expand All @@ -279,7 +315,7 @@ public ClassDescriptor getTypeQualifierClassDescriptor() {

/**
* Return whether or not this TypeQualifierValue denotes a strict qualifier.
*
*
* @return true if type qualifier is strict, false otherwise
*/
public boolean isStrictQualifier() {
Expand All @@ -289,7 +325,7 @@ public boolean isStrictQualifier() {
/**
* Return whether or not this TypeQualifierValue denotes an exclusive
* qualifier.
*
*
* @return true if type qualifier is exclusive, false otherwise
*/
public boolean isExclusiveQualifier() {
Expand All @@ -299,7 +335,7 @@ public boolean isExclusiveQualifier() {
/**
* Return whether or not this TypeQualifierValue denotes an exhaustive
* qualifier.
*
*
* @return true if type qualifier is exhaustive, false otherwise
*/
public boolean isExhaustiveQualifier() {
Expand All @@ -324,7 +360,7 @@ public boolean equals(Object o) {

/*
* (non-Javadoc)
*
*
* @see java.lang.Object#toString()
*/
@Override
Expand Down
Expand Up @@ -30,16 +30,26 @@
*/
public class ValidatorClassLoader extends ClassLoader {

ValidatorClassLoader() {
super(ClassLoader.getSystemClassLoader().getParent());
}
@Override
public Class findClass(String name) throws ClassNotFoundException {
if (name.startsWith("javax.annotation"))
return Class.forName(name);
byte[] b;
try {
b = loadClassData(name);
return defineClass(name, b, 0, b.length);
} catch (CheckedAnalysisException e) {
// e.printStackTrace();
return super.findClass(name);
} catch (RuntimeException e) {
// e.printStackTrace();
throw e;
}


}

private byte[] loadClassData(String name) throws CheckedAnalysisException {
Expand Down

0 comments on commit 4a9eaf4

Please sign in to comment.