Skip to content
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

Short-circuiting if statements are incorrectly parsed #2

Open
Pokechu22 opened this issue Mar 24, 2016 · 2 comments
Open

Short-circuiting if statements are incorrectly parsed #2

Pokechu22 opened this issue Mar 24, 2016 · 2 comments

Comments

@Pokechu22
Copy link
Owner

Certain packets with more complicated if statements (IE, ones that aren't just if (flag) but instead if (var == 1 || var == 2)) are parsed as if they were if (var).

For example, the world border packet is incorrectly parsed. It is currently parsed as

writeString(a);
writeByte(d);
if(d) {
  writeString(b);
  writeString(c.a());
}

but should actually be

writeString(a);
writeByte(d);
if(d == 0 || d == 2) {
  writeString(b);
  writeString(c.a());
}

The same applies with the teams packet and a few others.

@Pokechu22 Pokechu22 changed the title Play clientbound 3F / Scoreboard Objective is incorrectly parsed If statements with complex parameters are incorrectly parsed Mar 24, 2016
@Pokechu22
Copy link
Owner Author

It has both if statements after _PIT.operations, but loses one after _PIT.format.

@Pokechu22
Copy link
Owner Author

Pokechu22 commented Dec 15, 2017

Short-circuiting in action.

class shortcircuit {
	public void or1(int a) {
		if (a == 1 || a == 2) {
			writeByte(1);
		}
	}

	public void or2(int a) {
		if (a == 1 || a == 2 || a == 3) {
			writeByte(1);
		}
	}

	public void and1(int a, int b) {
		if (a == 1 && b == 2) {
			writeByte(1);
		}
	}

	public void complex1(int a, int b) {
		if ((a == 1 && b == 1) || (a == 2 && b == 0)) {
			writeByte(1);
		}
	}

	// To get burger to output something
	public Object writeByte(int n) {return null;}
}
from burger.toppings.packetinstructions import PacketInstructionsTopping as _PIT
from jawa.util.classloader import ClassLoader
import json
cl = ClassLoader(1)
cl.add_path('.')
cls = 'shortcircuit'
def operations(name, *arg_names):
    result = _PIT.operations(cl, cls, {}, methodname=name, arg_names=['this'] + list(arg_names))
    print json.dumps(result, indent=4, default=lambda o: o.__dict__)

def format(name, *arg_names):
    tmp = _PIT.operations(cl, cls, {}, methodname=name, arg_names=['this'] + list(arg_names))
    result = _PIT.format(tmp)
    print json.dumps(result, indent=4, default=lambda o: o.__dict__)

Testing each of those methods:

or1

Disassembly

  public void or1(int);
    Code:
       0: iload_1
       1: iconst_1
       2: if_icmpeq     10
       5: iload_1
       6: iconst_2
       7: if_icmpne     16
      10: aload_0
      11: iconst_1
      12: invokevirtual #2                  // Method writeByte:(I)Ljava/lang/Object;
      15: pop
      16: return

PIT.operations

[
    {
        "position": 2,
        "operation": "if",
        "condition": "n != 1"
    },
    {
        "position": 10,
        "operation": "endif"
    },
    {
        "position": 7,
        "operation": "if",
        "condition": "n == 2"
    },
    {
        "position": 16,
        "operation": "endif"
    },
    {
        "position": 12,
        "operation": "write",
        "type": "byte",
        "field": "1"
    }
]

PIT.format

{
    "instructions": [
        {
            "operation": "if",
            "condition": "n != 1",
            "instructions": [
                {
                    "operation": "write",
                    "type": "byte",
                    "field": "1"
                }
            ]
        }
    ]
}

or2

Disassembly

  public void or2(int);
    Code:
       0: iload_1
       1: iconst_1
       2: if_icmpeq     15
       5: iload_1
       6: iconst_2
       7: if_icmpeq     15
      10: iload_1
      11: iconst_3
      12: if_icmpne     21
      15: aload_0
      16: iconst_1
      17: invokevirtual #2                  // Method writeByte:(I)Ljava/lang/Object;
      20: pop
      21: return

PIT.operations

[
    {
        "position": 2,
        "operation": "if",
        "condition": "n != 1"
    },
    {
        "position": 15,
        "operation": "endif"
    },
    {
        "position": 7,
        "operation": "if",
        "condition": "n != 2"
    },
    {
        "position": 15,
        "operation": "endif"
    },
    {
        "position": 12,
        "operation": "if",
        "condition": "n == 3"
    },
    {
        "position": 20,
        "operation": "endif"
    },
    {
        "position": 17,
        "operation": "write",
        "type": "byte",
        "field": "1"
    }
]

PIT.format

{
    "instructions": [
        {
            "operation": "if",
            "condition": "n != 1",
            "instructions": [
                {
                    "operation": "write",
                    "type": "byte",
                    "field": "1"
                }
            ]
        }
    ]
}

and1

Disassembly

  public void and1(int, int);
    Code:
       0: iload_1
       1: iconst_1
       2: if_icmpne     16
       5: iload_2
       6: iconst_2
       7: if_icmpne     16
      10: aload_0
      11: iconst_1
      12: invokevirtual #2                  // Method writeByte:(I)Ljava/lang/Object;
      15: pop
      16: return

PIT.operations

[
    {
        "position": 2,
        "operation": "if",
        "condition": "a == 1"
    },
    {
        "position": 15,
        "operation": "endif"
    },
    {
        "position": 7,
        "operation": "if",
        "condition": "b == 2"
    },
    {
        "position": 15,
        "operation": "endif"
    },
    {
        "position": 12,
        "operation": "write",
        "type": "byte",
        "field": "1"
    }
]

PIT.format

{
    "instructions": [
        {
            "operation": "if",
            "condition": "a == 1",
            "instructions": [
                {
                    "operation": "if",
                    "condition": "b == 2",
                    "instructions": [
                        {
                            "operation": "write",
                            "type": "byte",
                            "field": "1"
                        }
                    ]
                }
            ]
        }
    ]
}

complex1

Disassembly

  public void complex1(int, int);
    Code:
       0: iload_1
       1: iconst_1
       2: if_icmpne     10
       5: iload_2
       6: iconst_1
       7: if_icmpeq     19
      10: iload_1
      11: iconst_2
      12: if_icmpne     25
      15: iload_2
      16: ifne          25
      19: aload_0
      20: iconst_1
      21: invokevirtual #2                  // Method writeByte:(I)Ljava/lang/Object;
      24: pop
      25: return

PIT.operations

[
    {
        "position": 2,
        "operation": "if",
        "condition": "a == 1"
    },
    {
        "position": 10,
        "operation": "endif"
    },
    {
        "position": 7,
        "operation": "if",
        "condition": "b != 1"
    },
    {
        "position": 19,
        "operation": "endif"
    },
    {
        "position": 12,
        "operation": "if",
        "condition": "a == 2"
    },
    {
        "position": 24,
        "operation": "endif"
    },
    {
        "position": 16,
        "operation": "if",
        "condition": "b == 0"
    },
    {
        "position": 24,
        "operation": "endif"
    },
    {
        "position": 21,
        "operation": "write",
        "type": "byte",
        "field": "1"
    }
]

PIT.format

{
    "instructions": [
        {
            "operation": "if",
            "condition": "a == 1",
            "instructions": [
                {
                    "operation": "if",
                    "condition": "a == 2",
                    "instructions": [
                        {
                            "operation": "write",
                            "type": "byte",
                            "field": "1"
                        }
                    ]
                }
            ]
        }
    ]
}

Conclusion

Short-circuiting is broken for ||, but works fine for && (the result is ugly but it is "correct").

@Pokechu22 Pokechu22 changed the title If statements with complex parameters are incorrectly parsed Short-circuiting if statements are incorrectly parsed Dec 15, 2017
Pokechu22 added a commit that referenced this issue Dec 24, 2017
This is one step to fixing #2, by getting rid of the need for the empty if check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant