Skip to content

Commit b07fb89

Browse files
authored
Merge branch 'main' into dynamic-field-uid-fix
2 parents 58462ac + a9e7d48 commit b07fb89

File tree

5 files changed

+215
-38
lines changed

5 files changed

+215
-38
lines changed

crates/move-model/src/model.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4073,6 +4073,11 @@ impl GlobalEnv {
40734073
self.sui_tx_context_epoch_timestamp_ms_qid(),
40744074
self.sui_tx_context_reference_gas_price_qid(),
40754075
self.sui_tx_context_gas_price_qid(),
4076+
// std::type_name native functions
4077+
self.std_type_name_with_defining_ids_qid(),
4078+
self.std_type_name_with_original_ids_qid(),
4079+
self.std_type_name_defining_id_qid(),
4080+
self.std_type_name_original_id_qid(),
40764081
]
40774082
.into_iter()
40784083
.filter_map(|x| x)

crates/move-prover-boogie-backend/src/boogie_backend/bytecode_translator.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,51 @@ impl<'env> BoogieTranslator<'env> {
248248
emitln!(self.writer);
249249
}
250250

251+
/// Emit uninterpreted Boogie function declarations for std::type_name native functions.
252+
/// These allow type_name functions to be used in quantifiers.
253+
fn emit_type_name_functions(&self, fun_env: &FunctionEnv, mono_info: &MonoInfo) {
254+
let type_name_fns = [
255+
self.env.std_type_name_with_defining_ids_qid(),
256+
self.env.std_type_name_with_original_ids_qid(),
257+
self.env.std_type_name_defining_id_qid(),
258+
self.env.std_type_name_original_id_qid(),
259+
];
260+
if !type_name_fns
261+
.into_iter()
262+
.flatten()
263+
.any(|id| id == fun_env.get_qualified_id())
264+
{
265+
return;
266+
}
267+
268+
let empty = &BTreeSet::new();
269+
for type_inst in mono_info
270+
.funs
271+
.get(&(fun_env.get_qualified_id(), FunctionVariant::Baseline))
272+
.unwrap_or(empty)
273+
{
274+
emitln!(
275+
self.writer,
276+
"function {}() returns ({});",
277+
boogie_function_name(fun_env, type_inst, FunctionTranslationStyle::Default),
278+
fun_env
279+
.get_return_types()
280+
.iter()
281+
.enumerate()
282+
.map(|(idx, ty)| {
283+
let ty = ty.instantiate(type_inst);
284+
format!(
285+
"$ret{}: {}",
286+
idx,
287+
boogie_type(self.env, ty.skip_reference())
288+
)
289+
})
290+
.join(", "),
291+
);
292+
emitln!(self.writer);
293+
}
294+
}
295+
251296
// Generate object::borrow_uid function
252297
fn translate_object_borrow_uid(&self, suffix: &str, obj_name: &str) {
253298
emitln!(
@@ -474,6 +519,7 @@ impl<'env> BoogieTranslator<'env> {
474519
self.emit_uninterpreted_native_pure(fun_env, type_inst);
475520
}
476521
}
522+
self.emit_type_name_functions(fun_env, &mono_info);
477523
continue;
478524
}
479525

crates/move-prover-boogie-backend/src/boogie_backend/runner.rs

