From 11551ade86248529bd72d7b2e0416e4f6b701a92 Mon Sep 17 00:00:00 2001 From: Carlo Alberto Pozzoli Date: Mon, 26 Aug 2024 14:31:33 +0200 Subject: [PATCH 1/2] Make virtual call resolution method publicly available --- .../java/proguard/analysis/CallResolver.java | 137 +------------ .../main/java/proguard/analysis/CallUtil.java | 182 ++++++++++++++++++ 2 files changed, 187 insertions(+), 132 deletions(-) create mode 100644 base/src/main/java/proguard/analysis/CallUtil.java diff --git a/base/src/main/java/proguard/analysis/CallResolver.java b/base/src/main/java/proguard/analysis/CallResolver.java index d40b6e3d..fc60fa4b 100644 --- a/base/src/main/java/proguard/analysis/CallResolver.java +++ b/base/src/main/java/proguard/analysis/CallResolver.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; @@ -657,8 +656,8 @@ private void handleInvokeSpecial( * @param ref The {@link AnyMethodrefConstant} specifying name and descriptor of the method to be * invoked. * @return The fully qualified names of potential call target classes (usually just one, but see - * {@link #resolveFromSuperinterfaces(Clazz, String, String)} for details on when there might - * be multiple). + * {@link CallUtil#resolveFromSuperinterfaces(Clazz, String, String)} for details on when + * there might be multiple). */ private Set resolveInvokeSpecial(Clazz callingClass, AnyMethodrefConstant ref) { String name = ref.getName(callingClass); @@ -700,7 +699,7 @@ private Set resolveInvokeSpecial(Clazz callingClass, AnyMethodrefConstan Optional target = Optional.empty(); if ((c.getAccessFlags() & AccessConstants.INTERFACE) == 0) { // 2. (C is a class -> check superclasses transitively) - target = resolveFromSuperclasses(c, name, descriptor); + target = CallUtil.resolveFromSuperclasses(c, name, descriptor); } else { // 3. (C is an interface -> Check if java.lang.Object has a suitable method) for (java.lang.reflect.Method m : Object.class.getMethods()) { @@ -715,7 +714,7 @@ && getDescriptor(m).equals(descriptor)) { // 4. (Otherwise find maximally specific method from superinterfaces) return target .map(Collections::singleton) - .orElseGet(() -> resolveFromSuperinterfaces(c, name, descriptor)); + .orElseGet(() -> CallUtil.resolveFromSuperinterfaces(c, name, descriptor)); } /** Get the Descriptor of a {@link java.lang.reflect.Method}. */ @@ -798,7 +797,7 @@ private void handleVirtualMethods( Metrics.increaseCount(MetricType.MISSING_CLASS); } - Set targetClasses = resolveVirtual(location.clazz, referencedClass, ref); + Set targetClasses = CallUtil.resolveVirtual(location.clazz, referencedClass, ref); if (targetClasses.isEmpty()) { if (referencedClass != null) { Metrics.increaseCount(MetricType.MISSING_METHODS); @@ -822,132 +821,6 @@ private void handleVirtualMethods( } } - /** - * The invokevirtual and invokeinterface resolution algorithm, annotated - * with JVM - * spec §6.5.invokevirtual citations where appropriate, so that the specified lookup process - * can easily be compared to this implementation. - * - * @param callingClass JVM spec: "current class". - * @param thisPtrType The type of the this pointer of the call (JVM spec: - * "objectref"). - * @param ref The {@link AnyMethodrefConstant} specifying name and descriptor of the method to be - * invoked. - * @return The fully qualified names of potential call target clases (usually just one, but see - * {@link #resolveFromSuperinterfaces(Clazz, String, String)} for details on when there might - * be multiple). - */ - private Set resolveVirtual( - Clazz callingClass, Clazz thisPtrType, AnyMethodrefConstant ref) { - if (thisPtrType == null) { - return Collections.emptySet(); - } - String name = ref.getName(callingClass); - String descriptor = ref.getType(callingClass); - - // 1. + 2. (Search the class belonging to the this pointer type and all its transitive - // superclasses) - return resolveFromSuperclasses(thisPtrType, name, descriptor) - .map(Collections::singleton) - // 3. (Otherwise find maximally specific method from superinterfaces) - .orElseGet(() -> resolveFromSuperinterfaces(thisPtrType, name, descriptor)); - } - - /** - * Search for the invocation target in a specific class and recursively in all superclasses. - * - * @param start The {@link Clazz} where the lookup is to be started. - * @param name The name of the method. - * @param descriptor The method descriptor. - * @return An {@link Optional} with the fully qualified name of the class containing the target - * method, empty if it couldn't be found. - */ - private Optional resolveFromSuperclasses(Clazz start, String name, String descriptor) { - Clazz curr = start; - while (curr != null) { - Method targetMethod = curr.findMethod(name, descriptor); - if (targetMethod != null && (targetMethod.getAccessFlags() & AccessConstants.ABSTRACT) == 0) { - return Optional.of(curr.getName()); - } - - curr = curr.getSuperClass(); - } - return Optional.empty(); - } - - /** - * Search for a maximally specific default implementation in all superinterfaces of a class. This - * step is potentially unintuitive and difficult to grasp, see JVM spec - * §5.4.3.3 for more information, as well as this great blog post concerning the - * resolution pitfalls. The following is based on the information on those websites. - * - * @param start The {@link Clazz} whose superinterfaces are to be searched. - * @param name The target method name. - * @param descriptor The target method descriptor. - * @return The fully qualified name of the class(es) that contain the method to be invoked. Be - * aware that purely from a JVM point of view, this choice can be ambiguous, in which case it - * just chooses the candidate randomly. Here, we don't want to gamble, but rather want to add - * call graph edges for every possibility, if this ever happens. Javac ensures that such a - * case never occurs, but who knows how the bytecode has been generated, so this possibility - * is implemented just in case. - */ - private Set resolveFromSuperinterfaces(Clazz start, String name, String descriptor) { - Set superInterfaces = new HashSet<>(); - getSuperinterfaces(start, superInterfaces); - // Get all transitive superinterfaces that have a matching method. - Set applicableInterfaces = - superInterfaces.stream() - .filter( - i -> { - Method m = i.findMethod(name, descriptor); - return m != null - && (m.getAccessFlags() - & (AccessConstants.PRIVATE - | AccessConstants.STATIC - | AccessConstants.ABSTRACT)) - == 0; - }) - .collect(Collectors.toSet()); - - // Tricky part: Find the "maximally specific" implementation, - // i.e. the lowest applicable interface in the type hierarchy. - for (Clazz iface : new HashSet<>(applicableInterfaces)) { - superInterfaces.clear(); - getSuperinterfaces(iface, superInterfaces); - // If an applicable interface overrides another applicable interface, it is more specific than - // the - // one being overridden -> the overridden interface is no longer applicable. - superInterfaces.forEach(applicableInterfaces::remove); - } - - return applicableInterfaces.stream().map(Clazz::getName).collect(Collectors.toSet()); - } - - /** - * Get the transitive superinterfaces of a class/interface recursively. - * - * @param start The {@link Clazz} where the collection process is to be started. - * @param accumulator The current set of superinterfaces, so that only one set is constructed at - * runtime. - */ - private void getSuperinterfaces(Clazz start, Set accumulator) { - for (int i = 0; i < start.getInterfaceCount(); i++) { - Clazz iface = start.getInterface(i); - if (iface == null) { - Metrics.increaseCount(MetricType.MISSING_CLASS); - continue; - } - accumulator.add(iface); - getSuperinterfaces(iface, accumulator); - } - if (start.getSuperClass() != null) { - getSuperinterfaces(start.getSuperClass(), accumulator); - } - } - private static class CurrentClazzMethodAttribute { public final Clazz clazz; public final Method method; diff --git a/base/src/main/java/proguard/analysis/CallUtil.java b/base/src/main/java/proguard/analysis/CallUtil.java new file mode 100644 index 00000000..c72a382a --- /dev/null +++ b/base/src/main/java/proguard/analysis/CallUtil.java @@ -0,0 +1,182 @@ +package proguard.analysis; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import proguard.classfile.AccessConstants; +import proguard.classfile.Clazz; +import proguard.classfile.Method; +import proguard.classfile.MethodSignature; +import proguard.classfile.constant.AnyMethodrefConstant; + +/** Utility methods for call resolution. */ +public class CallUtil { + private CallUtil() {} + + /** + * The invokevirtual and invokeinterface resolution algorithm, annotated + * with JVM + * spec §6.5.invokevirtual citations where appropriate, so that the specified lookup process + * can easily be compared to this implementation. + * + * @param callingClass JVM spec: "current class". + * @param thisPointerType The type of the this pointer of the call (JVM spec: + * "objectref"). + * @param ref The {@link AnyMethodrefConstant} specifying name and descriptor of the method to be + * invoked. + * @return The fully qualified names of potential call target clases (usually just one, but see + * {@link #resolveFromSuperinterfaces(Clazz, String, String)} for details on when there might + * be multiple). + */ + public static Set resolveVirtual( + Clazz callingClass, Clazz thisPointerType, AnyMethodrefConstant ref) { + return resolveVirtual(thisPointerType, ref.getName(callingClass), ref.getType(callingClass)); + } + + /** + * The invokevirtual and invokeinterface resolution algorithm, annotated + * with JVM + * spec §6.5.invokevirtual citations where appropriate, so that the specified lookup process + * can easily be compared to this implementation. + * + * @param thisPointerType The type of the this pointer of the call (JVM spec: + * "objectref"). + * @param methodName The name of the invoked method. + * @param descriptor The descriptor of the invoked method. + * @return The fully qualified names of potential call target clases (usually just one, but see + * {@link #resolveFromSuperinterfaces(Clazz, String, String)} for details on when there might + * be multiple). + */ + public static Set resolveVirtual( + Clazz thisPointerType, String methodName, String descriptor) { + if (thisPointerType == null) { + return Collections.emptySet(); + } + + // 1. + 2. (Search the class belonging to the this pointer type and all its transitive + // superclasses) + return resolveFromSuperclasses(thisPointerType, methodName, descriptor) + .map(Collections::singleton) + // 3. (Otherwise find maximally specific method from superinterfaces) + .orElseGet(() -> resolveFromSuperinterfaces(thisPointerType, methodName, descriptor)); + } + + /** + * Adapter of {@link CallUtil#resolveVirtual(Clazz, String, String)} returning {@link + * MethodSignature}. + * + * @param thisPointerType The type of the this pointer of the call (JVM spec: + * "objectref"). + * @param methodName The name of the invoked method. + * @param descriptor The descriptor of the invoked method. + * @return The {@link MethodSignature}s of potential call target (usually just one, but see {@link + * #resolveFromSuperinterfaces(Clazz, String, String)} for details on when there might be + * multiple). + */ + public static Set resolveVirtualSignatures( + Clazz thisPointerType, String methodName, String descriptor) { + return resolveVirtual(thisPointerType, methodName, descriptor).stream() + .map(className -> new MethodSignature(className, methodName, descriptor)) + .collect(Collectors.toSet()); + } + + /** + * Search for the invocation target in a specific class and recursively in all superclasses. + * + * @param start The {@link Clazz} where the lookup is to be started. + * @param name The name of the method. + * @param descriptor The method descriptor. + * @return An {@link Optional} with the fully qualified name of the class containing the target + * method, empty if it couldn't be found. + */ + public static Optional resolveFromSuperclasses( + Clazz start, String name, String descriptor) { + Clazz curr = start; + while (curr != null) { + Method targetMethod = curr.findMethod(name, descriptor); + if (targetMethod != null && (targetMethod.getAccessFlags() & AccessConstants.ABSTRACT) == 0) { + return Optional.of(curr.getName()); + } + + curr = curr.getSuperClass(); + } + return Optional.empty(); + } + + /** + * Search for a maximally specific default implementation in all superinterfaces of a class. This + * step is potentially unintuitive and difficult to grasp, see JVM spec + * §5.4.3.3 for more information, as well as this great blog post concerning the + * resolution pitfalls. The following is based on the information on those websites. + * + * @param start The {@link Clazz} whose superinterfaces are to be searched. + * @param name The target method name. + * @param descriptor The target method descriptor. + * @return The fully qualified name of the class(es) that contain the method to be invoked. Be + * aware that purely from a JVM point of view, this choice can be ambiguous, in which case it + * just chooses the candidate randomly. Here, we don't want to gamble, but rather want to add + * call graph edges for every possibility, if this ever happens. Javac ensures that such a + * case never occurs, but who knows how the bytecode has been generated, so this possibility + * is implemented just in case. + */ + public static Set resolveFromSuperinterfaces( + Clazz start, String name, String descriptor) { + Set superInterfaces = new HashSet<>(); + getSuperinterfaces(start, superInterfaces); + // Get all transitive superinterfaces that have a matching method. + Set applicableInterfaces = + superInterfaces.stream() + .filter( + i -> { + Method m = i.findMethod(name, descriptor); + return m != null + && (m.getAccessFlags() + & (AccessConstants.PRIVATE + | AccessConstants.STATIC + | AccessConstants.ABSTRACT)) + == 0; + }) + .collect(Collectors.toSet()); + + // Tricky part: Find the "maximally specific" implementation, + // i.e. the lowest applicable interface in the type hierarchy. + for (Clazz iface : new HashSet<>(applicableInterfaces)) { + superInterfaces.clear(); + getSuperinterfaces(iface, superInterfaces); + // If an applicable interface overrides another applicable interface, it is more specific than + // the + // one being overridden -> the overridden interface is no longer applicable. + superInterfaces.forEach(applicableInterfaces::remove); + } + + return applicableInterfaces.stream().map(Clazz::getName).collect(Collectors.toSet()); + } + + /** + * Get the transitive superinterfaces of a class/interface recursively. + * + * @param start The {@link Clazz} where the collection process is to be started. + * @param accumulator The current set of superinterfaces, so that only one set is constructed at + * runtime. + */ + public static void getSuperinterfaces(Clazz start, Set accumulator) { + for (int i = 0; i < start.getInterfaceCount(); i++) { + Clazz iface = start.getInterface(i); + if (iface == null) { + Metrics.increaseCount(Metrics.MetricType.MISSING_CLASS); + continue; + } + accumulator.add(iface); + getSuperinterfaces(iface, accumulator); + } + if (start.getSuperClass() != null) { + getSuperinterfaces(start.getSuperClass(), accumulator); + } + } +} From 88378b4ea84c10418e89a5bac9464f6a11d2099b Mon Sep 17 00:00:00 2001 From: Tom Vandenbussche Date: Thu, 29 Aug 2024 13:54:58 +0200 Subject: [PATCH 2/2] Convert exceptions in proguard.analysis --- .../java/proguard/analysis/CallResolver.java | 9 ++- .../analysis/DominatorCalculator.java | 9 ++- .../analysis/cpa/bam/BamTransferRelation.java | 9 ++- .../cpa/defaults/StackAbstractState.java | 9 ++- ...gramLocationDependentTransferRelation.java | 10 ++- ...ceduralCfaFillerAllInstructionVisitor.java | 8 ++- .../JvmMemoryLocationTransferRelation.java | 18 +++-- .../CompositeHeapJvmAbstractState.java | 27 +++++--- .../CompositeHeapTransferRelation.java | 9 ++- .../JvmCompositeHeapExpandOperator.java | 22 +++--- .../JvmCompositeHeapReduceOperator.java | 11 +-- .../JvmReferenceTransferRelation.java | 9 ++- .../jvm/domain/taint/JvmInvokeTaintSink.java | 10 ++- .../jvm/domain/taint/JvmTaintBamCpaRun.java | 30 ++++++-- .../JvmTaintMemoryLocationBamCpaRun.java | 8 ++- .../jvm/domain/value/JvmValueBamCpaRun.java | 7 +- .../value/JvmValueTransferRelation.java | 7 +- .../jvm/domain/value/ValueAbstractState.java | 7 +- .../operators/JvmDefaultExpandOperator.java | 49 ++++++++----- .../operators/JvmDefaultReduceOperator.java | 12 ++-- .../tree/JvmShallowHeapAbstractState.java | 8 ++- .../heap/tree/JvmTreeHeapAbstractState.java | 8 ++- .../JvmTreeHeapFollowerAbstractState.java | 34 ++++++---- .../JvmTreeHeapPrincipalAbstractState.java | 34 ++++++---- .../cpa/jvm/transfer/JvmTransferRelation.java | 34 +++++++--- .../analysis/cpa/jvm/util/JvmBamCpaRun.java | 10 ++- .../exception/PartialEvaluatorException.java | 2 +- .../main/java/proguard/exception/ErrorId.java | 68 +++++++++++++++++++ .../exception/ProguardCoreException.java | 30 +++++++- .../analysis/DominatorCalculatorTest.kt | 11 +-- 30 files changed, 402 insertions(+), 117 deletions(-) diff --git a/base/src/main/java/proguard/analysis/CallResolver.java b/base/src/main/java/proguard/analysis/CallResolver.java index fc60fa4b..44a195b1 100644 --- a/base/src/main/java/proguard/analysis/CallResolver.java +++ b/base/src/main/java/proguard/analysis/CallResolver.java @@ -18,6 +18,8 @@ package proguard.analysis; +import static proguard.exception.ErrorId.ANALYSIS_CALL_RESOLVER_SELECTIVE_PARAMETER_RECONSTRUCTION_MISSING_PARAMS; + import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; @@ -75,6 +77,7 @@ import proguard.evaluation.value.TypedReferenceValue; import proguard.evaluation.value.Value; import proguard.evaluation.value.ValueFactory; +import proguard.exception.ProguardCoreException; import proguard.util.PartialEvaluatorUtils; /** @@ -253,8 +256,10 @@ public CallResolver( this.selectiveParameterReconstruction = selectiveParameterReconstruction; if (selectiveParameterReconstruction && (interestingMethods == null || interestingCallPredicates == null)) { - throw new IllegalArgumentException( - "Using selectiveParameterReconstruction requires interestingMethods and interestingCallPredicates."); + throw new ProguardCoreException.Builder( + "Using selectiveParameterReconstruction requires interestingMethods and interestingCallPredicates.", + ANALYSIS_CALL_RESOLVER_SELECTIVE_PARAMETER_RECONSTRUCTION_MISSING_PARAMS) + .build(); } this.interestingMethods = interestingMethods; this.interestingCallPredicates = interestingCallPredicates; diff --git a/base/src/main/java/proguard/analysis/DominatorCalculator.java b/base/src/main/java/proguard/analysis/DominatorCalculator.java index 4f55d8e2..cb9c287f 100644 --- a/base/src/main/java/proguard/analysis/DominatorCalculator.java +++ b/base/src/main/java/proguard/analysis/DominatorCalculator.java @@ -18,6 +18,8 @@ package proguard.analysis; +import static proguard.exception.ErrorId.ANALYSIS_DOMINATOR_CALCULATOR_NO_DOMINATOR_AT_OFFSET; + import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; @@ -34,6 +36,7 @@ import proguard.classfile.instruction.Instruction; import proguard.classfile.instruction.InstructionFactory; import proguard.classfile.instruction.SwitchInstruction; +import proguard.exception.ProguardCoreException; /** * Calculate the dominator tree of any method, making it possible to determine which instructions @@ -122,7 +125,11 @@ public DominatorCalculator(boolean ignoreExceptions) { public boolean dominates(int dominator, int inferior) { BitSet dominators = dominatorMap.get(inferior); if (dominators == null) { - throw new IllegalStateException("No dominator information known for offset " + inferior); + throw new ProguardCoreException.Builder( + "No dominator information known for offset %d", + ANALYSIS_DOMINATOR_CALCULATOR_NO_DOMINATOR_AT_OFFSET) + .errorParameters(inferior) + .build(); } return dominators.get(offsetToIndex(dominator)); } diff --git a/base/src/main/java/proguard/analysis/cpa/bam/BamTransferRelation.java b/base/src/main/java/proguard/analysis/cpa/bam/BamTransferRelation.java index 3da78b72..6da2529e 100644 --- a/base/src/main/java/proguard/analysis/cpa/bam/BamTransferRelation.java +++ b/base/src/main/java/proguard/analysis/cpa/bam/BamTransferRelation.java @@ -18,6 +18,8 @@ package proguard.analysis.cpa.bam; +import static proguard.exception.ErrorId.ANALYSIS_BAM_TRANSFER_RELATION_STATE_NOT_LOCATION_DEPENDENT; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -49,6 +51,7 @@ import proguard.analysis.datastructure.callgraph.Call; import proguard.analysis.datastructure.callgraph.SymbolicCall; import proguard.classfile.Signature; +import proguard.exception.ProguardCoreException; /** * This {@link TransferRelation} extends an analysis inter-procedurally. The transfer relation @@ -159,8 +162,10 @@ public BamTransferRelation( public Collection generateAbstractSuccessors( AbstractState abstractState, Precision precision) { if (!(abstractState instanceof ProgramLocationDependent)) { - throw new IllegalArgumentException( - "The abstract state of type " + AbstractState.class + " is not location dependent"); + throw new ProguardCoreException.Builder( + "The abstract state of type " + AbstractState.class + " is not location dependent", + ANALYSIS_BAM_TRANSFER_RELATION_STATE_NOT_LOCATION_DEPENDENT) + .build(); } CfaNodeT currentLocation = diff --git a/base/src/main/java/proguard/analysis/cpa/defaults/StackAbstractState.java b/base/src/main/java/proguard/analysis/cpa/defaults/StackAbstractState.java index dceb5664..8050f15c 100644 --- a/base/src/main/java/proguard/analysis/cpa/defaults/StackAbstractState.java +++ b/base/src/main/java/proguard/analysis/cpa/defaults/StackAbstractState.java @@ -18,7 +18,10 @@ package proguard.analysis.cpa.defaults; +import static proguard.exception.ErrorId.ANALYSIS_STACK_STATE_OPERAND_STACK_INDEX_OUT_OF_BOUNDS; + import java.util.Stack; +import proguard.exception.ProguardCoreException; /** * This {@link StackAbstractState} represents a stack of {@link LatticeAbstractState}s with the @@ -94,7 +97,11 @@ public AbstractSpaceT popOrDefault(AbstractSpaceT defaultState) { public AbstractSpaceT peek(int index) { int elementIndex = size() - 1 - index; if (elementIndex < 0) { - throw new IllegalArgumentException("Operand stack index is out of bound (" + index + ")"); + throw new ProguardCoreException.Builder( + "Operand stack index is out of bounds (%d)", + ANALYSIS_STACK_STATE_OPERAND_STACK_INDEX_OUT_OF_BOUNDS) + .errorParameters(index) + .build(); } else { return get(elementIndex); } diff --git a/base/src/main/java/proguard/analysis/cpa/interfaces/ProgramLocationDependentTransferRelation.java b/base/src/main/java/proguard/analysis/cpa/interfaces/ProgramLocationDependentTransferRelation.java index 8c2a9627..b0769324 100644 --- a/base/src/main/java/proguard/analysis/cpa/interfaces/ProgramLocationDependentTransferRelation.java +++ b/base/src/main/java/proguard/analysis/cpa/interfaces/ProgramLocationDependentTransferRelation.java @@ -18,12 +18,15 @@ package proguard.analysis.cpa.interfaces; +import static proguard.exception.ErrorId.ANALYSIS_PROGRAM_LOCATION_DEPENDENT_TRANSFER_RELATION_STATE_UNSUPPORTED; + import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import proguard.classfile.Signature; +import proguard.exception.ProguardCoreException; /** * An interface for {@link TransferRelation}s that depend on the {@link @@ -55,8 +58,11 @@ default Collection wrapAbstractSuccessorInCollection( default Collection generateAbstractSuccessors( AbstractState abstractState, Precision precision) { if (!(abstractState instanceof ProgramLocationDependent)) { - throw new IllegalArgumentException( - getClass().getName() + " does not support " + abstractState.getClass().getName()); + throw new ProguardCoreException.Builder( + "%s does not support %s", + ANALYSIS_PROGRAM_LOCATION_DEPENDENT_TRANSFER_RELATION_STATE_UNSUPPORTED) + .errorParameters(getClass().getName(), abstractState.getClass().getName()) + .build(); } ProgramLocationDependent state = (ProgramLocationDependent) abstractState; diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/cfa/visitors/JvmIntraproceduralCfaFillerAllInstructionVisitor.java b/base/src/main/java/proguard/analysis/cpa/jvm/cfa/visitors/JvmIntraproceduralCfaFillerAllInstructionVisitor.java index ac37ee65..f2b06f6d 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/cfa/visitors/JvmIntraproceduralCfaFillerAllInstructionVisitor.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/cfa/visitors/JvmIntraproceduralCfaFillerAllInstructionVisitor.java @@ -18,6 +18,8 @@ package proguard.analysis.cpa.jvm.cfa.visitors; +import static proguard.exception.ErrorId.ANALYSIS_JVM_INTRAPROCEDURAL_CFA_FILLER_ALL_INSTRUCTION_UNEXPECTED_SWITCH; + import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Optional; @@ -51,6 +53,7 @@ import proguard.classfile.instruction.TableSwitchInstruction; import proguard.classfile.instruction.VariableInstruction; import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.exception.ProguardCoreException; /** * This {@link AttributeVisitor} visits the {@link CodeAttribute} of a {@link Method} and performs @@ -410,7 +413,10 @@ private void connectSwitch( // check just because the subsequent check on type, should never happen if (!(instruction instanceof TableSwitchInstruction || instruction instanceof LookUpSwitchInstruction)) { - throw new IllegalArgumentException("Unexpected switch instruction type"); + throw new ProguardCoreException.Builder( + "Unexpected switch instruction type", + ANALYSIS_JVM_INTRAPROCEDURAL_CFA_FILLER_ALL_INSTRUCTION_UNEXPECTED_SWITCH) + .build(); } JvmCfaNode currentNode = connect(offset, clazz); diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/memory/JvmMemoryLocationTransferRelation.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/memory/JvmMemoryLocationTransferRelation.java index 1b4530b3..8ef65cac 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/memory/JvmMemoryLocationTransferRelation.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/memory/JvmMemoryLocationTransferRelation.java @@ -18,6 +18,9 @@ package proguard.analysis.cpa.jvm.domain.memory; +import static proguard.exception.ErrorId.ANALYSIS_JVM_MEMORY_LOCATION_TRANSFER_RELATION_STATE_UNSUPPORTED; +import static proguard.exception.ErrorId.ANALYSIS_JVM_MEMORY_LOCATION_TRANSFER_RELATION_TYPE_UNSUPPORTED; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -74,6 +77,7 @@ import proguard.classfile.instruction.VariableInstruction; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.ClassUtil; +import proguard.exception.ProguardCoreException; /** * The {@link JvmMemoryLocationTransferRelation} computes the backward successors of an {@link @@ -147,8 +151,11 @@ public JvmMemoryLocationTransferRelation( public Collection generateAbstractSuccessors( AbstractState abstractState, Precision precision) { if (!(abstractState instanceof JvmMemoryLocationAbstractState)) { - throw new IllegalArgumentException( - getClass().getName() + " does not support " + abstractState.getClass().getName()); + throw new ProguardCoreException.Builder( + "%s does not support %s", + ANALYSIS_JVM_MEMORY_LOCATION_TRANSFER_RELATION_STATE_UNSUPPORTED) + .errorParameters(getClass().getName(), abstractState.getClass().getName()) + .build(); } JvmMemoryLocationAbstractState state = (JvmMemoryLocationAbstractState) abstractState.copy(); @@ -537,8 +544,11 @@ private Optional createCallerLocation( } else if (memoryLocation instanceof JvmStackLocation) { return Optional.empty(); } else { - throw new IllegalStateException( - "Unsupported memory location type " + memoryLocation.getClass().getCanonicalName()); + throw new ProguardCoreException.Builder( + "Unsupported memory location type %s", + ANALYSIS_JVM_MEMORY_LOCATION_TRANSFER_RELATION_TYPE_UNSUPPORTED) + .errorParameters(memoryLocation.getClass().getCanonicalName()) + .build(); } } diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/CompositeHeapJvmAbstractState.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/CompositeHeapJvmAbstractState.java index 2ae43e4d..7d0cfd80 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/CompositeHeapJvmAbstractState.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/CompositeHeapJvmAbstractState.java @@ -18,6 +18,10 @@ package proguard.analysis.cpa.jvm.domain.reference; +import static proguard.exception.ErrorId.ANALYSIS_COMPOSITE_HEAP_JVM_COMPARE_STATE_DIFFERENT_LENGTH; +import static proguard.exception.ErrorId.ANALYSIS_COMPOSITE_HEAP_JVM_JOIN_STATE_DIFFERENT_LENGTH; +import static proguard.exception.ErrorId.ANALYSIS_COMPOSITE_HEAP_JVM_NO_REFERENCE_STATE_AT_INDEX; + import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -30,6 +34,7 @@ import proguard.analysis.cpa.jvm.state.JvmAbstractState; import proguard.analysis.cpa.jvm.state.heap.tree.JvmTreeHeapFollowerAbstractState; import proguard.classfile.MethodSignature; +import proguard.exception.ProguardCoreException; /** * This {@link AbstractWrapperState} stores a {@link JvmReferenceAbstractState} having the {@link @@ -64,10 +69,12 @@ public CompositeHeapJvmAbstractState( List>> jvmAbstractStates) { if (!(jvmAbstractStates.get(REFERENCE_STATE_INDEX) instanceof JvmReferenceAbstractState)) { - throw new IllegalArgumentException( - "The abstract state at index " - + REFERENCE_STATE_INDEX - + " must be a reference abstract state"); + throw new ProguardCoreException.Builder( + "The abstract state at index " + + REFERENCE_STATE_INDEX + + " must be a reference abstract state", + ANALYSIS_COMPOSITE_HEAP_JVM_NO_REFERENCE_STATE_AT_INDEX) + .build(); } this.jvmAbstractStates = jvmAbstractStates; } @@ -104,8 +111,10 @@ public void updateHeapDependence() { @Override public CompositeHeapJvmAbstractState join(CompositeHeapJvmAbstractState abstractState) { if (jvmAbstractStates.size() != abstractState.jvmAbstractStates.size()) { - throw new IllegalArgumentException( - "Trying to join two abstract state sequences of different lengths"); + throw new ProguardCoreException.Builder( + "Trying to join two abstract state sequences of different lengths", + ANALYSIS_COMPOSITE_HEAP_JVM_JOIN_STATE_DIFFERENT_LENGTH) + .build(); } List>> resultStates = new ArrayList<>(jvmAbstractStates.size()); @@ -121,8 +130,10 @@ public CompositeHeapJvmAbstractState join(CompositeHeapJvmAbstractState abstract @Override public boolean isLessOrEqual(CompositeHeapJvmAbstractState abstractState) { if (jvmAbstractStates.size() != abstractState.jvmAbstractStates.size()) { - throw new IllegalArgumentException( - "Trying to compare two abstract state sequences of different lengths"); + throw new ProguardCoreException.Builder( + "Trying to compare two abstract state sequences of different lengths", + ANALYSIS_COMPOSITE_HEAP_JVM_COMPARE_STATE_DIFFERENT_LENGTH) + .build(); } for (int i = 0; i < jvmAbstractStates.size(); i++) { JvmAbstractState state1 = jvmAbstractStates.get(i); diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/CompositeHeapTransferRelation.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/CompositeHeapTransferRelation.java index a34d0b8c..01a85237 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/CompositeHeapTransferRelation.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/CompositeHeapTransferRelation.java @@ -18,6 +18,8 @@ package proguard.analysis.cpa.jvm.domain.reference; +import static proguard.exception.ErrorId.ANALYSIS_COMPOSITE_TRANSFER_RELATION_STATE_UNSUPPORTED; + import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -30,6 +32,7 @@ import proguard.analysis.cpa.jvm.state.JvmAbstractState; import proguard.analysis.cpa.jvm.transfer.JvmTransferRelation; import proguard.classfile.MethodSignature; +import proguard.exception.ProguardCoreException; /** * A wrapper class around multiple {@link JvmTransferRelation}s applying them elementwise to {@link @@ -69,8 +72,10 @@ public Iterable getWrappedTransferRelations() { public CompositeHeapJvmAbstractState generateEdgeAbstractSuccessor( AbstractState abstractState, JvmCfaEdge edge, Precision precision) { if (!(abstractState instanceof CompositeHeapJvmAbstractState)) { - throw new IllegalArgumentException( - getClass().getName() + " does not support " + abstractState.getClass().getName()); + throw new ProguardCoreException.Builder( + "%s does not support %s", ANALYSIS_COMPOSITE_TRANSFER_RELATION_STATE_UNSUPPORTED) + .errorParameters(getClass().getName(), abstractState.getClass().getName()) + .build(); } CompositeHeapJvmAbstractState compositeState = (CompositeHeapJvmAbstractState) abstractState; Iterator>> diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmCompositeHeapExpandOperator.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmCompositeHeapExpandOperator.java index 2574f828..e9245ae9 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmCompositeHeapExpandOperator.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmCompositeHeapExpandOperator.java @@ -18,6 +18,9 @@ package proguard.analysis.cpa.jvm.domain.reference; +import static proguard.exception.ErrorId.ANALYSIS_JVM_COMPOSITE_HEAP_EXPAND_OPERATOR_EXIT_STATE_UNSUPPORTED; +import static proguard.exception.ErrorId.ANALYSIS_JVM_COMPOSITE_HEAP_EXPAND_OPERATOR_INITIAL_STATE_UNSUPPORTED; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -29,6 +32,7 @@ import proguard.analysis.cpa.jvm.state.JvmAbstractState; import proguard.analysis.datastructure.callgraph.Call; import proguard.classfile.MethodSignature; +import proguard.exception.ProguardCoreException; /** * A wrapper class around multiple {@link ExpandOperator}s applying them elementwise to {@link @@ -65,17 +69,19 @@ public CompositeHeapJvmAbstractState expand( JvmCfaNode blockEntryNode, Call call) { if (!(expandedInitialState instanceof CompositeHeapJvmAbstractState)) { - throw new IllegalArgumentException( - "The operator works on composite JVM states, states of type " - + expandedInitialState.getClass().getName() - + " are not supported"); + throw new ProguardCoreException.Builder( + "The operator works on composite JVM states, states of type %s are not supported", + ANALYSIS_JVM_COMPOSITE_HEAP_EXPAND_OPERATOR_INITIAL_STATE_UNSUPPORTED) + .errorParameters(expandedInitialState.getClass().getName()) + .build(); } if (!(reducedExitState instanceof CompositeHeapJvmAbstractState)) { - throw new IllegalArgumentException( - "The operator works on composite JVM states, states of type " - + reducedExitState.getClass().getName() - + " are not supported"); + throw new ProguardCoreException.Builder( + "The operator works on composite JVM states, states of type %s are not supported", + ANALYSIS_JVM_COMPOSITE_HEAP_EXPAND_OPERATOR_EXIT_STATE_UNSUPPORTED) + .errorParameters(reducedExitState.getClass().getName()) + .build(); } List>> expandedStates = diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmCompositeHeapReduceOperator.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmCompositeHeapReduceOperator.java index f0307d28..7cb33cc9 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmCompositeHeapReduceOperator.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmCompositeHeapReduceOperator.java @@ -19,6 +19,7 @@ package proguard.analysis.cpa.jvm.domain.reference; import static proguard.analysis.cpa.jvm.domain.reference.CompositeHeapJvmAbstractState.REFERENCE_STATE_INDEX; +import static proguard.exception.ErrorId.ANALYSIS_JVM_COMPOSITE_HEAP_REDUCE_OPERATOR_STATE_UNSUPPORTED; import java.util.ArrayList; import java.util.List; @@ -31,6 +32,7 @@ import proguard.analysis.cpa.jvm.state.heap.tree.JvmTreeHeapFollowerAbstractState; import proguard.analysis.datastructure.callgraph.Call; import proguard.classfile.MethodSignature; +import proguard.exception.ProguardCoreException; /** * A wrapper class around multiple {@link ReduceOperator}s applying them elementwise to {@link @@ -65,10 +67,11 @@ public JvmCompositeHeapReduceOperator( public CompositeHeapJvmAbstractState reduce( AbstractState expandedInitialState, JvmCfaNode blockEntryNode, Call call) { if (!(expandedInitialState instanceof CompositeHeapJvmAbstractState)) { - throw new IllegalArgumentException( - "The operator works on composite JVM states, states of type " - + expandedInitialState.getClass().getName() - + " are not supported"); + throw new ProguardCoreException.Builder( + "The operator works on composite JVM states, states of type %s are not supported", + ANALYSIS_JVM_COMPOSITE_HEAP_REDUCE_OPERATOR_STATE_UNSUPPORTED) + .errorParameters(expandedInitialState.getClass().getName()) + .build(); } int stateSize = diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmReferenceTransferRelation.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmReferenceTransferRelation.java index 77dbdac5..1e5b372f 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmReferenceTransferRelation.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/reference/JvmReferenceTransferRelation.java @@ -18,6 +18,8 @@ package proguard.analysis.cpa.jvm.domain.reference; +import static proguard.exception.ErrorId.ANALYSIS_JVM_REFERENCE_TRANSFER_RELATION_STATE_UNSUPPORTED; + import java.util.Collection; import java.util.List; import proguard.analysis.cpa.defaults.SetAbstractState; @@ -30,6 +32,7 @@ import proguard.analysis.datastructure.callgraph.Call; import proguard.classfile.instruction.Instruction; import proguard.classfile.util.ClassUtil; +import proguard.exception.ProguardCoreException; /** * This {@link JvmTransferRelation} propagates reference values, destroys references upon arithmetic @@ -45,8 +48,10 @@ public class JvmReferenceTransferRelation extends JvmTransferRelation createExpandOpera return new JvmCompositeHeapExpandOperator( Arrays.asList(new JvmReferenceExpandOperator(cfa, reduceHeap), jvmExpandOperator)); default: - throw new IllegalArgumentException( - "Heap model " + heapModel.name() + " is not supported by " + getClass().getName()); + throw new ProguardCoreException.Builder( + "Heap model %s is not supported by %s", + ANALYSIS_JVM_TAINT_BAM_CPA_RUN_EXPAND_OPERATOR_HEAP_MODEL_UNSUPPORTED) + .errorParameters(heapModel.name(), getClass().getName()) + .build(); } } @@ -237,7 +249,10 @@ public Collection getInitialStates() { followerHeapNodeMapAbstractStateFactory), staticFieldMapAbstractStateFactory.createMapAbstractState())))); default: - throw new IllegalStateException("Invalid heap model: " + heapModel.name()); + throw new ProguardCoreException.Builder( + "Invalid heap model: %s", ANALYSIS_JVM_TAINT_BAM_CPA_RUN_HEAP_MODEL_INVALID) + .errorParameters(heapModel.name()) + .build(); } } @@ -270,7 +285,10 @@ public static class Builder extends JvmBamCpaRun.Builder { @Override public JvmTaintBamCpaRun build() { if (cfa == null || mainSignature == null) { - throw new IllegalStateException("CFA and the main signature must be set"); + throw new ProguardCoreException.Builder( + "CFA and the main signature must be set", + ANALYSIS_JVM_TAINT_BAM_CPA_RUN_CFA_OR_MAIN_SIGNATURE_NOT_SET) + .build(); } return new JvmTaintBamCpaRun<>( cfa, diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/taint/JvmTaintMemoryLocationBamCpaRun.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/taint/JvmTaintMemoryLocationBamCpaRun.java index 20e16945..dd66896a 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/taint/JvmTaintMemoryLocationBamCpaRun.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/taint/JvmTaintMemoryLocationBamCpaRun.java @@ -18,6 +18,8 @@ package proguard.analysis.cpa.jvm.domain.taint; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TAINT_MEMORY_LOCATION_BAM_CPA_RUN_CFA_OR_MAIN_SIGNATURE_NOT_SET; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -53,6 +55,7 @@ import proguard.analysis.cpa.util.StateNames; import proguard.classfile.MethodSignature; import proguard.classfile.Signature; +import proguard.exception.ProguardCoreException; /** This run wraps the execution of BAM {@link JvmMemoryLocationCpa}. */ public class JvmTaintMemoryLocationBamCpaRun @@ -333,7 +336,10 @@ public static class Builder { /** Returns the {@link JvmTaintMemoryLocationBamCpaRun} for given parameters. */ public JvmTaintMemoryLocationBamCpaRun build() { if (cfa == null || mainSignature == null) { - throw new IllegalStateException("CFA and the main signature must be set"); + throw new ProguardCoreException.Builder( + "CFA and the main signature must be set", + ANALYSIS_JVM_TAINT_MEMORY_LOCATION_BAM_CPA_RUN_CFA_OR_MAIN_SIGNATURE_NOT_SET) + .build(); } return new JvmTaintMemoryLocationBamCpaRun( cfa, diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/JvmValueBamCpaRun.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/JvmValueBamCpaRun.java index 1164add0..05daf6ba 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/JvmValueBamCpaRun.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/JvmValueBamCpaRun.java @@ -2,6 +2,7 @@ import static java.util.Collections.singletonList; import static proguard.analysis.cpa.jvm.domain.value.ValueAbstractState.UNKNOWN; +import static proguard.exception.ErrorId.ANALYSIS_JVM_VALUE_BAM_CPA_RUN_SET_CFA_UNSUPPORTED; import java.util.Collection; import proguard.analysis.cpa.bam.ExpandOperator; @@ -33,6 +34,7 @@ import proguard.evaluation.ExecutingInvocationUnit; import proguard.evaluation.value.ParticularValueFactory; import proguard.evaluation.value.ValueFactory; +import proguard.exception.ProguardCoreException; /** * This run wraps the execution of BAM JVM Value Analysis CPA (see {@link JvmValueAbstractState}). @@ -164,7 +166,10 @@ public Builder setCfa(JvmCfa cfa) { // Don't allow setting the CFA here because it could // result in a different CFA than the one used for the default // ValueFactory. - throw new UnsupportedOperationException("CFA should only be set via the Builder constructor"); + throw new ProguardCoreException.Builder( + "CFA should only be set via the Builder constructor", + ANALYSIS_JVM_VALUE_BAM_CPA_RUN_SET_CFA_UNSUPPORTED) + .build(); } public Builder setMainSignature(MethodSignature mainSignature) { diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/JvmValueTransferRelation.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/JvmValueTransferRelation.java index e7307873..d22d46fa 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/JvmValueTransferRelation.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/JvmValueTransferRelation.java @@ -4,6 +4,7 @@ import static proguard.classfile.TypeConstants.VOID; import static proguard.classfile.util.ClassUtil.internalMethodReturnType; import static proguard.classfile.util.ClassUtil.isInternalCategory2Type; +import static proguard.exception.ErrorId.ANALYSIS_JVM_VALUE_TRANSFER_RELATION_INCORRECT_PARAMETER_COUNT; import java.util.Arrays; import java.util.Collection; @@ -32,6 +33,7 @@ import proguard.evaluation.value.Value; import proguard.evaluation.value.ValueFactory; import proguard.evaluation.value.object.AnalyzedObjectFactory; +import proguard.exception.ProguardCoreException; /** A {@link JvmTransferRelation} that tracks values. */ public class JvmValueTransferRelation extends JvmTransferRelation { @@ -213,7 +215,10 @@ private void executeMethod( if (operandsArray.length != ClassUtil.internalMethodParameterCount( call.getTarget().descriptor.toString(), call.isStatic())) { - throw new IllegalStateException("Unexpected number of parameters"); + throw new ProguardCoreException.Builder( + "Unexpected number of parameters", + ANALYSIS_JVM_VALUE_TRANSFER_RELATION_INCORRECT_PARAMETER_COUNT) + .build(); } MethodResult result = null; diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/ValueAbstractState.java b/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/ValueAbstractState.java index ada84e8c..814e686c 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/ValueAbstractState.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/domain/value/ValueAbstractState.java @@ -22,6 +22,7 @@ import static proguard.classfile.ClassConstants.TYPE_JAVA_LANG_STRING_BUFFER; import static proguard.classfile.ClassConstants.TYPE_JAVA_LANG_STRING_BUILDER; import static proguard.evaluation.value.BasicValueFactory.UNKNOWN_VALUE; +import static proguard.exception.ErrorId.ANALYSIS_VALUE_ABSTRACT_STATE_CONDITION_UNCHECKED; import java.util.Objects; import org.apache.logging.log4j.LogManager; @@ -31,6 +32,7 @@ import proguard.evaluation.value.IdentifiedReferenceValue; import proguard.evaluation.value.TypedReferenceValue; import proguard.evaluation.value.Value; +import proguard.exception.ProguardCoreException; /** * An {@link AbstractState} for tracking JVM values. @@ -124,7 +126,10 @@ public boolean equals(Object o) { Object objectB = that.value.referenceValue().value(); if (objectA == null && objectB == null) { - throw new IllegalStateException("This condition should have been already checked"); + throw new ProguardCoreException.Builder( + "This condition should already have been checked", + ANALYSIS_VALUE_ABSTRACT_STATE_CONDITION_UNCHECKED) + .build(); } if (objectA == null || objectB == null) { return false; diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/operators/JvmDefaultExpandOperator.java b/base/src/main/java/proguard/analysis/cpa/jvm/operators/JvmDefaultExpandOperator.java index fa016d6d..5bb74026 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/operators/JvmDefaultExpandOperator.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/operators/JvmDefaultExpandOperator.java @@ -18,6 +18,12 @@ package proguard.analysis.cpa.jvm.operators; +import static proguard.exception.ErrorId.ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_EXIT_NODE_EXPECTED; +import static proguard.exception.ErrorId.ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_EXIT_STATE_UNSUPPORTED; +import static proguard.exception.ErrorId.ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_INITIAL_STATE_UNSUPPORTED; +import static proguard.exception.ErrorId.ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_MISSING_EXPECTED_CATCH_NODE_EXPECTED; +import static proguard.exception.ErrorId.ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_RETURN_INSTRUCTION_EXPECTED; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -45,6 +51,7 @@ import proguard.classfile.attribute.visitor.AllAttributeVisitor; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.instruction.Instruction; +import proguard.exception.ProguardCoreException; /** * This {@link ExpandOperator} simulates the JVM behavior on a method exit. @@ -98,17 +105,19 @@ public JvmAbstractState expand( Call call) { if (!(expandedInitialState instanceof JvmAbstractState)) { - throw new IllegalArgumentException( - "The operator works on JVM states, states of type " - + expandedInitialState.getClass().getName() - + " are not supported"); + throw new ProguardCoreException.Builder( + "The operator works on JVM states, states of type %s are not supported", + ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_INITIAL_STATE_UNSUPPORTED) + .errorParameters(expandedInitialState.getClass().getName()) + .build(); } if (!(reducedExitState instanceof JvmAbstractState)) { - throw new IllegalArgumentException( - "The operator works on JVM states, states of type " - + reducedExitState.getClass().getName() - + " are not supported"); + throw new ProguardCoreException.Builder( + "The operator works on JVM states, states of type %s are not supported", + ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_EXIT_STATE_UNSUPPORTED) + .errorParameters(reducedExitState.getClass().getName()) + .build(); } JvmCfaNode exitNode = ((JvmAbstractState) reducedExitState).getProgramLocation(); @@ -144,8 +153,10 @@ public JvmAbstractState expand( JvmCfaEdge returnEdge = exitNode.getEnteringEdges().get(0); if (!InstructionClassifier.isReturn( ((JvmInstructionCfaEdge) returnEdge).getInstruction().opcode)) { - throw new IllegalStateException( - "The entering edges into the return node should be return instructions"); + throw new ProguardCoreException.Builder( + "The entering edges into the return node should be return instructions", + ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_RETURN_INSTRUCTION_EXPECTED) + .build(); } Instruction returnInstruction = ((JvmInstructionCfaEdge) returnEdge).getInstruction(); @@ -182,12 +193,11 @@ public JvmAbstractState expand( return returnState; } - throw new IllegalStateException( - "The node of " - + exitNode.getSignature() - + " at offset " - + exitNode.getOffset() - + " is not an exit node"); + throw new ProguardCoreException.Builder( + "The node of %s at offset %d is not an exit node", + ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_EXIT_NODE_EXPECTED) + .errorParameters(exitNode.getSignature(), exitNode.getOffset()) + .build(); } /** Calculates the returned state. Can be overridden to handle special behavior. */ @@ -240,8 +250,11 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt cfa.getFunctionCatchNode( (MethodSignature) call.caller.signature, firstCatch.get().u2handlerPC); if (firstCatchNode == null) { - throw new IllegalStateException( - "Missing expected catch node in CFA for method " + call.caller.signature); + throw new ProguardCoreException.Builder( + "Missing expected catch node in CFA for method %s", + ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_MISSING_EXPECTED_CATCH_NODE_EXPECTED) + .errorParameters(call.caller.signature) + .build(); } nextNode = firstCatchNode; diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/operators/JvmDefaultReduceOperator.java b/base/src/main/java/proguard/analysis/cpa/jvm/operators/JvmDefaultReduceOperator.java index d17162f1..bdd5982d 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/operators/JvmDefaultReduceOperator.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/operators/JvmDefaultReduceOperator.java @@ -18,6 +18,8 @@ package proguard.analysis.cpa.jvm.operators; +import static proguard.exception.ErrorId.ANALYSIS_JVM_DEFAULT_REDUCE_OPERATOR_STATE_UNSUPPORTED; + import java.util.ListIterator; import proguard.analysis.cpa.bam.ReduceOperator; import proguard.analysis.cpa.defaults.LatticeAbstractState; @@ -34,6 +36,7 @@ import proguard.analysis.datastructure.callgraph.Call; import proguard.classfile.MethodSignature; import proguard.classfile.util.ClassUtil; +import proguard.exception.ProguardCoreException; /** * This {@link ReduceOperator} simulates the JVM behavior on a method call. It takes a clone of the @@ -69,10 +72,11 @@ public JvmAbstractState reduce( AbstractState expandedInitialState, JvmCfaNode blockEntryNode, Call call) { if (!(expandedInitialState instanceof JvmAbstractState)) { - throw new IllegalArgumentException( - "The operator works on JVM states, states of type " - + expandedInitialState.getClass().getName() - + " are not supported"); + throw new ProguardCoreException.Builder( + "The operator works on JVM states, states of type %s are not supported", + ANALYSIS_JVM_DEFAULT_REDUCE_OPERATOR_STATE_UNSUPPORTED) + .errorParameters(expandedInitialState.getClass().getName()) + .build(); } JvmAbstractState initialJvmState = diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmShallowHeapAbstractState.java b/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmShallowHeapAbstractState.java index 0da189b2..d4c7a2e2 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmShallowHeapAbstractState.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmShallowHeapAbstractState.java @@ -18,6 +18,8 @@ package proguard.analysis.cpa.jvm.state.heap.tree; +import static proguard.exception.ErrorId.ANALYSIS_JVM_SHALLOW_HEAP_STATE_INCOMPATIBLE; + import java.util.List; import java.util.Objects; import java.util.Set; @@ -27,6 +29,7 @@ import proguard.analysis.cpa.defaults.MapAbstractState; import proguard.analysis.cpa.jvm.cfa.nodes.JvmCfaNode; import proguard.analysis.cpa.jvm.state.heap.JvmHeapAbstractState; +import proguard.exception.ProguardCoreException; /** * A shallow heap models objects as atomic abstract states thus having only one level of depth. @@ -81,7 +84,10 @@ public void reduce(Set referencesToKeep) { @Override public void expand(JvmHeapAbstractState otherState) { if (!(otherState instanceof JvmShallowHeapAbstractState)) { - throw new IllegalArgumentException("The other state should be a JvmShallowHeapAbstractState"); + throw new ProguardCoreException.Builder( + "The other state should be a JvmShallowHeapAbstractState", + ANALYSIS_JVM_SHALLOW_HEAP_STATE_INCOMPATIBLE) + .build(); } ((JvmShallowHeapAbstractState) otherState) diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapAbstractState.java b/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapAbstractState.java index 6fa1dfec..1578622b 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapAbstractState.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapAbstractState.java @@ -18,12 +18,15 @@ package proguard.analysis.cpa.jvm.state.heap.tree; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TREE_HEAP_STATE_INCOMPATIBLE; + import proguard.analysis.cpa.defaults.LatticeAbstractState; import proguard.analysis.cpa.defaults.MapAbstractState; import proguard.analysis.cpa.defaults.SetAbstractState; import proguard.analysis.cpa.jvm.domain.reference.Reference; import proguard.analysis.cpa.jvm.state.heap.JvmHeapAbstractState; import proguard.analysis.cpa.state.MapAbstractStateFactory; +import proguard.exception.ProguardCoreException; /** * The tree heap model represents the memory as a map from references to objects or arrays ({@link @@ -150,7 +153,10 @@ public HeapNode getHeapNode(Reference reference) { @Override public void expand(JvmHeapAbstractState otherState) { if (!(otherState instanceof JvmTreeHeapAbstractState)) { - throw new IllegalArgumentException("The other state should be a JvmTreeHeapAbstractState"); + throw new ProguardCoreException.Builder( + "The other state should be a JvmTreeHeapAbstractState", + ANALYSIS_JVM_TREE_HEAP_STATE_INCOMPATIBLE) + .build(); } ((JvmTreeHeapAbstractState) otherState) diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapFollowerAbstractState.java b/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapFollowerAbstractState.java index e8e3f016..5a81756e 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapFollowerAbstractState.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapFollowerAbstractState.java @@ -18,6 +18,11 @@ package proguard.analysis.cpa.jvm.state.heap.tree; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TREE_HEAP_FOLLOWER_ARRAY_GET_UNSUPPORTED_REFERENCE_TYPE; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TREE_HEAP_FOLLOWER_ARRAY_SET_UNSUPPORTED_REFERENCE_TYPE; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TREE_HEAP_FOLLOWER_GET_UNSUPPORTED_REFERENCE_TYPE; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TREE_HEAP_FOLLOWER_SET_UNSUPPORTED_REFERENCE_TYPE; + import java.util.List; import java.util.Map.Entry; import java.util.Set; @@ -31,6 +36,7 @@ import proguard.analysis.cpa.jvm.state.heap.JvmHeapAbstractState; import proguard.analysis.cpa.jvm.witness.JvmMemoryLocation; import proguard.analysis.cpa.state.MapAbstractStateFactory; +import proguard.exception.ProguardCoreException; /** * This is a heap model for analyses that need to track the actual content of heap objects. This @@ -80,10 +86,11 @@ public StateT getFieldOrDefault(T object, String fqn, StateT defaultValue) { if (object instanceof SetAbstractState) { return getField((SetAbstractState) object, fqn, defaultValue); } - throw new IllegalStateException( - String.format( + throw new ProguardCoreException.Builder( "%s does not support %s as reference type", - getClass().getName(), object.getClass().getName())); + ANALYSIS_JVM_TREE_HEAP_FOLLOWER_GET_UNSUPPORTED_REFERENCE_TYPE) + .errorParameters(getClass().getName(), object.getClass().getName()) + .build(); } @Override @@ -96,10 +103,11 @@ public void setField(T object, String fqn, StateT value) { assignField((SetAbstractState) object, fqn, value); return; } - throw new IllegalStateException( - String.format( + throw new ProguardCoreException.Builder( "%s does not support %s as reference type", - getClass().getName(), object.getClass().getName())); + ANALYSIS_JVM_TREE_HEAP_FOLLOWER_SET_UNSUPPORTED_REFERENCE_TYPE) + .errorParameters(getClass().getName(), object.getClass().getName()) + .build(); } @Override @@ -111,10 +119,11 @@ public StateT getArrayElementOrDefault(T array, StateT index, StateT default if (array instanceof SetAbstractState) { return getArrayElementOrDefault((SetAbstractState) array, index, defaultValue); } - throw new IllegalStateException( - String.format( + throw new ProguardCoreException.Builder( "%s does not support %s as reference type", - getClass().getName(), array.getClass().getName())); + ANALYSIS_JVM_TREE_HEAP_FOLLOWER_ARRAY_GET_UNSUPPORTED_REFERENCE_TYPE) + .errorParameters(getClass().getName(), array.getClass().getName()) + .build(); } @Override @@ -127,10 +136,11 @@ public void setArrayElement(T array, StateT index, StateT value) { setArrayElement((SetAbstractState) array, index, value); return; } - throw new IllegalStateException( - String.format( + throw new ProguardCoreException.Builder( "%s does not support %s as reference type", - getClass().getName(), array.getClass().getName())); + ANALYSIS_JVM_TREE_HEAP_FOLLOWER_ARRAY_SET_UNSUPPORTED_REFERENCE_TYPE) + .errorParameters(getClass().getName(), array.getClass().getName()) + .build(); } @Override diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapPrincipalAbstractState.java b/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapPrincipalAbstractState.java index cc326e5c..8b8bea23 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapPrincipalAbstractState.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/state/heap/tree/JvmTreeHeapPrincipalAbstractState.java @@ -18,6 +18,11 @@ package proguard.analysis.cpa.jvm.state.heap.tree; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_ARRAY_GET_UNSUPPORTED_REFERENCE_TYPE; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_ARRAY_SET_UNSUPPORTED_REFERENCE_TYPE; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_GET_UNSUPPORTED_REFERENCE_TYPE; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_SET_UNSUPPORTED_REFERENCE_TYPE; + import java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; @@ -33,6 +38,7 @@ import proguard.analysis.cpa.jvm.witness.JvmStackLocation; import proguard.analysis.cpa.jvm.witness.JvmStaticFieldLocation; import proguard.analysis.cpa.state.MapAbstractStateFactory; +import proguard.exception.ProguardCoreException; /** * This is a self-sufficient heap model in the sense that it contains references necessary for @@ -84,10 +90,11 @@ private JvmTreeHeapPrincipalAbstractState( public SetAbstractState getFieldOrDefault( T object, String fqn, SetAbstractState defaultValue) { if (!(object instanceof SetAbstractState)) { - throw new IllegalStateException( - String.format( + throw new ProguardCoreException.Builder( "%s does not support %s as reference type", - getClass().getName(), object.getClass().getName())); + ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_GET_UNSUPPORTED_REFERENCE_TYPE) + .errorParameters(getClass().getName(), object.getClass().getName()) + .build(); } return ((SetAbstractState) object) .stream() @@ -107,10 +114,11 @@ public SetAbstractState getFieldOrDefault( @Override public void setField(T object, String fqn, SetAbstractState value) { if (!(object instanceof SetAbstractState)) { - throw new IllegalStateException( - String.format( + throw new ProguardCoreException.Builder( "%s does not support %s as reference type", - getClass().getName(), object.getClass().getName())); + ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_SET_UNSUPPORTED_REFERENCE_TYPE) + .errorParameters(getClass().getName(), object.getClass().getName()) + .build(); } SetAbstractState objectReference = (SetAbstractState) object; if (objectReference.size() <= 1) { @@ -140,10 +148,11 @@ public void setField(T object, String fqn, SetAbstractState value public SetAbstractState getArrayElementOrDefault( T array, SetAbstractState index, SetAbstractState defaultValue) { if (!(array instanceof SetAbstractState)) { - throw new IllegalStateException( - String.format( + throw new ProguardCoreException.Builder( "%s does not support %s as reference type", - getClass().getName(), array.getClass().getName())); + ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_ARRAY_GET_UNSUPPORTED_REFERENCE_TYPE) + .errorParameters(getClass().getName(), array.getClass().getName()) + .build(); } return ((SetAbstractState) array) .stream() @@ -164,10 +173,11 @@ public SetAbstractState getArrayElementOrDefault( public void setArrayElement( T array, SetAbstractState index, SetAbstractState value) { if (!(array instanceof SetAbstractState)) { - throw new IllegalStateException( - String.format( + throw new ProguardCoreException.Builder( "%s does not support %s as reference type", - getClass().getName(), array.getClass().getName())); + ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_ARRAY_SET_UNSUPPORTED_REFERENCE_TYPE) + .errorParameters(getClass().getName(), array.getClass().getName()) + .build(); } ((SetAbstractState) array) .forEach( diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/transfer/JvmTransferRelation.java b/base/src/main/java/proguard/analysis/cpa/jvm/transfer/JvmTransferRelation.java index a9652614..064e6e64 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/transfer/JvmTransferRelation.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/transfer/JvmTransferRelation.java @@ -21,8 +21,11 @@ import static proguard.classfile.ClassConstants.TYPE_JAVA_LANG_STRING; import static proguard.classfile.util.ClassUtil.internalTypeFromClassName; import static proguard.classfile.util.ClassUtil.isExtendable; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TRANSFER_RELATION_CONSTANT_INSTRUCTION_VISITOR_OPCODE_UNSUPPORTED; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TRANSFER_RELATION_INSTRUCTION_PUSH_COUNT_HIGHER_THAN_TWO; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TRANSFER_RELATION_STATE_UNSUPPORTED; +import static proguard.exception.ErrorId.ANALYSIS_JVM_TRANSFER_RELATION_UNEXPECTED_UNKNOWN_SIGNATURE; -import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -66,6 +69,7 @@ import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.ClassUtil; import proguard.evaluation.value.Value; +import proguard.exception.ProguardCoreException; /** * The {@link JvmTransferRelation} computes the successors of an {@link JvmAbstractState} for a @@ -83,8 +87,10 @@ public abstract class JvmTransferRelation state = (JvmAbstractState) abstractState; JvmAbstractState successor = state.copy(); @@ -476,9 +482,11 @@ public void visitSimpleInstruction( int resultCount = simpleInstruction.stackPushCount(clazz); if (resultCount > 2) { - throw new IllegalStateException( - "No instruction with more than 2 push count should be handled here. Instruction: " - + simpleInstruction); + throw new ProguardCoreException.Builder( + "No instruction with push count higher than 2 should be handled here. Instruction: %s", + ANALYSIS_JVM_TRANSFER_RELATION_INSTRUCTION_PUSH_COUNT_HIGHER_THAN_TWO) + .errorParameters(simpleInstruction) + .build(); } if (resultCount == 2) { abstractState.push(getAbstractDefault()); @@ -599,7 +607,10 @@ public void visitConstantInstruction( MethodSignature calleeSignature = CallResolver.quickResolve(constantInstruction, (ProgramClass) clazz); if (calleeSignature.equals(MethodSignature.UNKNOWN)) { - throw new IllegalStateException("Unexpected unknown signature"); + throw new ProguardCoreException.Builder( + "Unexpected unknown signature", + ANALYSIS_JVM_TRANSFER_RELATION_UNEXPECTED_UNKNOWN_SIGNATURE) + .build(); } processCall( abstractState, @@ -652,10 +663,11 @@ public void visitConstantInstruction( abstractState.push(handleCheckCast(abstractState.pop(), constantLookupVisitor.result)); break; default: // should never happen - throw new InvalidParameterException( - "The opcode " - + constantInstruction.opcode - + " is not supported by the constant instruction visitor"); + throw new ProguardCoreException.Builder( + "The opcode %02X is not supported by the constant instruction visitor", + ANALYSIS_JVM_TRANSFER_RELATION_CONSTANT_INSTRUCTION_VISITOR_OPCODE_UNSUPPORTED) + .errorParameters(constantInstruction.opcode) + .build(); } } diff --git a/base/src/main/java/proguard/analysis/cpa/jvm/util/JvmBamCpaRun.java b/base/src/main/java/proguard/analysis/cpa/jvm/util/JvmBamCpaRun.java index 4f23f2c9..1cf30e16 100644 --- a/base/src/main/java/proguard/analysis/cpa/jvm/util/JvmBamCpaRun.java +++ b/base/src/main/java/proguard/analysis/cpa/jvm/util/JvmBamCpaRun.java @@ -18,6 +18,8 @@ package proguard.analysis.cpa.jvm.util; +import static proguard.exception.ErrorId.ANALYSIS_JVM_BAM_CPA_RUN_UNSUPPORTED_HEAP_MODEL; + import java.util.Arrays; import proguard.analysis.cpa.bam.ReduceOperator; import proguard.analysis.cpa.defaults.BamCpaRun; @@ -36,6 +38,7 @@ import proguard.analysis.cpa.jvm.operators.JvmDefaultReduceOperator; import proguard.analysis.cpa.jvm.state.heap.HeapModel; import proguard.classfile.MethodSignature; +import proguard.exception.ProguardCoreException; /** * A JVM instance of {@link BamCpaRun} uses a reached set optimized for program location-dependent @@ -104,8 +107,11 @@ public ReduceOperator createReduceOpera return new JvmCompositeHeapReduceOperator( Arrays.asList(new JvmReferenceReduceOperator(reduceHeap), jvmReduceOperator)); default: - throw new IllegalArgumentException( - "Heap model " + heapModel.name() + " is not supported by " + getClass().getName()); + throw new ProguardCoreException.Builder( + "Heap model %s is not supported by %s", + ANALYSIS_JVM_BAM_CPA_RUN_UNSUPPORTED_HEAP_MODEL) + .errorParameters(heapModel.name(), getClass().getName()) + .build(); } } diff --git a/base/src/main/java/proguard/evaluation/exception/PartialEvaluatorException.java b/base/src/main/java/proguard/evaluation/exception/PartialEvaluatorException.java index 69ad2c46..5206479b 100644 --- a/base/src/main/java/proguard/evaluation/exception/PartialEvaluatorException.java +++ b/base/src/main/java/proguard/evaluation/exception/PartialEvaluatorException.java @@ -17,7 +17,7 @@ public PartialEvaluatorException( Method method, String message, String... errorParameters) { - super(componentErrorId, cause, message, errorParameters); + super(componentErrorId, cause, message, (Object[]) errorParameters); this.clazz = clazz; this.method = method; } diff --git a/base/src/main/java/proguard/exception/ErrorId.java b/base/src/main/java/proguard/exception/ErrorId.java index 12fdbea4..345d2c84 100644 --- a/base/src/main/java/proguard/exception/ErrorId.java +++ b/base/src/main/java/proguard/exception/ErrorId.java @@ -54,6 +54,74 @@ public final class ErrorId { // Proguard Util Exceptions public static final int WILDCARD_WRONG_INDEX = 8_000; + /** + * Group of errors. + * + * @see proguard.analysis + */ + public static final int ANALYSIS_JVM_TREE_HEAP_FOLLOWER_GET_UNSUPPORTED_REFERENCE_TYPE = 9_001; + + public static final int ANALYSIS_JVM_TREE_HEAP_FOLLOWER_SET_UNSUPPORTED_REFERENCE_TYPE = 9_002; + public static final int ANALYSIS_JVM_TREE_HEAP_FOLLOWER_ARRAY_GET_UNSUPPORTED_REFERENCE_TYPE = + 9_003; + public static final int ANALYSIS_JVM_TREE_HEAP_FOLLOWER_ARRAY_SET_UNSUPPORTED_REFERENCE_TYPE = + 9_004; + public static final int ANALYSIS_JVM_BAM_CPA_RUN_UNSUPPORTED_HEAP_MODEL = 9_005; + public static final int ANALYSIS_CALL_RESOLVER_SELECTIVE_PARAMETER_RECONSTRUCTION_MISSING_PARAMS = + 9_006; + public static final int ANALYSIS_JVM_SHALLOW_HEAP_STATE_INCOMPATIBLE = 9_007; + public static final int ANALYSIS_DOMINATOR_CALCULATOR_NO_DOMINATOR_AT_OFFSET = 9_008; + public static final int ANALYSIS_BAM_TRANSFER_RELATION_STATE_NOT_LOCATION_DEPENDENT = 9_009; + public static final int ANALYSIS_STACK_STATE_OPERAND_STACK_INDEX_OUT_OF_BOUNDS = 9_010; + public static final int ANALYSIS_PROGRAM_LOCATION_DEPENDENT_TRANSFER_RELATION_STATE_UNSUPPORTED = + 9_011; + public static final int + ANALYSIS_JVM_INTRAPROCEDURAL_CFA_FILLER_ALL_INSTRUCTION_UNEXPECTED_SWITCH = 9_012; + public static final int ANALYSIS_JVM_MEMORY_LOCATION_TRANSFER_RELATION_STATE_UNSUPPORTED = 9_013; + public static final int ANALYSIS_JVM_MEMORY_LOCATION_TRANSFER_RELATION_TYPE_UNSUPPORTED = 9_014; + public static final int ANALYSIS_COMPOSITE_HEAP_JVM_NO_REFERENCE_STATE_AT_INDEX = 9_015; + public static final int ANALYSIS_COMPOSITE_HEAP_JVM_JOIN_STATE_DIFFERENT_LENGTH = 9_016; + public static final int ANALYSIS_COMPOSITE_HEAP_JVM_COMPARE_STATE_DIFFERENT_LENGTH = 9_017; + public static final int ANALYSIS_COMPOSITE_TRANSFER_RELATION_STATE_UNSUPPORTED = 9_018; + public static final int ANALYSIS_JVM_COMPOSITE_HEAP_EXPAND_OPERATOR_INITIAL_STATE_UNSUPPORTED = + 9_019; + public static final int ANALYSIS_JVM_COMPOSITE_HEAP_EXPAND_OPERATOR_EXIT_STATE_UNSUPPORTED = + 9_020; + public static final int ANALYSIS_JVM_COMPOSITE_HEAP_REDUCE_OPERATOR_STATE_UNSUPPORTED = 9_021; + public static final int ANALYSIS_JVM_REFERENCE_TRANSFER_RELATION_STATE_UNSUPPORTED = 9_022; + public static final int ANALYSIS_JVM_INVOKE_TAINT_SINK_MISSING_TAINT = 9_023; + public static final int + ANALYSIS_JVM_TAINT_BAM_CPA_RUN_INTRAPROCEDURAL_CPA_HEAP_MODEL_UNSUPPORTED = 9_024; + public static final int ANALYSIS_JVM_TAINT_BAM_CPA_RUN_EXPAND_OPERATOR_HEAP_MODEL_UNSUPPORTED = + 9_025; + public static final int ANALYSIS_JVM_TAINT_BAM_CPA_RUN_HEAP_MODEL_INVALID = 9_026; + public static final int ANALYSIS_JVM_TAINT_BAM_CPA_RUN_CFA_OR_MAIN_SIGNATURE_NOT_SET = 9_027; + public static final int + ANALYSIS_JVM_TAINT_MEMORY_LOCATION_BAM_CPA_RUN_CFA_OR_MAIN_SIGNATURE_NOT_SET = 9_028; + public static final int ANALYSIS_JVM_VALUE_BAM_CPA_RUN_SET_CFA_UNSUPPORTED = 9_029; + public static final int ANALYSIS_JVM_VALUE_TRANSFER_RELATION_INCORRECT_PARAMETER_COUNT = 9_030; + public static final int ANALYSIS_VALUE_ABSTRACT_STATE_CONDITION_UNCHECKED = 9_031; + public static final int ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_INITIAL_STATE_UNSUPPORTED = 9_032; + public static final int ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_EXIT_STATE_UNSUPPORTED = 9_033; + public static final int ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_GET_UNSUPPORTED_REFERENCE_TYPE = 9_034; + public static final int ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_SET_UNSUPPORTED_REFERENCE_TYPE = 9_035; + public static final int ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_ARRAY_GET_UNSUPPORTED_REFERENCE_TYPE = + 9_036; + public static final int ANALYSIS_JVM_TREE_HEAP_PRINCIPAL_ARRAY_SET_UNSUPPORTED_REFERENCE_TYPE = + 9_037; + public static final int ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_RETURN_INSTRUCTION_EXPECTED = 9_038; + public static final int ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_EXIT_NODE_EXPECTED = 9_039; + public static final int + ANALYSIS_JVM_DEFAULT_EXPAND_OPERATOR_MISSING_EXPECTED_CATCH_NODE_EXPECTED = 9_040; + public static final int ANALYSIS_JVM_TRANSFER_RELATION_STATE_UNSUPPORTED = 9_041; + public static final int ANALYSIS_JVM_TRANSFER_RELATION_INSTRUCTION_PUSH_COUNT_HIGHER_THAN_TWO = + 9_042; + public static final int ANALYSIS_JVM_TRANSFER_RELATION_UNEXPECTED_UNKNOWN_SIGNATURE = 9_043; + public static final int + ANALYSIS_JVM_TRANSFER_RELATION_CONSTANT_INSTRUCTION_VISITOR_OPCODE_UNSUPPORTED = 9_044; + public static final int ANALYSIS_JVM_DEFAULT_REDUCE_OPERATOR_STATE_UNSUPPORTED = 9_045; + public static final int ANALYSIS_JVM_TREE_HEAP_STATE_INCOMPATIBLE = 9_046; + /** Private constructor to prevent instantiation of the class. */ private ErrorId() {} } diff --git a/base/src/main/java/proguard/exception/ProguardCoreException.java b/base/src/main/java/proguard/exception/ProguardCoreException.java index 0be5b3af..f6822c6b 100644 --- a/base/src/main/java/proguard/exception/ProguardCoreException.java +++ b/base/src/main/java/proguard/exception/ProguardCoreException.java @@ -42,7 +42,7 @@ public ProguardCoreException(int componentErrorId, String message, Object... err */ public ProguardCoreException( int componentErrorId, Throwable cause, String message, Object... errorParameters) { - super(String.format(message, errorParameters), cause); + super(message != null ? String.format(message, errorParameters) : null, cause); this.componentErrorId = componentErrorId; this.errorParameters = errorParameters; @@ -57,4 +57,32 @@ public int getComponentErrorId() { public Object[] getErrorParameters() { return errorParameters; } + + /** Builder to construct ProguardCoreException objects. */ + public static class Builder { + private final String message; + private final int componentErrorId; + + private Object[] errorParameters = new Object[] {}; + private Throwable cause = null; + + public Builder(String message, int componentErrorId) { + this.message = message; + this.componentErrorId = componentErrorId; + } + + public Builder errorParameters(Object... errorParameters) { + this.errorParameters = errorParameters; + return this; + } + + public Builder cause(Throwable cause) { + this.cause = cause; + return this; + } + + public ProguardCoreException build() { + return new ProguardCoreException(componentErrorId, cause, message, errorParameters); + } + } } diff --git a/base/src/test/kotlin/proguard/analysis/DominatorCalculatorTest.kt b/base/src/test/kotlin/proguard/analysis/DominatorCalculatorTest.kt index 8e5be9fa..754ec6f3 100644 --- a/base/src/test/kotlin/proguard/analysis/DominatorCalculatorTest.kt +++ b/base/src/test/kotlin/proguard/analysis/DominatorCalculatorTest.kt @@ -33,6 +33,7 @@ import proguard.classfile.attribute.visitor.AttributeVisitor import proguard.classfile.instruction.Instruction import proguard.classfile.visitor.ClassVisitor import proguard.classfile.visitor.MemberVisitor +import proguard.exception.ProguardCoreException import java.util.BitSet import kotlin.streams.asSequence @@ -580,16 +581,16 @@ class DominatorCalculatorTest : FreeSpec({ EXIT */ - shouldThrow { + shouldThrow { calculator.dominates(0, 1) } - shouldThrow { + shouldThrow { calculator.dominates(0, 3) } - shouldThrow { + shouldThrow { calculator.dominates(0, 5) } - shouldThrow { + shouldThrow { calculator.dominates(0, 7) } } @@ -609,7 +610,7 @@ class DominatorCalculatorTest : FreeSpec({ } "All offsets are unknown" { - shouldThrow { + shouldThrow { calculator.dominates(0, 1) } }