pycdc icon indicating copy to clipboard operation
pycdc copied to clipboard

pycdc gives wrong code when dealing with swapping two variables

Open GaoYuCan opened this issue 2 years ago • 6 comments

pycdc gives wrong code when dealing with swapping two variables:

pycdas

102     LOAD_FAST                     2: sbox
104     LOAD_FAST                     3: j
106     BINARY_SUBSCR
108     LOAD_FAST                     2: sbox
110     LOAD_FAST                     8: i
112     BINARY_SUBSCR
114     ROT_TWO
116     LOAD_FAST                     2: sbox
118     LOAD_FAST                     8: i
120     STORE_SUBSCR
122     LOAD_FAST                     2: sbox
124     LOAD_FAST                     3: j
126     STORE_SUBSCR

pycdc:

sbox[i] = sbox[j]
sbox[j] = sbox[i]

origin:

sbox[i], sbox[j] = sbox[j], sbox[i]

GaoYuCan avatar Mar 27 '23 14:03 GaoYuCan

Hello, but isn't it how it would looks like in 2 lines ? Pycdc might not always be able to get back a 1:1 code too.

TheHellTower avatar Mar 27 '23 17:03 TheHellTower

@TheHellTower the two pieces of code are not equivalent. The original swaps values of sbox[i] and sbox[j] while the second with is the same as sbox[i] = sbox[j] (the second assignment statement could be removed altogether).

rocky avatar Apr 28 '23 11:04 rocky

@TheHellTower the two pieces of code are not equivalent. The original swaps values of sbox[i] and sbox[j] while the second with is the same as sbox[i] = sbox[j] (the second assignment statement could be removed altogether).

Hey, sorry I'm back, I might try to look at it and see if I can get it solved !

TheHellTower avatar Jun 02 '23 00:06 TheHellTower

And for me it looks correct because I seen things similar like:

a, b = 1, 2
a = 1
b = 2

If you have a more detailed explanation don't hesitate because I don't really get it well if I'm wrong right now..

TheHellTower avatar Jun 02 '23 00:06 TheHellTower

When pycdc processes the code you provided, it is indeed correct, but it is unrelated to the current issue. The code you provided is a tuple unpacking operation at the Python bytecode level, rather than the variable swapping operation I mentioned earlier. The following code may give you a more intuitive understanding of this issue.

a = 1
b = 2
a, b = b, a
print(f"a = {a}, b = {b}")

the result of pycdas:

        0       LOAD_CONST                    0: (1, 2)
        2       UNPACK_SEQUENCE               2
        4       STORE_NAME                    0: a
        6       STORE_NAME                    1: b
        8       LOAD_NAME                     2: print
        10      LOAD_CONST                    1: 'a = '
        12      LOAD_NAME                     0: a
        14      FORMAT_VALUE                  0
        16      LOAD_CONST                    2: ', b = '
        18      LOAD_NAME                     1: b
        20      FORMAT_VALUE                  0
        22      BUILD_STRING                  4
        24      CALL_FUNCTION                 1
        26      POP_TOP                       
        28      LOAD_CONST                    3: None
        30      RETURN_VALUE                  

As I mentioned earlier, its core is the UNPACK_SEQUENCE instruction, which is tuple unpacking. However, the issue here is swapping, and the following is an example of swapping.

a = 1
b = 2
a, b = b, a
print(f"a = {a}, b = {b}")

the result of pycdas:

        0       LOAD_CONST                    0: 1
        2       STORE_NAME                    0: a
        4       LOAD_CONST                    1: 2
        6       STORE_NAME                    1: b
        8       LOAD_NAME                     1: b
        10      LOAD_NAME                     0: a
        12      ROT_TWO                       
        14      STORE_NAME                    0: a
        16      STORE_NAME                    1: b
        18      LOAD_NAME                     2: print
        20      LOAD_CONST                    2: 'a = '
        22      LOAD_NAME                     0: a
        24      FORMAT_VALUE                  0
        26      LOAD_CONST                    3: ', b = '
        28      LOAD_NAME                     1: b
        30      FORMAT_VALUE                  0
        32      BUILD_STRING                  4
        34      CALL_FUNCTION                 1
        36      POP_TOP                       
        38      LOAD_CONST                    4: None
        40      RETURN_VALUE                  

The core of this is the ROT_TWO instruction.

The following is an experiment demonstrating the incorrect code provided by pycdc:

image

attachment: pycdc_swap_issues.tar.gz

GaoYuCan avatar Jun 02 '23 03:06 GaoYuCan

When pycdc processes the code you provided, it is indeed correct, but it is unrelated to the current issue. The code you provided is a tuple unpacking operation at the Python bytecode level, rather than the variable swapping operation I mentioned earlier. The following code may give you a more intuitive understanding of this issue.

a = 1
b = 2
a, b = b, a
print(f"a = {a}, b = {b}")

the result of pycdas:

        0       LOAD_CONST                    0: (1, 2)
        2       UNPACK_SEQUENCE               2
        4       STORE_NAME                    0: a
        6       STORE_NAME                    1: b
        8       LOAD_NAME                     2: print
        10      LOAD_CONST                    1: 'a = '
        12      LOAD_NAME                     0: a
        14      FORMAT_VALUE                  0
        16      LOAD_CONST                    2: ', b = '
        18      LOAD_NAME                     1: b
        20      FORMAT_VALUE                  0
        22      BUILD_STRING                  4
        24      CALL_FUNCTION                 1
        26      POP_TOP                       
        28      LOAD_CONST                    3: None
        30      RETURN_VALUE                  

As I mentioned earlier, its core is the UNPACK_SEQUENCE instruction, which is tuple unpacking. However, the issue here is swapping, and the following is an example of swapping.

a = 1
b = 2
a, b = b, a
print(f"a = {a}, b = {b}")

the result of pycdas:

        0       LOAD_CONST                    0: 1
        2       STORE_NAME                    0: a
        4       LOAD_CONST                    1: 2
        6       STORE_NAME                    1: b
        8       LOAD_NAME                     1: b
        10      LOAD_NAME                     0: a
        12      ROT_TWO                       
        14      STORE_NAME                    0: a
        16      STORE_NAME                    1: b
        18      LOAD_NAME                     2: print
        20      LOAD_CONST                    2: 'a = '
        22      LOAD_NAME                     0: a
        24      FORMAT_VALUE                  0
        26      LOAD_CONST                    3: ', b = '
        28      LOAD_NAME                     1: b
        30      FORMAT_VALUE                  0
        32      BUILD_STRING                  4
        34      CALL_FUNCTION                 1
        36      POP_TOP                       
        38      LOAD_CONST                    4: None
        40      RETURN_VALUE                  

The core of this is the ROT_TWO instruction.

The following is an experiment demonstrating the incorrect code provided by pycdc:

image

attachment: pycdc_swap_issues.tar.gz

Hello, yeah now I get your problem.. I suppose for these cases we should first save the 2 values then swap them then.. To avoid getting this problem again, I don't have a perfect and clean-code idea to achieve this but I will see in the next days if I can fix it but can't promise, thanks for clarifying it and giving out the OPCode that generate the core problem !

TheHellTower avatar Jun 02 '23 04:06 TheHellTower