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

[Compiler-v2] check access for structs #12821

Merged
merged 3 commits into from
Apr 10, 2024
Merged

[Compiler-v2] check access for structs #12821

merged 3 commits into from
Apr 10, 2024

Conversation

rahxephon89
Copy link
Contributor

@rahxephon89 rahxephon89 commented Apr 8, 2024

Description

This PR adds the check to guarantee a struct can only be accessed within the module that defines it.

Close #11014
Close #12820

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Performance improvement
  • Refactoring
  • Dependency update
  • Documentation update
  • Tests

Which Components or Systems Does This Change Impact?

  • Validator Node
  • Full Node (API, Indexer, etc.)
  • Move/Aptos Virtual Machine
  • Aptos Framework
  • Aptos CLI/SDK
  • Developer Infrastructure
  • Other (specify)

How Has This Been Tested?

  1. Existing tests;
  2. Migrated three V1 tests;
  3. New tests

Key Areas to Review

Whether all ways of accessing a struct are covered.

Checklist

  • I have read and followed the CONTRIBUTING doc
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I identified and added all stakeholders and component owners affected by this change as reviewers
  • I tested both happy and unhappy path of the functionality
  • I have made corresponding changes to the documentation

Copy link

trunk-io bot commented Apr 8, 2024

⏱️ 13h 35m total CI duration on this PR
Job Cumulative Duration Recent Runs
rust-move-unit-coverage 2h 36m 🟥🟥🟥🟥🟥 (+3 more)
rust-unit-tests 2h 🟥🟩🟩🟩 (+1 more)
rust-targeted-unit-tests 1h 31m 🟩🟩🟩🟩
rust-move-tests 1h 22m 🟩🟩🟩🟩 (+4 more)
rust-lints 53m 🟩🟩🟩🟩 (+4 more)
execution-performance / single-node-performance 47m 🟩🟩
run-tests-main-branch 36m 🟩🟩🟩🟩🟩 (+3 more)
windows-build 34m 🟩🟩
rust-smoke-tests 31m 🟩
forge-e2e-test / forge 31m 🟩🟩
rust-images / rust-all 26m 🟩🟩
forge-compat-test / forge 23m 🟩🟩
cli-e2e-tests / run-cli-tests 23m 🟩🟩
general-lints 18m 🟩🟩🟩🟩 (+4 more)
check-dynamic-deps 18m 🟩🟩🟩🟩🟩 (+4 more)
check 6m 🟩
rust-build-cached-packages 6m 🟩
semgrep/ci 4m 🟩🟩🟩🟩🟩 (+4 more)
file_change_determinator 2m 🟩🟩🟩🟩🟩 (+4 more)
file_change_determinator 2m 🟩🟩🟩🟩🟩 (+4 more)
file_change_determinator 2m 🟩🟩🟩🟩 (+4 more)
node-api-compatibility-tests / node-api-compatibility-tests 2m 🟩🟩
permission-check 30s 🟩🟩🟩🟩🟩 (+4 more)
permission-check 29s 🟩🟩🟩🟩🟩 (+4 more)
file_change_determinator 27s 🟩🟩
permission-check 27s 🟩🟩🟩🟩🟩 (+4 more)
execution-performance / file_change_determinator 25s 🟩🟩
permission-check 22s 🟩🟩🟩🟩🟩 (+4 more)
determine-docker-build-metadata 10s 🟩🟩
permission-check 6s 🟩🟩

🚨 2 jobs on the last run were significantly faster/slower than expected

Job Duration vs 7d avg Delta
rust-targeted-unit-tests 20m 7m +213%
windows-build 15m 19m -20%

settingsfeedbackdocs ⋅ learn more about trunk.io

