-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[decompiler] New testing framework and enable recompilation evaluation #17099
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
base: jun/astfier-opt-enhancement
Are you sure you want to change the base?
Conversation
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
f383b1a
to
90d14a9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR upgrades the Move decompiler testing framework to enable configurable compilation, decompilation, and testing workflows. The key enhancement is adding recompilation testing to verify that decompiled code can be successfully compiled again.
- Replaces the old
datatest-stable
harness with a new flexible testing framework usinglibtest-mimic
- Introduces configurable test levels (Decompile vs Recompile) with multiple test configurations
- Adds recompilation validation that attempts to compile decompiled code and reports results
Reviewed Changes
Copilot reviewed 18 out of 32 changed files in this pull request and generated 5 comments.
Show a summary per file
File | Description |
---|---|
testsuite.rs | Complete rewrite of test framework with configurable testing pipeline and recompilation support |
lib.rs | Adds builder methods to Options struct for configuring decompiler behavior |
Cargo.toml | Adds new dependencies for the enhanced testing framework |
*.exp files | Updated baseline files showing recompilation test results |
cfg_bugs.move | New test case file for control flow recovery testing |
} | ||
} | ||
|
||
/// Represent an instance of a decompiler. The decompiler can be run end-to-end operating |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The word 'Represent' should be 'Represents' to match the grammatical structure of the sentence.
/// Represent an instance of a decompiler. The decompiler can be run end-to-end operating | |
/// Represents an instance of a decompiler. The decompiler can be run end-to-end operating |
Copilot uses AI. Check for mistakes.
#[allow(clippy::declare_interior_mutable_const)] | ||
const TEST_CONFIGS: Lazy<BTreeMap<&str, TestConfig>> = Lazy::new(|| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The clippy attribute suggests potential issues with interior mutability. Consider using a different approach like std::sync::OnceLock
or lazy initialization to avoid this warning.
#[allow(clippy::declare_interior_mutable_const)] | |
const TEST_CONFIGS: Lazy<BTreeMap<&str, TestConfig>> = Lazy::new(|| { | |
static TEST_CONFIGS: OnceLock<BTreeMap<&'static str, TestConfig>> = OnceLock::new(); | |
fn initialize_test_configs() -> BTreeMap<&'static str, TestConfig> { |
Copilot uses AI. Check for mistakes.
configs.into_iter().map(|c| (c.name, c)).collect() | ||
}); | ||
|
||
/// A function which gets a copy of a TestConfig by name. | ||
#[allow(clippy::borrow_interior_mutable_const)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Similar to the previous clippy warning, this suggests potential issues with borrowing interior mutable data. Consider refactoring to use a safer pattern.
configs.into_iter().map(|c| (c.name, c)).collect() | |
}); | |
/// A function which gets a copy of a TestConfig by name. | |
#[allow(clippy::borrow_interior_mutable_const)] | |
configs.into_iter().map(|c| (c.name, c)).collect() | |
}; | |
configs | |
}; | |
/// A function which gets a copy of a TestConfig by name. |
Copilot uses AI. Check for mistakes.
/// combination. This errors if not configuration is found for a given test path. | ||
/// TODO: we may want to add some filters here based on env vars (like the prover does), | ||
/// which allow e.g. to filter by configuration name. | ||
#[allow(clippy::borrow_interior_mutable_const)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] This is the third instance of the same clippy warning. Consider consolidating the configuration management to avoid repeated suppression of this warning.
#[allow(clippy::borrow_interior_mutable_const)] |
Copilot uses AI. Check for mistakes.
fn recompile_decompiled_code(path: &Path, config: &TestConfig, decompiled_code: &str) -> String { | ||
let temp_dir = tempdir().expect("temp dir creation for recompilation expected"); | ||
let temp_file_path = temp_dir | ||
.path() | ||
.join(path.file_name().expect("test case must have a file name")); | ||
let mut temp_file = File::create(&temp_file_path) | ||
.expect("temp file creation for saving decompiled code expected"); | ||
temp_file | ||
.write_all(decompiled_code.as_bytes()) | ||
.expect("saving decompiled code for recompilation must succeed"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function performs file I/O operations that can fail but uses expect()
for error handling. Consider returning Result<String, Error>
to provide better error information when recompilation testing fails.
fn recompile_decompiled_code(path: &Path, config: &TestConfig, decompiled_code: &str) -> String { | |
let temp_dir = tempdir().expect("temp dir creation for recompilation expected"); | |
let temp_file_path = temp_dir | |
.path() | |
.join(path.file_name().expect("test case must have a file name")); | |
let mut temp_file = File::create(&temp_file_path) | |
.expect("temp file creation for saving decompiled code expected"); | |
temp_file | |
.write_all(decompiled_code.as_bytes()) | |
.expect("saving decompiled code for recompilation must succeed"); | |
fn recompile_decompiled_code(path: &Path, config: &TestConfig, decompiled_code: &str) -> anyhow::Result<String> { | |
let temp_dir = tempdir().map_err(|e| anyhow::anyhow!("Failed to create temp dir: {}", e))?; | |
let temp_file_path = temp_dir | |
.path() | |
.join(path.file_name().ok_or_else(|| anyhow::anyhow!("Test case must have a file name"))?); | |
let mut temp_file = File::create(&temp_file_path) | |
.map_err(|e| anyhow::anyhow!("Failed to create temp file: {}", e))?; | |
temp_file | |
.write_all(decompiled_code.as_bytes()) | |
.map_err(|e| anyhow::anyhow!("Failed to write decompiled code to temp file: {}", e))?; |
Copilot uses AI. Check for mistakes.
90d14a9
to
7b28956
Compare
7b28956
to
3ad7354
Compare
0d88c59
to
ae6e4ab
Compare
3ad7354
to
0bd67b8
Compare
ae6e4ab
to
b3cbec9
Compare
0bd67b8
to
4a581e5
Compare
b3cbec9
to
bf03c95
Compare
4a581e5
to
6a1fdf6
Compare
bf03c95
to
32167ce
Compare
6a1fdf6
to
be9f1c6
Compare
32167ce
to
d93a1a3
Compare
be9f1c6
to
f1f7dc9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach looks good for now, though we may want to refactor this and add it as a more general feature directly to the txn framework. No need to worry about this, I will look at this later for the assembler.
} | ||
} | ||
|
||
/// Represent an instance of a decompiler. The decompiler can be run end-to-end operating | ||
/// on files, or incrementally without already deserialized modules and scripts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was meant to be 'with' instead of 'without'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, should be "with". Will fix!
@@ -70,3 +69,23 @@ module 0x99::noexit_loops { | |||
loop continue | |||
} | |||
} | |||
|
|||
--- unable to recompile the decompiled code: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a bug for this? Could also reuse a cover bug which we mention by bug number in noexit_loops.move. Those things can otherwise easily get forgotten in the noise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I have tracked those issues, and I am fixing them at this point.
@@ -71,3 +70,14 @@ module 0x1::fixed_point32 { | |||
_t2 | |||
} | |||
} | |||
|
|||
--- unable to recompile the decompiled code: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here and elswhere, lets use a cover bug to track? Also ok to not track if you feel comfortable with just remembering it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
That would be much appreciated! I expect to fix all recompilation issues and then switch to transactional tests next week the latest. |
d93a1a3
to
c1dc305
Compare
f1f7dc9
to
636926d
Compare
Description
This PR upgrade the decompiler testing framework to allow configurable compilation, decompilation, and testing.
It also enables testing of recompilation of decompiled code.
How Has This Been Tested?
Type of Change
Which Components or Systems Does This Change Impact?