238 lines
7.6 KiB
Java
238 lines
7.6 KiB
Java
|
/*******************************************************************************
|
||
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||
|
* All rights reserved. This program and the accompanying materials
|
||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||
|
* which accompanies this distribution, and is available at
|
||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||
|
*
|
||
|
* Contributors:
|
||
|
* IBM Corporation - initial API and implementation
|
||
|
*******************************************************************************/
|
||
|
package com.ibm.wala.util.warnings;
|
||
|
|
||
|
import java.util.Iterator;
|
||
|
import java.util.Set;
|
||
|
|
||
|
import com.ibm.wala.classLoader.CallSiteReference;
|
||
|
import com.ibm.wala.classLoader.IMethod;
|
||
|
import com.ibm.wala.classLoader.SyntheticMethod;
|
||
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||
|
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||
|
import com.ibm.wala.ipa.callgraph.impl.UnresolvedReflectionWarning;
|
||
|
import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter;
|
||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||
|
import com.ibm.wala.types.MethodReference;
|
||
|
import com.ibm.wala.types.TypeName;
|
||
|
import com.ibm.wala.types.TypeReference;
|
||
|
import com.ibm.wala.util.Atom;
|
||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||
|
import com.ibm.wala.util.collections.IteratorUtil;
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Support to walk a call graph and generate warnings.
|
||
|
*
|
||
|
* @author sfink
|
||
|
*/
|
||
|
public class CallGraphWarnings {
|
||
|
|
||
|
private static final TypeReference[] ignoredTypeArray = {
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Object"),
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lorg/apache/xerces/dom3/UserDataHandler"),
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lorg/w3c/dom/events/EventListener"),
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lorg/w3c/dom/ls/DOMBuilderFilter"),
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lorg/apache/xerces/dom/PSVIAttrNSImpl"),
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lorg/apache/xerces/dom/PSVIElementNSImpl"),
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lorg/apache/xerces/dom/NodeIteratorImpl"),
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lorg/apache/xml/serializer/SerializerTrace"),
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lorg/xml/sax/DocumentHandler"),
|
||
|
TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lorg/apache/xerces/dom/RangeImpl") };
|
||
|
|
||
|
/**
|
||
|
* Set of TypeReferences representing types which we do not report unreachable
|
||
|
* warnings for.
|
||
|
*/
|
||
|
private static Set<TypeReference> ignoredTypes = HashSetFactory.make();
|
||
|
static {
|
||
|
for (int i = 0; i < ignoredTypeArray.length; i++) {
|
||
|
ignoredTypes.add(ignoredTypeArray[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set of Atoms representing package names whose methods should be treated as
|
||
|
* no-ops
|
||
|
*/
|
||
|
private static Set<Atom> ignoredPackages = HashSetFactory.make();
|
||
|
|
||
|
/**
|
||
|
* Register a package names whose methods should be treated as no-ops; don't
|
||
|
* report unreachable warnings for these
|
||
|
*/
|
||
|
public static synchronized void ignorePackage(Atom p) {
|
||
|
ignoredPackages.add(p);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param m
|
||
|
* @return true iff we can ignore unreachable warnings for m
|
||
|
*/
|
||
|
private static boolean canIgnore(MethodReference m) {
|
||
|
TypeReference T = m.getDeclaringClass();
|
||
|
TypeName n = T.getName();
|
||
|
Atom p = n.getPackage();
|
||
|
return (ignoredPackages.contains(p) || ignoredTypes.contains(m.getDeclaringClass()));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param cg
|
||
|
* Call Graph
|
||
|
* @return set of warnings inferred from the call graph.
|
||
|
*/
|
||
|
public static WarningSet getWarnings(CallGraph cg) {
|
||
|
WarningSet result = new WarningSet();
|
||
|
if (cg.getNumberOfNodes() == 1) {
|
||
|
result.add(NoEntrypointsFailure.INSTANCE);
|
||
|
} else {
|
||
|
for (Iterator it = cg.iterateNodes(); it.hasNext();) {
|
||
|
CGNode n = (CGNode) it.next();
|
||
|
RTAContextInterpreter interp = cg.getInterpreter(n);
|
||
|
addWarningsForNode(result, n, interp);
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @author sfink
|
||
|
*/
|
||
|
private static class NoEntrypointsFailure extends Warning {
|
||
|
|
||
|
private static NoEntrypointsFailure INSTANCE = new NoEntrypointsFailure();
|
||
|
NoEntrypointsFailure() {
|
||
|
super(Warning.SEVERE);
|
||
|
}
|
||
|
public String getMsg() {
|
||
|
return getClass().toString();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void addWarningsForNode(WarningSet warnings, CGNode n, RTAContextInterpreter interp) {
|
||
|
IMethod m = n.getMethod();
|
||
|
if (m == null) {
|
||
|
return;
|
||
|
}
|
||
|
if (m.isSynthetic()) {
|
||
|
SyntheticMethod s = (SyntheticMethod) m;
|
||
|
if (s.hasPoison()) {
|
||
|
warnings.add(new PoisonWarning(s.getPoisonLevel(),n));
|
||
|
}
|
||
|
if (s.isFactoryMethod()) {
|
||
|
int count = IteratorUtil.count(interp.iterateNewSites(n, new WarningSet()));
|
||
|
if (count == 1) {
|
||
|
warnings.add(new UnresolvedReflectionWarning(n));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (m.isNative()) {
|
||
|
warnings.add(new NativeWarning(n));
|
||
|
}
|
||
|
// check that every call site in node has at least one successor
|
||
|
for (Iterator it = interp.iterateCallSites(n, warnings); it.hasNext();) {
|
||
|
CallSiteReference site = (CallSiteReference) it.next();
|
||
|
Iterator targets = n.getPossibleTargets(site).iterator();
|
||
|
|
||
|
if (!targets.hasNext()) {
|
||
|
if (!canIgnore(site.getDeclaredTarget())) {
|
||
|
warnings.add(new NoCalleeWarning(n, site));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @author sfink
|
||
|
*
|
||
|
*/
|
||
|
private static class PoisonWarning extends MethodWarning {
|
||
|
|
||
|
final String poison;
|
||
|
public PoisonWarning(byte level, CGNode node) {
|
||
|
super(level, node.getMethod().getReference());
|
||
|
poison = ((SyntheticMethod)node.getMethod()).getPoison();
|
||
|
}
|
||
|
|
||
|
public String getMsg() {
|
||
|
return getClass() + " " + poison;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @author sfink
|
||
|
*
|
||
|
* A warning generated by reaching an unmodelled native method
|
||
|
*/
|
||
|
private static class NativeWarning extends MethodWarning {
|
||
|
/**
|
||
|
* @param node
|
||
|
*/
|
||
|
public NativeWarning(CGNode node) {
|
||
|
super(SEVERE, node.getMethod().getReference());
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* (non-Javadoc)
|
||
|
*
|
||
|
* @see com.ibm.wala.util.Warning#getMsg()
|
||
|
*/
|
||
|
public String getMsg() {
|
||
|
return "Native method " + getMethod();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @author sfink
|
||
|
*
|
||
|
* A warning generated by reaching an call site with no callees found.
|
||
|
*/
|
||
|
private static class NoCalleeWarning extends MethodWarning {
|
||
|
|
||
|
private CallSiteReference site;
|
||
|
|
||
|
/**
|
||
|
* @param node
|
||
|
*/
|
||
|
public NoCalleeWarning(CGNode node, CallSiteReference site) {
|
||
|
super(node.getMethod().getReference());
|
||
|
this.site = site;
|
||
|
ClassLoaderReference cl = node.getMethod().getDeclaringClass().getClassLoader().getReference();
|
||
|
if (cl.equals(ClassLoaderReference.Primordial)) {
|
||
|
setLevel(CLIENT_MILD);
|
||
|
} else if (cl.equals(ClassLoaderReference.Extension)) {
|
||
|
setLevel(CLIENT_MODERATE);
|
||
|
} else {
|
||
|
setLevel(CLIENT_SEVERE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* (non-Javadoc)
|
||
|
*
|
||
|
* @see com.ibm.wala.util.Warning#getMsg()
|
||
|
*/
|
||
|
public String getMsg() {
|
||
|
return "No callee for " + site + " in node " + getMethod();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* (non-Javadoc)
|
||
|
*
|
||
|
* @see com.ibm.wala.util.warnings.Warning#severityString()
|
||
|
*/
|
||
|
protected String severityString() {
|
||
|
return "Unreachable call";
|
||
|
}
|
||
|
}
|
||
|
}
|