Skip to content

Commit

Permalink
[vm_runtime] verify modules while loading them from the store
Browse files Browse the repository at this point in the history
Modules loaded from the store weren't being verified previously. This diff allows that to happen. The work involves threading verification errors through to the protobuf error messages.

This is a blocker to making `LoadedModule` use `VerifiedModule`.

This found an interesting bug in one of our tests, where a test module we had defined was failing to verify.
  • Loading branch information
sunshowers authored and calibra-opensource committed Jun 26, 2019
1 parent 09345d3 commit 8070ea9
Show file tree
Hide file tree
Showing 21 changed files with 407 additions and 124 deletions.
1 change: 1 addition & 0 deletions common/proptest_helpers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ publish = false
edition = "2018"

[dependencies]
crossbeam = "0.7.1"
proptest = "0.9.4"
proptest-derive = "0.1.2"
32 changes: 32 additions & 0 deletions common/proptest_helpers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,45 @@ mod repeat_vec;

pub use crate::{growing_subset::GrowingSubset, repeat_vec::RepeatVec};

use crossbeam::thread;
use proptest::sample::Index as PropIndex;
use proptest_derive::Arbitrary;
use std::{
any::Any,
collections::BTreeSet,
ops::{Deref, Index as OpsIndex},
};

/// Creates a new thread with a larger stack size.
///
/// Generating some proptest values can overflow the stack. This allows test authors to work around
/// this limitation.
///
/// This is expected to be used with closure-style proptest invocations:
///
/// ```
/// use proptest::prelude::*;
/// use proptest_helpers::with_stack_size;
///
/// with_stack_size(4 * 1024 * 1024, || proptest!(|(x in 0usize..128)| {
/// // assertions go here
/// prop_assert!(x >= 0 && x < 128);
/// }));
/// ```
pub fn with_stack_size<'a, F, T>(size: usize, f: F) -> Result<T, Box<dyn Any + 'static + Send>>
where
F: FnOnce() -> T + Send + 'a,
T: Send + 'a,
{
thread::scope(|s| {
let handle = s.builder().stack_size(size).spawn(|_| f()).map_err(|err| {
let any: Box<dyn Any + 'static + Send> = Box::new(err);
any
})?;
handle.join()
})?
}

/// Given a maximum value `max` and a list of [`Index`](proptest::sample::Index) instances, picks
/// integers in the range `[0, max)` uniformly randomly and without duplication.
///
Expand Down
1 change: 1 addition & 0 deletions execution/execution_proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ protobuf = "2.6"

crypto = { path = "../../crypto/legacy_crypto" }
failure = { path = "../../common/failure_ext", package = "failure_ext" }
proptest_helpers = { path = "../../common/proptest_helpers" }
proto_conv = { path = "../../common/proto_conv", features = ["derive"] }
types = { path = "../../types" }

Expand Down
16 changes: 11 additions & 5 deletions execution/execution_proto/src/protobuf_conversion_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
ExecuteChunkRequest, ExecuteChunkResponse,
};
use proptest::prelude::*;
use proptest_helpers::with_stack_size;
use proto_conv::test_helper::assert_protobuf_encode_decode;

