fix: terminate type inference on first stack overflow (#2744)

This commit is contained in:
Skylot
2026-01-18 17:52:38 +00:00
parent a0466d4494
commit b725dd18b6
5 changed files with 17 additions and 14 deletions
@@ -12,7 +12,7 @@ public class DepthTraversal {
cls.getInnerClasses().forEach(inCls -> visit(visitor, inCls));
cls.getMethods().forEach(mth -> visit(visitor, mth));
}
} catch (StackOverflowError | Exception e) {
} catch (StackOverflowError | BootstrapMethodError | Exception e) {
cls.addError(e.getClass().getSimpleName() + " in pass: " + visitor.getClass().getSimpleName(), e);
}
}
@@ -23,7 +23,7 @@ public class DepthTraversal {
return;
}
visitor.visit(mth);
} catch (StackOverflowError | Exception e) {
} catch (StackOverflowError | BootstrapMethodError | Exception e) {
mth.addError(e.getClass().getSimpleName() + " in pass: " + visitor.getClass().getSimpleName(), e);
}
}
@@ -73,6 +73,8 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
assignImmutableTypes(mth);
initTypeBounds(mth);
runTypePropagation(mth);
} catch (StackOverflowError | BootstrapMethodError e) {
mth.addError("Type inference failed with stack overflow", new JadxOverflowException(e.getMessage()));
} catch (Exception e) {
mth.addError("Type inference failed", e);
}
@@ -30,7 +30,6 @@ import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.dex.nodes.utils.TypeUtils;
import jadx.core.utils.exceptions.JadxOverflowException;
import jadx.core.utils.exceptions.JadxRuntimeException;
import static jadx.core.dex.visitors.typeinference.TypeUpdateResult.CHANGED;
@@ -223,16 +222,11 @@ public final class TypeUpdate {
return CHANGED;
}
updateInfo.requestUpdate(arg, candidateType);
try {
TypeUpdateResult result = runListeners(updateInfo, arg, candidateType);
if (result == REJECT) {
updateInfo.rollbackUpdate(arg);
}
return result;
} catch (StackOverflowError | BootstrapMethodError error) {
throw new JadxOverflowException("Type update terminated with stack overflow, arg: " + arg
+ ", method size: " + updateInfo.getMth().getInsnsCount());
TypeUpdateResult result = runListeners(updateInfo, arg, candidateType);
if (result == REJECT) {
updateInfo.rollbackUpdate(arg);
}
return result;
}
private TypeUpdateResult runListeners(TypeUpdateInfo updateInfo, InsnArg arg, ArgType candidateType) {
@@ -9,6 +9,7 @@ import jadx.api.JadxArgs;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxOverflowException;
import jadx.core.utils.exceptions.JadxRuntimeException;
@@ -34,7 +35,11 @@ public class TypeUpdateInfo {
}
if (updateSeq > updatesLimitCount) {
throw new JadxOverflowException("Type inference error: updates count limit reached"
+ " with updateSeq = " + updateSeq + ". Try increasing the type limit count on preferences.");
+ " with updateSeq = " + updateSeq + ". Try increasing type updates limit count.");
}
if (updateSeq % 100 == 0) {
// check for interruption sometimes (every update is too often)
Utils.checkThreadInterrupt();
}
}
@@ -35,10 +35,12 @@ public class DecompilerScheduler implements IDecompileScheduler {
check(result, classes);
}
return result;
} catch (StackOverflowError | BootstrapMethodError e) {
LOG.warn("Stack overflow while building decompile batches, continue with fallback");
} catch (Exception e) {
LOG.warn("Build batches failed (continue with fallback)", e);
return buildFallback(classes);
}
return buildFallback(classes);
}
/**