Lines changed: 84 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub fn run_with_timeout(args: &[String], timeout: Duration) -> Result<Output> {
4444
use nix::sys::signal::{self, Signal};
4545
use nix::unistd::Pid;
4646
use std::os::unix::process::CommandExt;
47+
use std::time::Instant;
4748

4849
let mut child = Command::new(&args[0])
4950
.args(&args[1..])
@@ -54,26 +55,48 @@ pub fn run_with_timeout(args: &[String], timeout: Duration) -> Result<Output> {
5455

5556
let pid = child.id() as i32;
5657

57-
match child.wait_timeout(timeout)? {
58-
Some(status) => {
59-
let stdout = child.stdout.take().unwrap();
60-
let stderr = child.stderr.take().unwrap();
61-
62-
use std::io::Read;
63-
let mut stdout_bytes = Vec::new();
64-
let mut stderr_bytes = Vec::new();
65-
std::io::BufReader::new(stdout).read_to_end(&mut stdout_bytes)?;
66-
std::io::BufReader::new(stderr).read_to_end(&mut stderr_bytes)?;
67-
68-
Ok(Output {
69-
status,
70-
stdout: stdout_bytes,
71-
stderr: stderr_bytes,
72-
})
73-
}
74-
None => {
58+
let stdout = child.stdout.take().unwrap();
59+
let stderr = child.stderr.take().unwrap();
60+
61+
let stdout_thread = std::thread::spawn(move || {
62+
use std::io::Read;
63+
let mut bytes = Vec::new();
64+
std::io::BufReader::new(stdout).read_to_end(&mut bytes).ok();
65+
bytes
66+
});
67+
68+
let stderr_thread = std::thread::spawn(move || {
69+
use std::io::Read;
70+
let mut bytes = Vec::new();
71+
std::io::BufReader::new(stderr).read_to_end(&mut bytes).ok();
72+
bytes
73+
});
74+
75+
let start = Instant::now();
76+
loop {
77+
let elapsed = start.elapsed();
78+
if elapsed >= timeout {
7579
let _ = signal::killpg(Pid::from_raw(pid), Signal::SIGKILL);
76-
Err(Error::new(ErrorKind::TimedOut, "Process timed out"))
80+
let _ = stdout_thread.join();
81+
let _ = stderr_thread.join();
82+
return Err(Error::new(ErrorKind::TimedOut, "Process timed out"));
83+
}
84+
85+
let remaining = timeout - elapsed;
86+
let poll = remaining.min(Duration::from_millis(100));
87+
88+
match child.wait_timeout(poll)? {
89+
Some(status) => {
90+
let stdout_bytes = stdout_thread.join().unwrap_or_default();
91+
let stderr_bytes = stderr_thread.join().unwrap_or_default();
92+
93+
return Ok(Output {
94+
status,
95+
stdout: stdout_bytes,
96+
stderr: stderr_bytes,
97+
});
98+
}
99+
None => {}
77100
}
78101
}
79102
}
@@ -165,6 +188,7 @@ pub fn run_with_timeout_and_line_callback<F: FnMut(&str) + Send>(
165188
#[cfg(windows)]
166189
pub fn run_with_timeout(args: &[String], timeout: Duration) -> Result<Output> {
167190
use std::os::windows::process::CommandExt;
191+
use std::time::Instant;
168192

169193
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
170194

@@ -177,28 +201,50 @@ pub fn run_with_timeout(args: &[String], timeout: Duration) -> Result<Output> {
177201

178202
let pid = child.id();
179203

180-
match child.wait_timeout(timeout)? {
181-
Some(status) => {
182-
let stdout = child.stdout.take().unwrap();
183-
let stderr = child.stderr.take().unwrap();
184-
185-
use std::io::Read;
186-
let mut stdout_bytes = Vec::new();
187-
let mut stderr_bytes = Vec::new();
188-
std::io::BufReader::new(stdout).read_to_end(&mut stdout_bytes)?;
189-
std::io::BufReader::new(stderr).read_to_end(&mut stderr_bytes)?;
190-
191-
Ok(Output {
192-
status,
193-
stdout: stdout_bytes,
194-
stderr: stderr_bytes,
195-
})
196-
}
197-
None => {
204+
let stdout = child.stdout.take().unwrap();
205+
let stderr = child.stderr.take().unwrap();
206+
207+
let stdout_thread = std::thread::spawn(move || {
208+
use std::io::Read;
209+
let mut bytes = Vec::new();
210+
std::io::BufReader::new(stdout).read_to_end(&mut bytes).ok();
211+
bytes
212+
});
213+
214+
let stderr_thread = std::thread::spawn(move || {
215+
use std::io::Read;
216+
let mut bytes = Vec::new();
217+
std::io::BufReader::new(stderr).read_to_end(&mut bytes).ok();
218+
bytes
219+
});
220+
221+
let start = Instant::now();
222+
loop {
223+
let elapsed = start.elapsed();
224+
if elapsed >= timeout {
198225
let _ = Command::new("taskkill")
199226
.args(&["/F", "/T", "/PID", &pid.to_string()])
200227
.output();
201-
Err(Error::new(ErrorKind::TimedOut, "Process timed out"))
228+
let _ = stdout_thread.join();
229+
let _ = stderr_thread.join();
230+
return Err(Error::new(ErrorKind::TimedOut, "Process timed out"));
231+
}
232+
233+
let remaining = timeout - elapsed;
234+
let poll = remaining.min(Duration::from_millis(100));
235+
236+
match child.wait_timeout(poll)? {
237+
Some(status) => {
238+
let stdout_bytes = stdout_thread.join().unwrap_or_default();
239+
let stderr_bytes = stderr_thread.join().unwrap_or_default();
240+
241+
return Ok(Output {
242+
status,
243+
stdout: stdout_bytes,
244+
stderr: stderr_bytes,
245+
});
246+
}
247+
None => {}
202248
}
203249
}
204250
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/// Test that type_name functions can be used as Boogie functions in specs.
2+
/// The type_name functions are marked #[ext(pure)] and called from non-pure
3+
/// functions, which are then verified.
4+
module 0x42::type_name_pure;
5+
6+
use std::type_name;
7+
#[spec_only]
8+
use prover::prover::ensures;
9+
10+
public struct MyCoin has drop {}
11+
12+
#[ext(pure)]
13+
public fun get_type_name(): type_name::TypeName {
14+
type_name::with_defining_ids<MyCoin>()
15+
}
16+
17+
#[ext(pure)]
18+
public fun get_original_type_name(): type_name::TypeName {
19+
type_name::with_original_ids<MyCoin>()
20+
}
21+
22+
#[ext(pure)]
23+
public fun get_defining_id(): address {
24+
type_name::defining_id<MyCoin>()
25+
}
26+
27+
#[ext(pure)]
28+
public fun get_original_id(): address {
29+
type_name::original_id<MyCoin>()
30+
}
31+
32+
public fun use_type_name(): type_name::TypeName {
33+
get_type_name()
34+
}
35+
36+
public fun use_original_type_name(): type_name::TypeName {
37+
get_original_type_name()
38+
}
39+
40+
public fun use_defining_id(): address {
41+
get_defining_id()
42+
}
43+
44+
public fun use_original_id(): address {
45+
get_original_id()
46+
}
47+
48+
#[spec(prove)]
49+
fun use_type_name_spec(): type_name::TypeName {
50+
let result = use_type_name();
51+
ensures(result == get_type_name());
52+
result
53+
}
54+
55+
#[spec(prove)]
56+
fun use_original_type_name_spec(): type_name::TypeName {
57+
let result = use_original_type_name();
58+
ensures(result == get_original_type_name());
59+
result
60+
}
61+
62+
#[spec(prove)]
63+
fun use_defining_id_spec(): address {
64+
let result = use_defining_id();
65+
ensures(result == get_defining_id());
66+
result
67+
}
68+
69+
#[spec(prove)]
70+
fun use_original_id_spec(): address {
71+
let result = use_original_id();
72+
ensures(result == get_original_id());
73+
result
74+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
source: crates/sui-prover/tests/integration.rs
3+
assertion_line: 297
4+
expression: output
5+
---
6+
Verification successful

0 commit comments

Comments
 (0)