New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'break' is not emitted in some cases #20

Open
AdamMil opened this Issue Jan 21, 2019 · 2 comments

Comments

Projects
None yet
1 participant
@AdamMil
Copy link

AdamMil commented Jan 21, 2019

Consider this small script:

while(true) {
  if(!this.condition) {
    if(--n <= 0) { break; }
  }
}

When compiled and decompiled, the output is:

while (true) {
        if (!this.condition) {
                if (--this.n <= 0) {
                }
        }
}

The 'break' statement is missing, resulting in an infinite loop.

@AdamMil

This comment has been minimized.

Copy link
Author

AdamMil commented Jan 21, 2019

While debugging, I notice this:

void NutFunction::DecompileJCMP(VMState& state, int condVar, int offsetIp, int iterVar, int cmpOp) const
{
    ...
    bool bCanBreak = (state.m_BlockState.inLoop || state.m_BlockState.inSwitch);

Here, m_BlockState refers to the 'if' statement and .inLoop is false. However, m_BlockState.parent refers to the loop and has .inLoop true. I think either bCanBreak needs to examine the chain of parent blocks, or inLoop needs to be propagated from parent to child.

I changed the code to:

bool bCanBreak = false;
for (BlockState *p = &state.m_BlockState; !bCanBreak && p; p = p->parent)
{
    bCanBreak = (p->inLoop || p->inSwitch);
}

And got the correct output for my example. But I'm not sure that's the correct change.

@AdamMil

This comment has been minimized.

Copy link
Author

AdamMil commented Jan 21, 2019

Perhaps elseEnd > prevBlockState.blockEnd also needs to be fixed to compare against the containing loop or switch end?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment