Use non-recursive methods to prevent StackOverflow exceptions
This commit is contained in:
parent
6dfe2fd1b6
commit
4fcb332ddf
|
@ -170,38 +170,60 @@ namespace de4dot.blocks {
|
|||
dest.Add(block);
|
||||
}
|
||||
|
||||
struct VisitState {
|
||||
public BlockInfo Info;
|
||||
public List<BaseBlock> Targets;
|
||||
public int TargetIndex;
|
||||
public BlockInfo TargetInfo;
|
||||
public VisitState(BlockInfo info) {
|
||||
this.Info = info;
|
||||
this.Targets = null;
|
||||
this.TargetIndex = 0;
|
||||
this.TargetInfo = null;
|
||||
}
|
||||
}
|
||||
Stack<VisitState> visitStateStack = new Stack<VisitState>();
|
||||
void Visit(BlockInfo info) {
|
||||
if (info.baseBlock == firstBlock)
|
||||
// This method used to be recursive but to prevent stack overflows,
|
||||
// it's not recursive anymore.
|
||||
|
||||
VisitState state = new VisitState(info);
|
||||
recursive_call:
|
||||
if (state.Info.baseBlock == firstBlock)
|
||||
throw new ApplicationException("Can't visit firstBlock");
|
||||
stack.Push(info);
|
||||
info.onStack = true;
|
||||
info.dfsNumber = dfsNumber;
|
||||
info.low = dfsNumber;
|
||||
stack.Push(state.Info);
|
||||
state.Info.onStack = true;
|
||||
state.Info.dfsNumber = dfsNumber;
|
||||
state.Info.low = dfsNumber;
|
||||
dfsNumber++;
|
||||
|
||||
foreach (var tmp in GetTargets(info.baseBlock)) {
|
||||
var targetInfo = GetInfo(tmp);
|
||||
if (targetInfo == null)
|
||||
state.Targets = GetTargets(state.Info.baseBlock);
|
||||
state.TargetIndex = 0;
|
||||
return_to_caller:
|
||||
for (; state.TargetIndex < state.Targets.Count; state.TargetIndex++) {
|
||||
state.TargetInfo = GetInfo(state.Targets[state.TargetIndex]);
|
||||
if (state.TargetInfo == null)
|
||||
continue;
|
||||
if (targetInfo.baseBlock == firstBlock)
|
||||
if (state.TargetInfo.baseBlock == firstBlock)
|
||||
continue;
|
||||
|
||||
if (!targetInfo.Visited()) {
|
||||
Visit(targetInfo);
|
||||
info.low = Math.Min(info.low, targetInfo.low);
|
||||
if (!state.TargetInfo.Visited()) {
|
||||
visitStateStack.Push(state);
|
||||
state = new VisitState(state.TargetInfo);
|
||||
goto recursive_call;
|
||||
}
|
||||
else if (targetInfo.onStack)
|
||||
info.low = Math.Min(info.low, targetInfo.dfsNumber);
|
||||
else if (state.TargetInfo.onStack)
|
||||
state.Info.low = Math.Min(state.Info.low, state.TargetInfo.dfsNumber);
|
||||
}
|
||||
|
||||
if (info.low != info.dfsNumber)
|
||||
return;
|
||||
if (state.Info.low != state.Info.dfsNumber)
|
||||
goto return_from_method;
|
||||
var sccBlocks = new List<BaseBlock>();
|
||||
while (true) {
|
||||
var poppedInfo = stack.Pop();
|
||||
poppedInfo.onStack = false;
|
||||
sccBlocks.Add(poppedInfo.baseBlock);
|
||||
if (ReferenceEquals(info, poppedInfo))
|
||||
if (ReferenceEquals(state.Info, poppedInfo))
|
||||
break;
|
||||
}
|
||||
if (sccBlocks.Count > 1) {
|
||||
|
@ -213,6 +235,14 @@ namespace de4dot.blocks {
|
|||
else {
|
||||
sorted.Insert(0, sccBlocks[0]);
|
||||
}
|
||||
|
||||
return_from_method:
|
||||
if (visitStateStack.Count == 0)
|
||||
return;
|
||||
state = visitStateStack.Pop();
|
||||
state.Info.low = Math.Min(state.Info.low, state.TargetInfo.low);
|
||||
state.TargetIndex++;
|
||||
goto return_to_caller;
|
||||
}
|
||||
|
||||
void SortLoopBlock(List<BaseBlock> list) {
|
||||
|
|
|
@ -100,25 +100,38 @@ namespace de4dot.blocks {
|
|||
return false;
|
||||
}
|
||||
|
||||
void ScanBaseBlock(BaseBlock bb, int stackStart) {
|
||||
if (blockInfos.ContainsKey(bb) || !scopeBlock.IsOurBaseBlock(bb))
|
||||
return;
|
||||
struct ScanBaseBlockState {
|
||||
public BaseBlock bb;
|
||||
public int stackStart;
|
||||
public ScanBaseBlockState(BaseBlock bb, int stackStart) {
|
||||
this.bb = bb;
|
||||
this.stackStart = stackStart;
|
||||
}
|
||||
}
|
||||
Stack<ScanBaseBlockState> scanBaseBlockStack = new Stack<ScanBaseBlockState>();
|
||||
void ScanBaseBlock(BaseBlock bbx, int stackStartx) {
|
||||
scanBaseBlockStack.Push(new ScanBaseBlockState(bbx, stackStartx));
|
||||
while (scanBaseBlockStack.Count > 0) {
|
||||
var state = scanBaseBlockStack.Pop();
|
||||
if (blockInfos.ContainsKey(state.bb) || !scopeBlock.IsOurBaseBlock(state.bb))
|
||||
continue;
|
||||
|
||||
var blockInfo = new BlockInfo(bb, stackStart);
|
||||
blockInfos[bb] = blockInfo;
|
||||
var blockInfo = new BlockInfo(state.bb, state.stackStart);
|
||||
blockInfos[state.bb] = blockInfo;
|
||||
|
||||
var block = bb as Block;
|
||||
var block = state.bb as Block;
|
||||
if (block == null) { // i.e., if try, filter, or handler block
|
||||
// It's not important to know the exact values, so we set them both to 0.
|
||||
// Compilers must make sure the stack is empty when entering a try block.
|
||||
blockInfo.stackStart = blockInfo.stackEnd = 0;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
blockInfo.CalculateStackUsage();
|
||||
|
||||
foreach (var target in block.GetTargets())
|
||||
ScanBaseBlock(target, blockInfo.stackEnd);
|
||||
scanBaseBlockStack.Push(new ScanBaseBlockState(target, blockInfo.stackEnd));
|
||||
}
|
||||
}
|
||||
|
||||
void CreateNewList() {
|
||||
|
|
Loading…
Reference in New Issue
Block a user