Skip to content

Commit a3a669f

Browse files
author
Eduardo Leegwater Simões
authored
Merge pull request #326 from dusk-network/single-instance-per-call
One instance per contract function call
2 parents bb2f3fc + cfe6134 commit a3a669f

File tree

4 files changed

+151
-172
lines changed

4 files changed

+151
-172
lines changed

piecrust/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Changed
1515

16+
- Change to have one instance per contract function call [#325]
1617
- Upgrade `dusk-wasmtime` to version `17`
1718

1819
### Fixed
1920

21+
- Fix bad dereferences in caused by instance reclamation [#325]
2022
- Fix overflow in gas limit calculation in inter-contract call
2123

2224
## [0.15.0] - 2024-01-24
@@ -357,6 +359,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
357359
[#234]: https://github.com/dusk-network/piecrust/pull/234
358360

359361
<!-- ISSUES -->
362+
[#325]: https://github.com/dusk-network/piecrust/issues/325
360363
[#301]: https://github.com/dusk-network/piecrust/issues/313
361364
[#301]: https://github.com/dusk-network/piecrust/issues/301
362365
[#296]: https://github.com/dusk-network/piecrust/issues/296

piecrust/src/imports.rs

+19-23
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,12 @@ pub(crate) fn hq(
138138
) -> WasmtimeResult<u32> {
139139
let env = fenv.data_mut();
140140

141-
let instance = env.self_instance();
141+
let mut instance = env.self_instance();
142142

143143
let name_len = name_len as usize;
144144

145-
check_ptr(instance, name_ofs, name_len)?;
146-
check_arg(instance, arg_len)?;
145+
check_ptr(&instance, name_ofs, name_len)?;
146+
check_arg(&instance, arg_len)?;
147147

148148
let name = instance.with_memory(|buf| {
149149
// performance: use a dedicated buffer here?
@@ -163,11 +163,11 @@ pub(crate) fn hd(
163163
) -> WasmtimeResult<u32> {
164164
let env = fenv.data_mut();
165165

166-
let instance = env.self_instance();
166+
let mut instance = env.self_instance();
167167

168168
let name_len = name_len as usize;
169169

170-
check_ptr(instance, name_ofs, name_len)?;
170+
check_ptr(&instance, name_ofs, name_len)?;
171171

172172
let name = instance.with_memory(|buf| {
173173
// performance: use a dedicated buffer here?
@@ -194,13 +194,13 @@ pub(crate) fn c(
194194
) -> WasmtimeResult<i32> {
195195
let env = fenv.data_mut();
196196

197-
let instance = env.self_instance();
197+
let mut instance = env.self_instance();
198198

199199
let name_len = name_len as usize;
200200

201-
check_ptr(instance, mod_id_ofs, CONTRACT_ID_BYTES)?;
202-
check_ptr(instance, name_ofs, name_len)?;
203-
check_arg(instance, arg_len)?;
201+
check_ptr(&instance, mod_id_ofs, CONTRACT_ID_BYTES)?;
202+
check_ptr(&instance, name_ofs, name_len)?;
203+
check_arg(&instance, arg_len)?;
204204

205205
let argbuf_ofs = instance.arg_buffer_offset();
206206

@@ -222,12 +222,8 @@ pub(crate) fn c(
222222
&memory[mod_id_ofs..][..std::mem::size_of::<ContractId>()],
223223
);
224224

225-
let callee_stack_element = env
226-
.push_callstack(mod_id, callee_limit)
227-
.expect("pushing to the callstack should succeed");
228-
let callee = env
229-
.instance(&callee_stack_element.contract_id)
230-
.expect("callee instance should exist");
225+
let mut callee = env.instance(mod_id)?;
226+
env.push_callstack(mod_id, callee_limit, callee.mem_len());
231227

232228
callee.snap().map_err(|err| Error::MemorySnapshotFailure {
233229
reason: None,
@@ -242,7 +238,7 @@ pub(crate) fn c(
242238
let ret_len = callee
243239
.call(name, arg.len() as u32, callee_limit)
244240
.map_err(Error::normalize)?;
245-
check_arg(callee, ret_len as u32)?;
241+
check_arg(&callee, ret_len as u32)?;
246242

247243
// copy back result
248244
callee.read_argument(&mut memory[argbuf_ofs..][..ret_len as usize]);
@@ -291,8 +287,8 @@ pub(crate) fn emit(
291287

292288
let topic_len = topic_len as usize;
293289

294-
check_ptr(instance, topic_ofs, topic_len)?;
295-
check_arg(instance, arg_len)?;
290+
check_ptr(&instance, topic_ofs, topic_len)?;
291+
check_arg(&instance, arg_len)?;
296292

297293
let data = instance.with_arg_buf(|buf| {
298294
let arg_len = arg_len as usize;
@@ -327,7 +323,7 @@ fn feed(mut fenv: Caller<Env>, arg_len: u32) -> WasmtimeResult<()> {
327323
let env = fenv.data_mut();
328324
let instance = env.self_instance();
329325

330-
check_arg(instance, arg_len)?;
326+
check_arg(&instance, arg_len)?;
331327

332328
let data = instance.with_arg_buf(|buf| {
333329
let arg_len = arg_len as usize;
@@ -342,7 +338,7 @@ fn hdebug(mut fenv: Caller<Env>, msg_len: u32) -> WasmtimeResult<()> {
342338
let env = fenv.data_mut();
343339
let instance = env.self_instance();
344340

345-
check_arg(instance, msg_len)?;
341+
check_arg(&instance, msg_len)?;
346342

347343
Ok(instance.with_arg_buf(|buf| {
348344
let slice = &buf[..msg_len as usize];
@@ -365,7 +361,7 @@ fn limit(fenv: Caller<Env>) -> u64 {
365361

366362
fn spent(fenv: Caller<Env>) -> u64 {
367363
let env = fenv.data();
368-
let instance = env.self_instance();
364+
let mut instance = env.self_instance();
369365

370366
let limit = env.limit();
371367
let remaining = instance.get_remaining_gas();
@@ -377,7 +373,7 @@ fn panic(fenv: Caller<Env>, arg_len: u32) -> WasmtimeResult<()> {
377373
let env = fenv.data();
378374
let instance = env.self_instance();
379375

380-
check_arg(instance, arg_len)?;
376+
check_arg(&instance, arg_len)?;
381377

382378
Ok(instance.with_arg_buf(|buf| {
383379
let slice = &buf[..arg_len as usize];
@@ -392,7 +388,7 @@ fn panic(fenv: Caller<Env>, arg_len: u32) -> WasmtimeResult<()> {
392388
}
393389

394390
fn owner(fenv: Caller<Env>, mod_id_ofs: usize) -> WasmtimeResult<i32> {
395-
check_ptr(fenv.data().self_instance(), mod_id_ofs, CONTRACT_ID_BYTES)?;
391+
check_ptr(&fenv.data().self_instance(), mod_id_ofs, CONTRACT_ID_BYTES)?;
396392

397393
let env = fenv.data();
398394

piecrust/src/instance.rs

+60-36
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Copyright (c) DUSK NETWORK. All rights reserved.
66

77
use std::io;
8+
use std::mem::MaybeUninit;
89
use std::ops::{Deref, DerefMut};
910

1011
use dusk_wasmtime::{Instance, Module, Mutability, Store, ValType};
@@ -17,15 +18,47 @@ use crate::store::Memory;
1718
use crate::Error;
1819

1920
pub struct WrappedInstance {
20-
instance: Instance,
21-
arg_buf_ofs: usize,
22-
store: Store<Env>,
23-
memory: Memory,
21+
inner: *mut WrappedInstanceInner,
22+
original: bool,
23+
}
24+
25+
impl Clone for WrappedInstance {
26+
fn clone(&self) -> Self {
27+
Self {
28+
inner: self.inner,
29+
original: false,
30+
}
31+
}
32+
}
33+
34+
impl Drop for WrappedInstance {
35+
fn drop(&mut self) {
36+
if self.original {
37+
unsafe {
38+
let _ = Box::from_raw(self.inner);
39+
}
40+
}
41+
}
42+
}
43+
44+
impl Deref for WrappedInstance {
45+
type Target = WrappedInstanceInner;
46+
47+
fn deref(&self) -> &Self::Target {
48+
unsafe { &*self.inner }
49+
}
50+
}
51+
52+
impl DerefMut for WrappedInstance {
53+
fn deref_mut(&mut self) -> &mut Self::Target {
54+
unsafe { &mut *self.inner }
55+
}
2456
}
2557

2658
pub(crate) struct Env {
2759
self_id: ContractId,
2860
session: Session,
61+
instance: MaybeUninit<WrappedInstance>,
2962
}
3063

3164
impl Deref for Env {
@@ -43,20 +76,8 @@ impl DerefMut for Env {
4376
}
4477

4578
impl Env {
46-
pub fn self_instance<'b>(&self) -> &'b mut WrappedInstance {
47-
let stack_element = self
48-
.session
49-
.nth_from_top(0)
50-
.expect("there should be at least one element in the call stack");
51-
self.instance(&stack_element.contract_id)
52-
.expect("instance should exist")
53-
}
54-
55-
pub fn instance<'b>(
56-
&self,
57-
contract_id: &ContractId,
58-
) -> Option<&'b mut WrappedInstance> {
59-
self.session.instance(contract_id)
79+
pub fn self_instance(&self) -> WrappedInstance {
80+
unsafe { self.instance.assume_init_ref().clone() }
6081
}
6182

6283
pub fn limit(&self) -> u64 {
@@ -94,6 +115,7 @@ impl WrappedInstance {
94115
let env = Env {
95116
self_id: contract_id,
96117
session,
118+
instance: MaybeUninit::uninit(),
97119
};
98120

99121
let module =
@@ -177,28 +199,35 @@ impl WrappedInstance {
177199
// A memory is no longer new after one instantiation
178200
memory.is_new = false;
179201

180-
let wrapped = WrappedInstance {
202+
let inner = WrappedInstanceInner {
181203
store,
182204
instance,
183205
arg_buf_ofs,
184206
memory,
185207
};
186208

187-
Ok(wrapped)
188-
}
209+
let mut instance = WrappedInstance {
210+
inner: Box::into_raw(Box::new(inner)),
211+
original: true,
212+
};
213+
let instance_clone = instance.clone();
189214

190-
pub(crate) fn snap(&mut self) -> io::Result<()> {
191-
self.memory.snap()?;
192-
Ok(())
193-
}
215+
instance.store.data_mut().instance = MaybeUninit::new(instance_clone);
194216

195-
pub(crate) fn revert(&mut self) -> io::Result<()> {
196-
self.memory.revert()?;
197-
Ok(())
217+
Ok(instance)
198218
}
219+
}
199220

200-
pub(crate) fn apply(&mut self) -> io::Result<()> {
201-
self.memory.apply()?;
221+
pub struct WrappedInstanceInner {
222+
instance: Instance,
223+
arg_buf_ofs: usize,
224+
store: Store<Env>,
225+
memory: Memory,
226+
}
227+
228+
impl WrappedInstanceInner {
229+
pub(crate) fn snap(&mut self) -> io::Result<()> {
230+
self.memory.snap()?;
202231
Ok(())
203232
}
204233

@@ -238,11 +267,6 @@ impl WrappedInstance {
238267
self.memory.current_len
239268
}
240269

241-
/// Sets the length of the memory.
242-
pub(crate) fn set_len(&mut self, len: usize) {
243-
self.memory.current_len = len;
244-
}
245-
246270
pub(crate) fn with_arg_buf<F, R>(&self, f: F) -> R
247271
where
248272
F: FnOnce(&[u8]) -> R,
@@ -342,7 +366,7 @@ impl WrappedInstance {
342366
}
343367

344368
fn map_call_err(
345-
instance: &mut WrappedInstance,
369+
instance: &mut WrappedInstanceInner,
346370
err: dusk_wasmtime::Error,
347371
) -> Error {
348372
if instance.get_remaining_gas() == 0 {

0 commit comments

Comments
 (0)