Fix for switches in infinite loop decompiler bug

This commit is contained in:
caheckman 2019-05-08 11:13:20 -04:00
parent 0a0b716266
commit efabf89ea2
3 changed files with 10 additions and 5 deletions

View file

@ -1767,8 +1767,9 @@ BlockInfLoop *BlockGraph::newBlockInfLoop(FlowBlock *body)
/// Add the new BlockSwitch to \b this, collapsing all the case FlowBlocks into it.
/// \param cs is the list of case FlowBlocks
/// \param hasExit is \b true if the switch has a formal exit
/// \return the new BlockSwitch
BlockSwitch *BlockGraph::newBlockSwitch(const vector<FlowBlock *> &cs)
BlockSwitch *BlockGraph::newBlockSwitch(const vector<FlowBlock *> &cs,bool hasExit)
{
FlowBlock *rootbl = cs[0];
@ -1779,6 +1780,8 @@ BlockSwitch *BlockGraph::newBlockSwitch(const vector<FlowBlock *> &cs)
ret->grabCaseBasic(leafbl->subBlock(0),cs); // Must be called before the identifyInternal
identifyInternal(ret,cs);
addBlock(ret);
if (hasExit)
ret->forceOutputNum(1); // If there is an exit, there should be exactly 1 out edge
ret->clearFlag(f_switch_out); // Don't consider this as being a switch "out"
return ret;
}

View file

@ -326,7 +326,7 @@ public:
BlockWhileDo *newBlockWhileDo(FlowBlock *cond,FlowBlock *cl); ///< Build a new BlockWhileDo
BlockDoWhile *newBlockDoWhile(FlowBlock *condcl); ///< Build a new BlockDoWhile
BlockInfLoop *newBlockInfLoop(FlowBlock *body); ///< Build a new BlockInfLoop
BlockSwitch *newBlockSwitch(const vector<FlowBlock *> &cs); ///< Build a new BlockSwitch
BlockSwitch *newBlockSwitch(const vector<FlowBlock *> &cs,bool hasExit); ///< Build a new BlockSwitch
void orderBlocks(void) { ///< Sort blocks using the final ordering
if (list.size()!=1) sort(list.begin(),list.end(),compareFinalOrder); }

View file

@ -1636,7 +1636,10 @@ bool CollapseStructure::ruleBlockSwitch(FlowBlock *bl)
// Find "obvious" exitblock, is sizeIn>1 or sizeOut>1
for(int4 i=0;i<sizeout;++i) {
FlowBlock *curbl = bl->getOut(i);
if (curbl == bl) return false; // Cannot exit to itself (this can happen as a goto)
if (curbl == bl) {
exitblock = curbl; // Exit back to top of switch (loop)
break;
}
if (curbl->sizeOut() > 1) {
exitblock = curbl;
break;
@ -1673,7 +1676,6 @@ bool CollapseStructure::ruleBlockSwitch(FlowBlock *bl)
if (exitblock->isGotoOut(i)) return false;
for(int4 i=0;i<sizeout;++i) {
FlowBlock *curbl = bl->getOut(i);
if (curbl == bl) return false;
if (curbl == exitblock) continue; // The switch can go straight to the exit block
if (curbl->sizeIn() > 1) return false; // A case can only have the switch fall into it
if (curbl->isGotoIn(0)) return false; // In cannot be a goto
@ -1696,7 +1698,7 @@ bool CollapseStructure::ruleBlockSwitch(FlowBlock *bl)
if (curbl == exitblock) continue; // Don't include exit as a case
cases.push_back(curbl);
}
graph.newBlockSwitch(cases);
graph.newBlockSwitch(cases,(exitblock != (FlowBlock *)0));
return true;
}