Skip to content

Commit 1f511ec

Browse files
authored
Merge pull request casper-network#5207 from mpapierski/update-cargo-casper-2
Fix segfault in cargo-casper
2 parents 3fef4e0 + 399d3a1 commit 1f511ec

File tree

3 files changed

+36
-47
lines changed

3 files changed

+36
-47
lines changed

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 14 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,15 @@
1-
use core::slice;
2-
use std::{ffi::c_void, path::Path, ptr::NonNull};
1+
use std::{mem::MaybeUninit, path::Path};
32

43
use libloading::{Library, Symbol};
54

65
const COLLECT_SCHEMA_FUNC: &str = "__cargo_casper_collect_schema";
76

8-
type CollectSchema = unsafe extern "C" fn(
9-
callback: unsafe extern "C" fn(*const u8, usize, *mut c_void),
10-
ctx: *mut c_void,
11-
);
7+
type CollectSchema = unsafe extern "C" fn(size_ptr: *mut u64) -> *mut u8;
128

139
pub(crate) struct Artifact {
1410
library: Library,
1511
}
1612

17-
unsafe extern "C" fn collect_schema_cb<T: FnOnce(&[u8])>(
18-
data_ptr: *const u8,
19-
data_len: usize,
20-
ctx: *mut c_void,
21-
) {
22-
let ptr: *mut Option<T> = ctx as _;
23-
let data = slice::from_raw_parts(data_ptr, data_len);
24-
let ptr = (*ptr).take().unwrap();
25-
ptr(data);
26-
}
27-
28-
fn collect_schema_helper<T>(library: &Library, cb: T)
29-
where
30-
T: for<'a> FnOnce(&'a [u8]),
31-
{
32-
let collect_schema: Symbol<CollectSchema> =
33-
unsafe { library.get(COLLECT_SCHEMA_FUNC.as_bytes()).unwrap() };
34-
35-
let ptr = NonNull::from(&Some(cb));
36-
unsafe { collect_schema(collect_schema_cb::<T>, ptr.as_ptr() as *mut _) };
37-
}
38-
3913
impl Artifact {
4014
pub(crate) fn from_path<P: AsRef<Path>>(
4115
artifact_path: P,
@@ -50,12 +24,17 @@ impl Artifact {
5024
/// This returns a [`serde_json::Value`] to skip validation of a `Schema` object structure which
5125
/// (in theory) can differ.
5226
pub(crate) fn collect_schema(&self) -> serde_json::Result<serde_json::Value> {
53-
let mut value = None;
54-
55-
collect_schema_helper(&self.library, |data| {
56-
value = Some(serde_json::from_slice(data));
57-
});
58-
59-
value.expect("Callback called")
27+
let collect_schema: Symbol<CollectSchema> =
28+
unsafe { self.library.get(COLLECT_SCHEMA_FUNC.as_bytes()).unwrap() };
29+
30+
let json_bytes = {
31+
let mut value = MaybeUninit::uninit();
32+
let leaked_json_bytes = unsafe { collect_schema(value.as_mut_ptr()) };
33+
let size = unsafe { value.assume_init() };
34+
let length: usize = size.try_into().unwrap();
35+
unsafe { Vec::from_raw_parts(leaked_json_bytes, length, length) }
36+
};
37+
38+
serde_json::from_slice(&json_bytes)
6039
}
6140
}

smart_contracts/sdk/src/abi_generator.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::ffi::c_void;
1+
use core::{mem, ptr::NonNull};
22

33
use crate::{
44
abi::{Declaration, Definitions},
@@ -43,11 +43,16 @@ pub static ABI_COLLECTORS: [fn(&mut crate::abi::Definitions)] = [..];
4343
#[linkme(crate = crate::linkme)]
4444
pub static MESSAGES: [Message] = [..];
4545

46+
/// This function is called by the host to collect the schema from the contract.
47+
///
48+
/// This is considered internal implementation detail and should not be used directly.
49+
/// Primary user of this API is `cargo-casper` tool that will use it to extract scheama from the
50+
/// contract.
51+
///
52+
/// # Safety
53+
/// Pointer to json bytes passed to the callback is valid only within the scope of that function.
4654
#[export_name = "__cargo_casper_collect_schema"]
47-
pub extern "C" fn cargo_casper_collect_schema(
48-
callback: extern "C" fn(*const u8, usize, *mut c_void),
49-
ctx: *mut c_void,
50-
) {
55+
pub unsafe extern "C" fn cargo_casper_collect_schema(size_ptr: *mut u64) -> *mut u8 {
5156
// Collect definitions
5257
let definitions = {
5358
let mut definitions = Definitions::default();
@@ -95,6 +100,11 @@ pub extern "C" fn cargo_casper_collect_schema(
95100
};
96101

97102
// Write the schema using the provided writer
98-
let json_bytes = serde_json::to_vec(&schema).expect("Serialized schema");
99-
callback(json_bytes.as_ptr(), json_bytes.len(), ctx);
103+
let mut json_bytes = serde_json::to_vec(&schema).expect("Serialized schema");
104+
NonNull::new(size_ptr)
105+
.expect("expected non-null ptr")
106+
.write(json_bytes.len().try_into().expect("usize to u64"));
107+
let ptr = json_bytes.as_mut_ptr();
108+
mem::forget(json_bytes);
109+
ptr
100110
}

0 commit comments

Comments
 (0)