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

[move] Fixed locals disassembly #20747

Merged
merged 3 commits into from
Jan 6, 2025
Merged

[move] Fixed locals disassembly #20747

merged 3 commits into from
Jan 6, 2025

Conversation

awelc
Copy link
Contributor

@awelc awelc commented Dec 30, 2024

Description

It looks like locals are currently not disassembled correctly when running Move disassembler and this PR contains a fix. In particular, consider the following Move code:

module test::M1;

public enum SomeEnum has drop, copy {
    NamedVariant { field: u64 },
    PositionalVariant(u64),
}

public fun foo(e: SomeEnum, p1: u64, p2: u64): (u64, u64) {
    match (e) {
        SomeEnum::NamedVariant { field } => {
            let mut res = field + p1;
            res = res + p2;
            (res, res)
        },
        SomeEnum::PositionalVariant(field) => (field, field)
    }
}

#[test]
public fun test() {
    let e = SomeEnum::NamedVariant { field: 42 };
    foo(e, 42, 7);
}

When running disassembler on the M1 module, the following 3 locals are reported in the disassembly:

L0:	__match_tmp%#unpack_subject#1#1#0: SomeEnum
L1:	field#3#0: u64
L2:	res#1#0: u64

However, 6 locals are reported in the source map:

%#7
%#8
__match_tmp%#match_subject#2#2#0
__match_tmp%#unpack_subject#1#1#0
field#3#0
res#1#0

The same number of locals is also reported in the trace generated out of the test function in M1.

It looks like the disassembler incorrectly assumes that function parameters are included in the locals and only locals beyond the (optional) initial number of parameters should be counted. After making the adjustment to ignore the parameters when disassembling locals, the following is reported in the disassembly which is consistent with the number (and names) of the locals in the source map and with the types of the locals in the trace:

L0:	%#7: u64
L1:	%#8: u64
L2:	__match_tmp%#match_subject#2#2#0: &SomeEnum
L3:	__match_tmp%#unpack_subject#1#1#0: SomeEnum
L4:	field#3#0: u64
L5:	res#1#0: u64

Test plan

All tests should pass

@awelc awelc self-assigned this Dec 30, 2024
Copy link

vercel bot commented Dec 30, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
sui-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 30, 2024 9:59pm
3 Skipped Deployments
Name Status Preview Comments Updated (UTC)
multisig-toolkit ⬜️ Ignored (Inspect) Visit Preview Dec 30, 2024 9:59pm
sui-kiosk ⬜️ Ignored (Inspect) Visit Preview Dec 30, 2024 9:59pm
sui-typescript-docs ⬜️ Ignored (Inspect) Visit Preview Dec 30, 2024 9:59pm

@awelc awelc temporarily deployed to sui-typescript-aws-kms-test-env December 30, 2024 18:32 — with GitHub Actions Inactive
parameter_len + local_idx,
signature,
)?;
self.disassemble_type_for_local(buffer, function_source_map, local_idx, signature)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is quite right. There's a slight mismatch here due to an underlying problem/mismatch between source maps and compiled modules:

  • In the bytecode all parameters are laid out in locals (so the first parameter_len local indices in the bytecode are the parameters).
  • In the function source map, we add parameters in to the parameters field, but not the locals.

I see two possibilities here:

  1. Pass local_idx + parameter_len here (since this is the index into the bytecode, so we want to skip the parameters here).
  2. Update the source map generation to also add the parameters to the locals (and in this case the parameters field in the function source map should be removed).

I prefer option (2) but that's a lot more work than just updating the index here, so if you need this to unblock you updating the index just here is probably fine.

Copy link
Contributor Author

@awelc awelc Dec 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is going to work as in disassemble_locals we actually iterate over locals indexes from the source map:

        for (local_idx, (name, _)) in function_source_map.locals.iter().enumerate() {
               ...
        }

If we use local_idx +parameter_len to get the type, we will miss some of them as locals signature only contains locals types:

L0:	%#7: SomeEnum
L1:	%#8: u64
L2:	__match_tmp%#match_subject#2#2#0: u64
L3:	__match_tmp%#unpack_subject#1#1#0: ERROR[Unable to get type for local at index 6]
L4:	field#3#0: ERROR[Unable to get type for local at index 7]
L5:	res#1#0: ERROR[Unable to get type for local at index 8]

That being said, with the current solution locals indexes displayed with locals disassembly do not match what's in the disassembled bytecode due to what you observed ("in the bytecode all parameters are laid out in locals") and we need to bump them up using parameter_len (note that now MoveLoc and StLoc disassembly's indexes much parameter and local indexes):

public foo(e#0#0: SomeEnum, p1#0#0: u64, p2#0#0: u64): u64 * u64 {
L3:	%#7: u64
L4:	%#8: u64
L5:	__match_tmp%#match_subject#2#2#0: &SomeEnum
L6:	__match_tmp%#unpack_subject#1#1#0: SomeEnum
L7:	field#3#0: u64
L8:	res#1#0: u64
B0:
	0: MoveLoc[0](e#0#0: SomeEnum)
	1: StLoc[6](__match_tmp%#unpack_subject#1#1#0: SomeEnum)

...

Copy link
Contributor

@tzakian tzakian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good to me!

@awelc awelc merged commit a56deae into main Jan 6, 2025
52 checks passed
@awelc awelc deleted the aw/disassembler-locals-fix branch January 6, 2025 18:06
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

Successfully merging this pull request may close these issues.

2 participants