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);
|
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) {
|
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");
|
throw new ApplicationException("Can't visit firstBlock");
|
||||||
stack.Push(info);
|
stack.Push(state.Info);
|
||||||
info.onStack = true;
|
state.Info.onStack = true;
|
||||||
info.dfsNumber = dfsNumber;
|
state.Info.dfsNumber = dfsNumber;
|
||||||
info.low = dfsNumber;
|
state.Info.low = dfsNumber;
|
||||||
dfsNumber++;
|
dfsNumber++;
|
||||||
|
|
||||||
foreach (var tmp in GetTargets(info.baseBlock)) {
|
state.Targets = GetTargets(state.Info.baseBlock);
|
||||||
var targetInfo = GetInfo(tmp);
|
state.TargetIndex = 0;
|
||||||
if (targetInfo == null)
|
return_to_caller:
|
||||||
|
for (; state.TargetIndex < state.Targets.Count; state.TargetIndex++) {
|
||||||
|
state.TargetInfo = GetInfo(state.Targets[state.TargetIndex]);
|
||||||
|
if (state.TargetInfo == null)
|
||||||
continue;
|
continue;
|
||||||
if (targetInfo.baseBlock == firstBlock)
|
if (state.TargetInfo.baseBlock == firstBlock)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!targetInfo.Visited()) {
|
if (!state.TargetInfo.Visited()) {
|
||||||
Visit(targetInfo);
|
visitStateStack.Push(state);
|
||||||
info.low = Math.Min(info.low, targetInfo.low);
|
state = new VisitState(state.TargetInfo);
|
||||||
|
goto recursive_call;
|
||||||
}
|
}
|
||||||
else if (targetInfo.onStack)
|
else if (state.TargetInfo.onStack)
|
||||||
info.low = Math.Min(info.low, targetInfo.dfsNumber);
|
state.Info.low = Math.Min(state.Info.low, state.TargetInfo.dfsNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.low != info.dfsNumber)
|
if (state.Info.low != state.Info.dfsNumber)
|
||||||
return;
|
goto return_from_method;
|
||||||
var sccBlocks = new List<BaseBlock>();
|
var sccBlocks = new List<BaseBlock>();
|
||||||
while (true) {
|
while (true) {
|
||||||
var poppedInfo = stack.Pop();
|
var poppedInfo = stack.Pop();
|
||||||
poppedInfo.onStack = false;
|
poppedInfo.onStack = false;
|
||||||
sccBlocks.Add(poppedInfo.baseBlock);
|
sccBlocks.Add(poppedInfo.baseBlock);
|
||||||
if (ReferenceEquals(info, poppedInfo))
|
if (ReferenceEquals(state.Info, poppedInfo))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (sccBlocks.Count > 1) {
|
if (sccBlocks.Count > 1) {
|
||||||
|
@ -213,6 +235,14 @@ namespace de4dot.blocks {
|
||||||
else {
|
else {
|
||||||
sorted.Insert(0, sccBlocks[0]);
|
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) {
|
void SortLoopBlock(List<BaseBlock> list) {
|
||||||
|
|
|
@ -100,25 +100,38 @@ namespace de4dot.blocks {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScanBaseBlock(BaseBlock bb, int stackStart) {
|
struct ScanBaseBlockState {
|
||||||
if (blockInfos.ContainsKey(bb) || !scopeBlock.IsOurBaseBlock(bb))
|
public BaseBlock bb;
|
||||||
return;
|
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);
|
var blockInfo = new BlockInfo(state.bb, state.stackStart);
|
||||||
blockInfos[bb] = blockInfo;
|
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
|
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.
|
// 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.
|
// Compilers must make sure the stack is empty when entering a try block.
|
||||||
blockInfo.stackStart = blockInfo.stackEnd = 0;
|
blockInfo.stackStart = blockInfo.stackEnd = 0;
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockInfo.CalculateStackUsage();
|
blockInfo.CalculateStackUsage();
|
||||||
|
|
||||||
foreach (var target in block.GetTargets())
|
foreach (var target in block.GetTargets())
|
||||||
ScanBaseBlock(target, blockInfo.stackEnd);
|
scanBaseBlockStack.Push(new ScanBaseBlockState(target, blockInfo.stackEnd));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateNewList() {
|
void CreateNewList() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user