proptest! {
Expand All @@ -16,11 +17,6 @@ proptest! {
assert_protobuf_encode_decode(&execute_block_request);
}

#[test]
fn test_execute_block_response_roundtrip(execute_block_response in any::<ExecuteBlockResponse>()) {
assert_protobuf_encode_decode(&execute_block_response);
}

#[test]
fn test_commit_block_request_roundtrip(commit_block_request in any::<CommitBlockRequest>()) {
assert_protobuf_encode_decode(&commit_block_request);
Expand All @@ -43,3 +39,13 @@ proptest! {
assert_protobuf_encode_decode(&execute_chunk_response);
}
}

#[test]
fn test_execute_block_response_roundtrip() {
with_stack_size(4 * 1024 * 1024, || {
proptest!(|(execute_block_response in any::<ExecuteBlockResponse>())| {
assert_protobuf_encode_decode(&execute_block_response);
})
})
.unwrap();
}
6 changes: 4 additions & 2 deletions language/vm/cost_synthesis/src/stack_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,8 @@ where
let module = self
.module_cache
.get_loaded_module(&module_id)
.expect("[Module Lookup] Error while looking up module")
.expect("[Module Lookup] Invariant violation while looking up module")
.expect("[Module Lookup] Runtime error while looking up module")
.expect("[Module Lookup] Unable to find module");
let struct_def_idx = if self.struct_handle_table.contains_key(&module_id) {
self.struct_handle_table
Expand Down Expand Up @@ -400,7 +401,8 @@ where
let module = self
.module_cache
.get_loaded_module(&module_id)
.expect("[Module Lookup] Error while looking up module")
.expect("[Module Lookup] Invariant violation while looking up module")
.expect("[Module Lookup] Runtime error while looking up module")
.expect("[Module Lookup] Unable to find module");
let function_def_idx = if self.function_handle_table.contains_key(&module_id) {
*self
Expand Down
3 changes: 2 additions & 1 deletion language/vm/cost_synthesis/src/vm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ macro_rules! with_loaded_vm {
$module_cache.cache_module(root_module.clone());
let $mod = $module_cache
.get_loaded_module(&module_id)
.expect("[Module Cache] Internal error encountered when fetching module.")
.expect("[Module Lookup] Invariant violation while looking up module")
.expect("[Module Lookup] Runtime error while looking up module")
.expect("[Module Cache] Unable to find module in module cache.");
for m in modules {
$module_cache.cache_module(m);
Expand Down
10 changes: 10 additions & 0 deletions language/vm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use failure::Fail;
use std::{fmt, iter::FromIterator};
use types::{
account_address::AccountAddress,
language_storage::ModuleId,
transaction::TransactionStatus,
vm_error::{VMStatus, VMValidationStatus, VMVerificationError, VMVerificationStatus},
};
Expand Down Expand Up @@ -51,6 +52,7 @@ pub enum VMErrorKind {
ValueDeserializerError,
CodeSerializerError(BinaryError),
CodeDeserializerError(BinaryError),
Verification(Vec<VerificationStatus>),
}

#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
Expand All @@ -60,6 +62,8 @@ pub enum VerificationStatus {
/// A verification error was detected in a module. The first element is the index of the module
/// in the transaction.
Module(u16, VerificationError),
/// A verification error was detected in a dependency of a module.
Dependency(ModuleId, VerificationError),
}

#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
Expand Down Expand Up @@ -702,6 +706,9 @@ impl From<&VerificationStatus> for VMVerificationStatus {
VerificationStatus::Module(module_idx, err) => {
VMVerificationStatus::Module(*module_idx, err.into())
}
VerificationStatus::Dependency(dependency_id, err) => {
VMVerificationStatus::Dependency(dependency_id.clone(), err.into())
}
}
}
}
Expand Down Expand Up @@ -745,8 +752,11 @@ impl From<&VMErrorKind> for VMStatus {
VMErrorKind::ValueSerializerError => ExecutionStatus::ValueSerializationError,
VMErrorKind::ValueDeserializerError => ExecutionStatus::ValueDeserializationError,
VMErrorKind::DuplicateModuleName => ExecutionStatus::DuplicateModuleName,
// The below errors already have top-level VMStatus variants associated with them, so
// return those.
VMErrorKind::CodeSerializerError(err) => return VMStatus::from(err),
VMErrorKind::CodeDeserializerError(err) => return VMStatus::from(err),
VMErrorKind::Verification(statuses) => return statuses.iter().collect(),
};
VMStatus::Execution(err)
}
Expand Down
1 change: 1 addition & 0 deletions language/vm/vm_runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ config = { path = "../../../config"}
logger = { path = "../../../common/logger" }

[dev-dependencies]
assert_matches = "1.3.0"
compiler = { path = "../../compiler"}

[dependencies.prometheus]
Expand Down
Loading

0 comments on commit 8070ea9

Please sign in to comment.