@@ -335,7 +335,7 @@ const TEST_CONFIGS: Lazy<BTreeMap<&str, TestConfig>> = Lazy::new(|| {
include: vec!["/acquires-checker/"],
exclude: vec![],
exp_suffix: None,
options: opts.clone(),
options: opts.clone().set_experiment(Experiment::ACCESS_CHECK, false),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

skip access check for acquires-checker so that the error messages remain the same.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add this as a comment please?

@@ -430,34 +433,3 @@ move-compiler/tests/move_check/typing/while_body.exp move-compiler-v2/tests/ch
move-compiler/tests/move_check/typing/while_body_invalid.exp move-compiler-v2/tests/checking/typing/while_body_invalid.exp
move-compiler/tests/move_check/typing/while_condition.exp move-compiler-v2/tests/checking/typing/while_condition.exp
move-compiler/tests/move_check/typing/while_condition_invalid.exp move-compiler-v2/tests/checking/typing/while_condition_invalid.exp
move-compiler/tests/move_check/parser/aptos_stdlib_attributes.exp move-compiler-v2/tests/checking/attributes/aptos_stdlib_attributes.exp
Copy link
Contributor Author

Choose a reason for hiding this comment

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

After Brian's PR to fix the update tool is landed, these will be recovered.

@@ -225,17 +222,3 @@ move-compiler/tests/move_check/verification/{
single_module_invalid.move,
single_module_valid.move,
}
move-compiler/tests/move_check/unit_test/{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

After Brian's PR to fix the update tool is landed, these will be recovered.

@rahxephon89 rahxephon89 force-pushed the teng/fix-11014 branch 2 times, most recently from 382c47f to eb2c259 Compare April 8, 2024 06:27
@rahxephon89 rahxephon89 changed the title [WIP][Compiler-v2] check access for structs [Compiler-v2] check access for structs Apr 8, 2024
@rahxephon89 rahxephon89 marked this pull request as ready for review April 8, 2024 07:04
error: Invalid pack operation on external type D::G
┌─ tests/visibility-checker/pack_unpack_structs.move:13:16
13 │ public fun foo(): C::T {
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice if we could show the module header lines, since that's the controlling factor. Not sure we have those Locs easily available, though.

Please file an issue to follow up on that. It will require adding a field to ModuleData similar to the id_loc field of FunctionData. To initialize that will require adding a parameter id_loc to ModuleBuilder::translate(). Call sites to that should have it available.

mid: &ModuleId,
pat: &Pattern,
) {
match pat {
Copy link
Contributor

Choose a reason for hiding this comment

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

You can probably simplify this a bit by using Pattern::visit_pre_post.

Copy link
Contributor

@vineethk vineethk left a comment

Choose a reason for hiding this comment

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

Looking good so far.

env.diag_with_labels(Severity::Error, fun_loc, &msg, call_details);
}

/// check a struct can only be accessed within the module that defines it.
Copy link
Contributor

Choose a reason for hiding this comment

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

It is a bit misleading to say "struct can only be accessed within the module that defines it" -> struct types are indeed accessible outside of the module, just that certain privileged operations are limited to the defining module (https://aptos.dev/move/book/structs-and-resources#privileged-struct-operations).

Please update docs and maybe function names?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

/// For all function in target modules:
///
/// If `before_inlining`, then
/// - check that all function calls involving inline functions are accessible;
/// - warn about unused private functions
/// Otherwise (`!before_inlining`):
/// - check that all function calls *not* involving inline functions are accessible.
/// - check structs are not accessed across the module boundary.
Copy link
Contributor

Choose a reason for hiding this comment

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

same comment as above (certain privileged operations on structs cannot be done across module boundary).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

id,
"called",
format!(
"Invalid storage operation on external type `{}`",
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe you also fix #12820 with this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I think that's the case

| Operation::BorrowGlobal(_)
| Operation::MoveFrom
| Operation::MoveTo
if env.get_node_instantiation(*id)[0].get_struct(env).is_some() =>
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of doing this check here (the if condition), and then redoing a portion of it again inside, it may be cleaner to move the check inside (and not repeat some of the code).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

"called",
format!(
"Invalid storage operation on external type `{}`",
struct_env.get_full_name_str()
Copy link
Contributor

Choose a reason for hiding this comment

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

We could perhaps provide more information here to be more heipful to the user, similar to what we do with inaccessible calls (see third_party/move/move-compiler-v2/tests/visibility-checker/v1-typing/module_call_entry_function_was_invalid.exp for an example)?

Maybe we could have something along the lines of: "Invalid operation: storage operation <blah> on type <blah> can only be done within the defining module <blah>" ...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

id,
"accessed",
format!(
"Invalid access of field `{}` on external type `{}`",
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar note as above.

Maybe we could have something along the lines of: "Invalid field access: the field blah on type blah can only be accessed withing the defining module blah".

These can be of respite especially in the presence of inlining.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

id,
"packed",
format!(
"Invalid pack operation on external type {}",
Copy link
Contributor

Choose a reason for hiding this comment

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

We can additionally say that only the module defining the struct can create (pack) it.

I find "external type" to provide insufficient guidance to a user (it is external to what? to the module, but that is not clear and can get muddied especially with inlining and where we would point the primary error at).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

},
_ => {},
},
ExpData::Assign(_, pat, _) | ExpData::Block(_, pat, _, _) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like Lambda also has a pattern, is that a missing case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This check is performed after inlining. Do we still have Lambda then? cc @brmataptos

Copy link
Contributor

Choose a reason for hiding this comment

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

Currently, no, but you can throw it in if you want to handle future cases, maybe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

})
}
} // end 0x42::token

Copy link
Contributor

Choose a reason for hiding this comment

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

Could we add more inline tests, specifically, inline functions that do each of the restricted cases? We may then want to improve error messages for the inlined cases (like is done for visibility of calls).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -335,7 +335,7 @@ const TEST_CONFIGS: Lazy<BTreeMap<&str, TestConfig>> = Lazy::new(|| {
include: vec!["/acquires-checker/"],
exclude: vec![],
exp_suffix: None,
options: opts.clone(),
options: opts.clone().set_experiment(Experiment::ACCESS_CHECK, false),
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add this as a comment please?

Copy link
Contributor

@vineethk vineethk left a comment

Choose a reason for hiding this comment

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

Very nice! LGTM.

note: I have a comment on a minor typo.


/// check privileged operations on a struct such as storage operation, pack/unpack and field accesses
/// can only be performed within the module that defines it.
fn check_previleged_operations_on_structs(env: &GlobalEnv, fun_env: &FunctionEnv) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
fn check_previleged_operations_on_structs(env: &GlobalEnv, fun_env: &FunctionEnv) {
fn check_privileged_operations_on_structs(env: &GlobalEnv, fun_env: &FunctionEnv) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@rahxephon89 rahxephon89 enabled auto-merge (squash) April 10, 2024 19:43

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

Copy link
Contributor

✅ Forge suite compat success on aptos-node-v1.10.1 ==> 7371e5b627d164b3b82d8bc450986701cdf8851e

Compatibility test results for aptos-node-v1.10.1 ==> 7371e5b627d164b3b82d8bc450986701cdf8851e (PR)
1. Check liveness of validators at old version: aptos-node-v1.10.1
compatibility::simple-validator-upgrade::liveness-check : committed: 6274 txn/s, latency: 5245 ms, (p50: 5000 ms, p90: 7100 ms, p99: 9300 ms), latency samples: 219600
2. Upgrading first Validator to new version: 7371e5b627d164b3b82d8bc450986701cdf8851e
compatibility::simple-validator-upgrade::single-validator-upgrade : committed: 1827 txn/s, latency: 15759 ms, (p50: 18600 ms, p90: 22100 ms, p99: 22500 ms), latency samples: 91360
3. Upgrading rest of first batch to new version: 7371e5b627d164b3b82d8bc450986701cdf8851e
compatibility::simple-validator-upgrade::half-validator-upgrade : committed: 1808 txn/s, latency: 15906 ms, (p50: 19600 ms, p90: 22900 ms, p99: 23200 ms), latency samples: 90420
4. upgrading second batch to new version: 7371e5b627d164b3b82d8bc450986701cdf8851e
compatibility::simple-validator-upgrade::rest-validator-upgrade : committed: 3180 txn/s, latency: 9811 ms, (p50: 10400 ms, p90: 12300 ms, p99: 12600 ms), latency samples: 127200
5. check swarm health
Compatibility test for aptos-node-v1.10.1 ==> 7371e5b627d164b3b82d8bc450986701cdf8851e passed
Test Ok

Copy link
Contributor

✅ Forge suite realistic_env_max_load success on 7371e5b627d164b3b82d8bc450986701cdf8851e

two traffics test: inner traffic : committed: 8105 txn/s, latency: 4840 ms, (p50: 4600 ms, p90: 5700 ms, p99: 10800 ms), latency samples: 3501420
two traffics test : committed: 100 txn/s, latency: 1908 ms, (p50: 1900 ms, p90: 2100 ms, p99: 4400 ms), latency samples: 1780
Latency breakdown for phase 0: ["QsBatchToPos: max: 0.204, avg: 0.202", "QsPosToProposal: max: 0.260, avg: 0.235", "ConsensusProposalToOrdered: max: 0.460, avg: 0.416", "ConsensusOrderedToCommit: max: 0.332, avg: 0.313", "ConsensusProposalToCommit: max: 0.745, avg: 0.729"]
Max round gap was 1 [limit 4] at version 1738709. Max no progress secs was 4.650287 [limit 15] at version 1738709.
Test Ok

@rahxephon89 rahxephon89 merged commit 59586fe into main Apr 10, 2024
42 of 43 checks passed
@rahxephon89 rahxephon89 deleted the teng/fix-11014 branch April 10, 2024 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants