Skip to content

Commit 7af7b91

Browse files
authored
[move][decompiler] Fixes toward decompiling on-chain packages (#24310)
## Description This cleans up and fixes a number of lingering errors with the decompiler. ## Test plan New tests, plus tests working. --- ## Release notes Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required. For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates. - [ ] Protocol: - [ ] Nodes (Validators and Full nodes): - [ ] gRPC: - [ ] JSON-RPC: - [ ] GraphQL: - [ ] CLI: - [ ] Rust SDK: - [ ] Indexing Framework:
1 parent 3b59b5b commit 7af7b91

File tree

25 files changed

+1698
-77
lines changed

25 files changed

+1698
-77
lines changed

external-crates/move/crates/move-decompiler/src/ast.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub enum Exp {
8181
Vec<(Symbol, String)>,
8282
Box<Exp>,
8383
),
84+
VecUnpack(Vec<String>, Box<Exp>),
8485
Borrow(/* mut*/ bool, Box<Exp>),
8586
Value(Value),
8687
Variable(String),
@@ -118,6 +119,7 @@ impl Exp {
118119
Exp::Return(_) | Exp::Value(_) | Exp::Variable(_) | Exp::Constant(_) => false,
119120
Exp::Unpack(_, _, exp) => exp.contains_break(),
120121
Exp::UnpackVariant(_, _, _, exp) => exp.contains_break(),
122+
Exp::VecUnpack(_, exp) => exp.contains_break(),
121123
}
122124
}
123125

@@ -148,6 +150,7 @@ impl Exp {
148150
Exp::Return(_) | Exp::Value(_) | Exp::Variable(_) | Exp::Constant(_) => false,
149151
Exp::Unpack(_, _, exp) => exp.contains_continue(),
150152
Exp::UnpackVariant(_, _, _, exp) => exp.contains_continue(),
153+
Exp::VecUnpack(_, exp) => exp.contains_continue(),
151154
}
152155
}
153156

@@ -305,8 +308,7 @@ impl std::fmt::Display for Exp {
305308
if !items.is_empty() {
306309
write!(f, " ")?;
307310
}
308-
writeln!(f, "}} = {};", exp)?;
309-
Ok(())
311+
writeln!(f, "}} = {};", exp)
310312
}
311313
Exp::UnpackVariant(unpack_kind, (module, enum_, variant), items, exp) => {
312314
indent(f, level)?;
@@ -328,8 +330,18 @@ impl std::fmt::Display for Exp {
328330
UnpackKind::ImmRef => "&",
329331
UnpackKind::MutRef => "&mut ",
330332
};
331-
writeln!(f, "}} = {unpack_str}{exp};",)?;
332-
Ok(())
333+
writeln!(f, "}} = {unpack_str}{exp};",)
334+
}
335+
Exp::VecUnpack(items, exp) => {
336+
indent(f, level)?;
337+
write!(f, "let [")?;
338+
for (i, name) in items.iter().enumerate() {
339+
if i > 0 {
340+
write!(f, ", ")?;
341+
}
342+
write!(f, "{}", name)?;
343+
}
344+
writeln!(f, "] = {};", exp)
333345
}
334346
}
335347
}

external-crates/move/crates/move-decompiler/src/pretty_printer.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,15 @@ fn exp(context: &Context, exp: &Exp) -> Doc {
285285
.concat_space(D::text("="))
286286
.concat_space(recur(context, exp))
287287
}
288+
Exp::VecUnpack(lhs, exp) => {
289+
if lhs.is_empty() {
290+
D::text("std::vector::destroy_empty").concat(recur(context, exp).parens())
291+
} else {
292+
D::text("/* UNSUPPORT OP: MULTIARG VEC UNPACK ON ")
293+
.concat(recur(context, exp))
294+
.concat(D::text(" */"))
295+
}
296+
}
288297
Exp::UnpackVariant(_unpack_kind, (mod_, enum_, variant), items, exp) => {
289298
let items_doc = fields(items);
290299
D::text(format!("{mod_}::{enum_}::{variant}"))

external-crates/move/crates/move-decompiler/src/refinement/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ trait Refine {
8484
E::Value(_) => false,
8585
E::Variable(_) => false,
8686
E::Constant(_) => false,
87+
E::VecUnpack(_, e) => self.refine(e),
8788
E::Unpack(_, _, e) => self.refine(e),
8889
E::UnpackVariant(_, _, _, e) => self.refine(e),
8990
}

external-crates/move/crates/move-decompiler/src/structuring/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ fn structure_nodes(
8282
}
8383
}
8484

85+
#[allow(clippy::expect_fun_call)]
8586
fn structure_loop(
8687
config: &config::Config,
8788
graph: &mut Graph,

external-crates/move/crates/move-decompiler/src/structuring/term_reconstruction.rs

Lines changed: 85 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -49,75 +49,93 @@ pub fn exp(
4949
}
5050
SI::AssignReg {
5151
lhs,
52-
rhs:
53-
RValue::Data {
54-
op: DataOp::Unpack(ty),
55-
args,
56-
},
57-
} => {
58-
let fields = &ty.struct_.fields.0;
59-
debug_assert!(fields.len() == lhs.len());
60-
assert!(args.len() == 1);
61-
let unpack_fields = fields
62-
.iter()
63-
.zip(lhs.iter())
64-
.map(|(f, r)| (f.1.name, r.name()))
65-
.collect::<Vec<_>>();
66-
let module_id = ty.struct_.defining_module;
67-
let name = ty.struct_.name;
68-
let rhs = Box::new(trivials(&mut map, args.clone()).remove(0));
69-
seq.push(Out::Exp::Unpack((module_id, name), unpack_fields, rhs));
70-
}
71-
SI::AssignReg {
72-
lhs,
73-
rhs:
74-
RValue::Data {
75-
op:
76-
op @ (DataOp::UnpackVariant(_)
77-
| DataOp::UnpackVariantImmRef(_)
78-
| DataOp::UnpackVariantMutRef(_)),
79-
args,
80-
},
81-
} => {
82-
let (ty, unpack_kind) = match op {
83-
DataOp::UnpackVariant(ty) => (ty, Out::UnpackKind::Value),
84-
DataOp::UnpackVariantImmRef(ty) => (ty, Out::UnpackKind::ImmRef),
85-
DataOp::UnpackVariantMutRef(ty) => (ty, Out::UnpackKind::MutRef),
86-
_ => unreachable!(),
87-
};
88-
let fields = &ty.variant.fields.0;
89-
debug_assert!(fields.len() == lhs.len());
90-
assert!(args.len() == 1);
91-
let unpack_fields = fields
92-
.iter()
93-
.zip(lhs.iter())
94-
.map(|(f, r)| (*f.0, r.name()))
95-
.collect::<Vec<_>>();
96-
let module_id = ty.enum_.defining_module;
97-
let enum_ = ty.enum_.name;
98-
let variant = ty.variant.name;
99-
let rhs = Box::new(trivials(&mut map, args.clone()).remove(0));
100-
seq.push(Out::Exp::UnpackVariant(
101-
unpack_kind,
102-
(module_id, enum_, variant),
103-
unpack_fields,
104-
rhs,
105-
));
106-
}
107-
SI::AssignReg {
108-
lhs: _,
109-
rhs:
110-
RValue::Data {
111-
op: DataOp::WriteRef,
112-
args,
113-
},
114-
} => seq.push(Out::Exp::Data {
115-
op: DataOp::WriteRef,
116-
args: trivials(&mut map, args),
117-
}),
52+
rhs: RValue::Data { op, args },
53+
} => match op {
54+
// Multi-arity LHSs
55+
DataOp::Unpack(ty) => {
56+
let fields = &ty.struct_.fields.0;
57+
debug_assert!(fields.len() == lhs.len());
58+
assert!(args.len() == 1);
59+
let unpack_fields = fields
60+
.iter()
61+
.zip(lhs.iter())
62+
.map(|(f, r)| (f.1.name, r.name()))
63+
.collect::<Vec<_>>();
64+
let module_id = ty.struct_.defining_module;
65+
let name = ty.struct_.name;
66+
let rhs = Box::new(trivials(&mut map, args.clone()).remove(0));
67+
seq.push(Out::Exp::Unpack((module_id, name), unpack_fields, rhs));
68+
}
69+
DataOp::UnpackVariant(_)
70+
| DataOp::UnpackVariantImmRef(_)
71+
| DataOp::UnpackVariantMutRef(_) => {
72+
let (ty, unpack_kind) = match op {
73+
DataOp::UnpackVariant(ty) => (ty, Out::UnpackKind::Value),
74+
DataOp::UnpackVariantImmRef(ty) => (ty, Out::UnpackKind::ImmRef),
75+
DataOp::UnpackVariantMutRef(ty) => (ty, Out::UnpackKind::MutRef),
76+
_ => unreachable!(),
77+
};
78+
let fields = &ty.variant.fields.0;
79+
debug_assert!(fields.len() == lhs.len());
80+
assert!(args.len() == 1);
81+
let unpack_fields = fields
82+
.iter()
83+
.zip(lhs.iter())
84+
.map(|(f, r)| (*f.0, r.name()))
85+
.collect::<Vec<_>>();
86+
let module_id = ty.enum_.defining_module;
87+
let enum_ = ty.enum_.name;
88+
let variant = ty.variant.name;
89+
let rhs = Box::new(trivials(&mut map, args.clone()).remove(0));
90+
seq.push(Out::Exp::UnpackVariant(
91+
unpack_kind,
92+
(module_id, enum_, variant),
93+
unpack_fields,
94+
rhs,
95+
));
96+
}
97+
DataOp::VecUnpack(_ty) => {
98+
assert!(args.len() == 1, "VecUnpack expects a single argument");
99+
let unpack_fields = lhs.iter().map(|r| r.name()).collect::<Vec<_>>();
100+
let rhs = Box::new(trivials(&mut map, args.clone()).remove(0));
101+
seq.push(Out::Exp::VecUnpack(unpack_fields, rhs));
102+
}
103+
// Zero-arity LHSs
104+
DataOp::VecSwap(ty) => seq.push(Out::Exp::Data {
105+
op: DataOp::VecSwap(ty),
106+
args: trivials(&mut map, args),
107+
}),
108+
DataOp::WriteRef => seq.push(Out::Exp::Data {
109+
op: DataOp::WriteRef,
110+
args: trivials(&mut map, args),
111+
}),
112+
DataOp::VecPushBack(ty) => seq.push(Out::Exp::Data {
113+
op: DataOp::VecPushBack(ty),
114+
args: trivials(&mut map, args),
115+
}),
116+
// Single-arity LHSs
117+
DataOp::ReadRef
118+
| DataOp::FreezeRef
119+
| DataOp::MutBorrowField(_)
120+
| DataOp::ImmBorrowField(_)
121+
| DataOp::VecPack(_)
122+
| DataOp::VecLen(_)
123+
| DataOp::VecImmBorrow(_)
124+
| DataOp::VecMutBorrow(_)
125+
| DataOp::VecPopBack(_)
126+
| DataOp::PackVariant(_)
127+
| DataOp::Pack(_) => {
128+
let [reg] = &lhs[..] else {
129+
panic!("Register assignment with invalid lhs {:?}", lhs);
130+
};
131+
let rvalue = rvalue(&mut map, RValue::Data { op, args });
132+
let res = map.insert(reg.name, rvalue);
133+
assert!(res.is_none());
134+
}
135+
},
118136
SI::AssignReg { lhs, rhs } => {
119137
let [reg] = &lhs[..] else {
120-
panic!("Registe assignment with invalid lhs {:?}", rhs);
138+
panic!("Register assignment with invalid lhs {:?}", lhs);
121139
};
122140
let rvalue = rvalue(&mut map, rhs);
123141
let res = map.insert(reg.name, rvalue);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
source: crates/move-decompiler/tests/tests.rs
3+
---
4+
// Auto-generated by Move decompiler
5+
6+
module e14edd90e55069be679479d7067ca9e3caf1542cf4ca5b3a827979856888dd07::andy70b;
7+
8+
// -- structs --
9+
10+
public struct ANDY70B has drop { dummy_field: bool }
11+
12+
// -- constants --
13+
14+
const C0: vector<u8> = vec![49u8, 49u8, 49u8, 49u8, 49u8, 49u8, 49u8, 49u8, 49u8, 32u8, 32u8, 32u8];
15+
16+
const C1: vector<u8> = vec![65u8, 78u8, 68u8, 89u8, 55u8, 48u8, 66u8, 32u8, 32u8, 32u8, 32u8, 32u8];
17+
18+
const C2: vector<u8> = vec![65u8, 78u8, 68u8, 89u8, 55u8, 48u8, 66u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8];
19+
20+
const C3: vector<u8> = vec![84u8, 104u8, 101u8, 32u8, 102u8, 105u8, 114u8, 115u8, 116u8, 32u8, 116u8, 114u8, 117u8, 116u8, 104u8, 32u8, 116u8, 101u8, 114u8, 109u8, 105u8, 110u8, 97u8, 108u8, 32u8, 99u8, 111u8, 105u8, 110u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8];
21+
22+
const C4: vector<u8> = vec![104u8, 116u8, 116u8, 112u8, 115u8, 58u8, 47u8, 47u8, 100u8, 100u8, 46u8, 100u8, 101u8, 120u8, 115u8, 99u8, 114u8, 101u8, 101u8, 110u8, 101u8, 114u8, 46u8, 99u8, 111u8, 109u8, 47u8, 100u8, 115u8, 45u8, 100u8, 97u8, 116u8, 97u8, 47u8, 116u8, 111u8, 107u8, 101u8, 110u8, 115u8, 47u8, 115u8, 111u8, 108u8, 97u8, 110u8, 97u8, 47u8, 54u8, 57u8, 80u8, 52u8, 99u8, 106u8, 86u8, 120u8, 83u8, 98u8, 114u8, 71u8, 102u8, 107u8, 115u8, 53u8, 98u8, 99u8, 65u8, 67u8, 53u8, 121u8, 74u8, 71u8, 119u8, 82u8, 66u8, 118u8, 121u8, 101u8, 90u8, 57u8, 101u8, 120u8, 68u8, 109u8, 104u8, 111u8, 86u8, 67u8, 105u8, 116u8, 86u8, 84u8, 46u8, 112u8, 110u8, 103u8, 63u8, 99u8, 108u8, 97u8, 105u8, 109u8, 73u8, 100u8, 61u8, 75u8, 112u8, 106u8, 88u8, 75u8, 54u8, 78u8, 72u8, 73u8, 102u8, 114u8, 66u8, 78u8, 118u8, 69u8, 90u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8];
23+
24+
// -- functions --
25+
26+
fun init(l0: 0xe14edd90e55069be679479d7067ca9e3caf1542cf4ca5b3a827979856888dd07::andy70b::ANDY70B, l1: &mut 0x2::tx_context::TxContext) {
27+
{
28+
let l2 = 0xe14edd90e55069be679479d7067ca9e3caf1542cf4ca5b3a827979856888dd07::andy70b::trim_right(C0);
29+
let l4 = &l2.len();
30+
let l10 = 0x1::ascii::into_bytes(0x1::string::to_ascii(0x1::string::utf8(0xe14edd90e55069be679479d7067ca9e3caf1542cf4ca5b3a827979856888dd07::andy70b::trim_right(C1))));
31+
let l9 = 0xe14edd90e55069be679479d7067ca9e3caf1542cf4ca5b3a827979856888dd07::andy70b::trim_right(C2);
32+
let l5 = 0xe14edd90e55069be679479d7067ca9e3caf1542cf4ca5b3a827979856888dd07::andy70b::trim_right(C3);
33+
let l6 = 0xe14edd90e55069be679479d7067ca9e3caf1542cf4ca5b3a827979856888dd07::andy70b::trim_right(C4);
34+
if (&l6.len() == 0u64) {
35+
let l3 = 0x1::option::none();
36+
} else {
37+
l3 = 0x1::option::some(0x2::url::new_unsafe_from_bytes(l6));
38+
};
39+
let l7 = l3;
40+
let (reg_32, reg_33) = 0x2::coin::create_currency(l0, l4 as u8, l10, l9, l5, l7, l1);
41+
let l8 = reg_33;
42+
0x2::transfer::public_transfer(reg_32, 0x2::tx_context::sender(freeze(l1)));
43+
0x2::transfer::public_share_object(l8);
44+
return
45+
}
46+
}
47+
48+
fun trim_right(l0: vector<u8>): vector<u8> {
49+
{
50+
let l2 = l0;
51+
let l1 = 32u8;
52+
let l3 = &l1;
53+
loop {
54+
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)