STARK: Dont try to visit the same block multiple times when decompiling

Unless the block is trivial. The original compiler seems to reuse "end" commands.
This commit is contained in:
Bastien Bouclet 2016-06-01 18:03:25 +02:00
parent d2f1bb8d80
commit d523c326c5
4 changed files with 25 additions and 1 deletions

View File

@ -307,6 +307,14 @@ CFGCommand *Block::getConditionCommand() const {
}
}
bool Block::allowDuplication() const {
// Allow simple termination blocks to be duplicated in the decompiled output
bool isScriptEnd = !_follower && !_trueBranch && !_falseBranch;
bool isShort = _commands.size() < 5;
return isScriptEnd && isShort;
}
ControlStructure::ControlStructure(ControlStructureType t) :
type(t),
condition(nullptr),

View File

@ -87,6 +87,9 @@ public:
bool isInfiniteLoopStart() const;
void setInfiniteLoopStart(bool infiniteLoopStart);
/** Can this block appear multiple times in the decompiled output? */
bool allowDuplication() const;
// Graph query methods
bool hasPredecessor(Block *predecessor) const;
bool hasSuccessor(Block *successor) const;

View File

@ -290,6 +290,18 @@ void Decompiler::buildASTFromBlock(ASTBlock *parent, Block *block, Block *stopBl
stopBlock = block;
}
{
bool alreadyVisited = Common::find(_visitedBlocks.begin(), _visitedBlocks.end(), block) != _visitedBlocks.end();
if (alreadyVisited && !block->allowDuplication()) {
// FIXME: We just return for now when an already visited block is visited again.
// Obviously, this leads to invalid decompiled code, which is caught by the verification step.
// To fix, either handle the cases leading to multiple visits, or generate gotos.
return;
}
}
_visitedBlocks.push_back(block);
Common::Array<CFGCommand *> commands = block->getLinearCommands();
for (uint i = 0; i < commands.size(); i++) {
parent->addNode(new ASTCommand(parent, commands[i]));
@ -376,7 +388,7 @@ bool Decompiler::verifyCommandInAST(CFGCommand *cfgCommand) {
return false;
}
if (list.size() > 1) {
if (list.size() > 1 && !cfgCommand->getBlock()->allowDuplication()) {
_error = Common::String::format("Command %d found %d times in the AST", cfgCommand->getIndex(), list.size());
return false;
}

View File

@ -92,6 +92,7 @@ private:
ASTNode *_astHead;
Common::Array<Block *> _visitedInfiniteLoopStarts;
Common::Array<Block *> _visitedBlocks;
};
} // End of namespace Tools