From: Owen Avery <[email protected]>
This should remove a use-after-free as well as simplify the FFI
interface.
gcc/rust/ChangeLog:
* ast/rust-fmt.cc (Pieces::collect): Handle changes to ffi
interface.
(Pieces::~Pieces): Remove function definition.
(Pieces::Pieces): Likewise.
(Pieces::operator=): Likewise.
* ast/rust-fmt.h: Include "optional.h".
(rust_ffi_alloc): New extern "C" function declaration.
(rust_ffi_dealloc): Likewise.
(class FFIVec): New class.
(class FFIOpt): Likewise.
(RustHamster::RustHamster): New constructor accepting const
std::string reference.
(struct FormatSpec): Use FFIOpt.
(struct PieceSlice): Remove struct.
(struct RustString): Likewise.
(struct FormatArgsHandle): Likewise.
(collect_pieces): Change function signature.
(clone_pieces): Likewise.
(destroy_pieces): Remove extern "C" function declaration.
(Pieces::~Pieces): Remove function declaration.
(Pieces::operator=): Likewise.
(Pieces::get_pieces): Handle changes to class fields.
(Pieces::Pieces): Remove copy and move constructor declarations,
adjust signature of remaining constructor declaration.
(Pieces::pieces_vector): Remove member variable.
(Pieces::handle): Likewise.
(Pieces::data): Add member variable.
* expand/rust-macro-builtins-asm.cc (expand_inline_asm_strings):
Use references to avoid copying.
libgrust/ChangeLog:
* libformat_parser/src/lib.rs (struct FFIVec): New.
(trait StringLeakExt): Remove.
(struct FFIOpt): New.
(trait IntoFFI): Adjust implementation for Option.
(struct RustHamster): Add lifetime and adjust conversion to and
from &str.
(enum Piece): Adjust definition to handle changes to
RustHamster.
(struct Argument): Likewise.
(struct FormatSpec): Use FFIOpt and RustHamster.
(enum Position): Use RustHamster.
(enum Count): Likewise.
(struct PieceSlice): Replace with...
(typedef PieceVec): ...this.
(struct RustString): Remove.
(struct FormatArgsHandle): Likewise.
(fn collect_pieces): Adjust signature, greatly simplifying
implementation.
(fn clone_pieces): Likewise.
(fn destroy_pieces): Remove.
(trait LayoutExt): New.
(fn rust_ffi_alloc): New.
(fn rust_ffi_dealloc): New.
Signed-off-by: Owen Avery <[email protected]>
---
gcc/rust/ast/rust-fmt.cc | 38 +--
gcc/rust/ast/rust-fmt.h | 195 +++++++----
gcc/rust/expand/rust-macro-builtins-asm.cc | 4 +-
libgrust/libformat_parser/src/lib.rs | 359 +++++++++++++--------
4 files changed, 378 insertions(+), 218 deletions(-)
diff --git a/gcc/rust/ast/rust-fmt.cc b/gcc/rust/ast/rust-fmt.cc
index a29c8203ae8..21f4f03bb6f 100644
--- a/gcc/rust/ast/rust-fmt.cc
+++ b/gcc/rust/ast/rust-fmt.cc
@@ -32,41 +32,11 @@ Pieces
Pieces::collect (const std::string &to_parse, bool append_newline,
ffi::ParseMode parse_mode)
{
- auto handle
- = ffi::collect_pieces (to_parse.c_str (), append_newline, parse_mode);
-
- // this performs multiple copies, can we avoid them maybe?
- // TODO: Instead of just creating a vec of, basically, `ffi::Piece`s, we
- // should transform them into the proper C++ type which we can work with. so
- // transform all the strings into C++ strings? all the Option<T> into
- // tl::optional<T>?
- auto pieces_vector = std::vector<ffi::Piece> (handle.piece_slice.base_ptr,
- handle.piece_slice.base_ptr
- + handle.piece_slice.len);
-
- return Pieces (handle, std::move (pieces_vector));
-}
-
-Pieces::~Pieces () { ffi::destroy_pieces (handle); }
-
-Pieces::Pieces (const Pieces &other) : pieces_vector (other.pieces_vector)
-{
- handle = ffi::clone_pieces (other.handle);
+ Pieces ret (to_parse, ffi::FFIVec<ffi::Piece> ());
+ ret.data->second = ffi::collect_pieces (ffi::RustHamster (ret.data->first),
+ append_newline, parse_mode);
+ return ret;
}
-Pieces &
-Pieces::operator= (const Pieces &other)
-{
- handle = ffi::clone_pieces (other.handle);
- pieces_vector = other.pieces_vector;
-
- return *this;
-}
-
-Pieces::Pieces (Pieces &&other)
- : pieces_vector (std::move (other.pieces_vector)),
- handle (clone_pieces (other.handle))
-{}
-
} // namespace Fmt
} // namespace Rust
diff --git a/gcc/rust/ast/rust-fmt.h b/gcc/rust/ast/rust-fmt.h
index 3722db291ab..c23499c3709 100644
--- a/gcc/rust/ast/rust-fmt.h
+++ b/gcc/rust/ast/rust-fmt.h
@@ -20,20 +20,138 @@
#define RUST_FMT_H
#include "rust-system.h"
-
-// FIXME: How to encode Option?
+#include "optional.h"
namespace Rust {
namespace Fmt {
namespace ffi {
+extern "C" {
+
+unsigned char *rust_ffi_alloc (size_t count, size_t elem_size, size_t align);
+
+void rust_ffi_dealloc (unsigned char *data, size_t count, size_t elem_size,
+ size_t align);
+
+} // extern "C"
+
+template <typename T> class FFIVec
+{
+ T *data;
+ size_t len;
+ size_t cap;
+
+public:
+ FFIVec () : data ((T *) alignof (T)), len (0), cap (0) {}
+
+ FFIVec (const FFIVec &) = delete;
+ FFIVec &operator= (const FFIVec &) = delete;
+
+ FFIVec (FFIVec &&other) : data (other.data), len (other.len), cap (other.cap)
+ {
+ other.data = (T *) alignof (T);
+ other.len = 0;
+ other.cap = 0;
+ }
+
+ FFIVec &operator= (FFIVec &&other)
+ {
+ this->~FFIVec ();
+ new (this) FFIVec (std::move (other));
+ return *this;
+ }
+
+ ~FFIVec ()
+ {
+ // T can't be zero-sized
+ if (cap)
+ rust_ffi_dealloc ((unsigned char *) data, cap, sizeof (T), alignof (T));
+ }
+
+ size_t size () const { return len; }
+
+ const T &operator[] (size_t idx) const
+ {
+ rust_assert (idx <= len);
+ return data[idx];
+ }
+
+ T *begin () { return data; }
+ const T *begin () const { return data; }
+ T *end () { return data + len; }
+ const T *end () const { return data + len; }
+};
+
+template <typename T> class FFIOpt
+{
+ struct alignas (T) Inner
+ {
+ char data[sizeof (T)];
+ } inner;
+ bool is_some;
+
+public:
+ template <typename U> FFIOpt (U &&val) : is_some (true)
+ {
+ new (inner.data) T (std::forward<U> (val));
+ }
+
+ FFIOpt () : is_some (false) {}
+
+ FFIOpt (const FFIOpt &other) : is_some (other.is_some)
+ {
+ if (is_some)
+ new (inner.data) T (*(const T *) other.inner.data);
+ }
+
+ FFIOpt (FFIOpt &&other) : is_some (other.is_some)
+ {
+ if (is_some)
+ new (inner.data) T (std::move (*(const T *) other.inner.data));
+ }
+
+ ~FFIOpt ()
+ {
+ if (is_some)
+ ((T *) inner.data)->~T ();
+ }
+
+ FFIOpt &operator= (const FFIOpt &other)
+ {
+ this->~FFIOpt ();
+ new (this) FFIOpt (other);
+ return *this;
+ }
+
+ FFIOpt &operator= (FFIOpt &&other)
+ {
+ this->~FFIOpt ();
+ new (this) FFIOpt (std::move (other));
+ return *this;
+ }
+
+ tl::optional<std::reference_wrapper<T>> get_opt ()
+ {
+ return (T *) inner.data;
+ }
+
+ tl::optional<std::reference_wrapper<const T>> get_opt () const
+ {
+ return (const T *) inner.data;
+ }
+};
+
struct RustHamster
{
const char *ptr;
size_t len;
std::string to_string () const;
+
+ explicit RustHamster (const std::string &str)
+ : ptr (str.data ()), len (str.size ())
+ {}
};
/// Enum of alignments which are supported.
@@ -166,33 +284,33 @@ struct Count
struct FormatSpec
{
/// Optionally specified character to fill alignment with.
- const uint32_t *fill;
+ FFIOpt<uint32_t> fill;
/// Span of the optionally specified fill character.
- const InnerSpan *fill_span;
+ FFIOpt<InnerSpan> fill_span;
/// Optionally specified alignment.
Alignment align;
/// The `+` or `-` flag.
- const Sign *sign;
+ FFIOpt<Sign> sign;
/// The `#` flag.
bool alternate;
/// The `0` flag.
bool zero_pad;
/// The `x` or `X` flag. (Only for `Debug`.)
- const DebugHex *debug_hex;
+ FFIOpt<DebugHex> debug_hex;
/// The integer precision to use.
Count precision;
/// The span of the precision formatting flag (for diagnostics).
- const InnerSpan *precision_span;
+ FFIOpt<InnerSpan> precision_span;
/// The string width requested for the resulting format.
Count width;
/// The span of the width formatting flag (for diagnostics).
- const InnerSpan *width_span;
+ FFIOpt<InnerSpan> width_span;
/// The descriptor string representing the name of the format desired for
/// this argument, this can be empty or any number of characters, although
/// it is required to be one word.
RustHamster ty;
/// The span of the descriptor string (for diagnostics).
- const InnerSpan *ty_span;
+ FFIOpt<InnerSpan> ty_span;
};
/// Representation of an argument specification.
@@ -238,26 +356,6 @@ struct Piece
};
};
-struct PieceSlice
-{
- const Piece *base_ptr;
- size_t len;
- size_t cap;
-};
-
-struct RustString
-{
- const unsigned char *ptr;
- size_t len;
- size_t cap;
-};
-
-struct FormatArgsHandle
-{
- PieceSlice piece_slice;
- RustString rust_string;
-};
-
enum ParseMode
{
Format = 0,
@@ -266,12 +364,10 @@ enum ParseMode
extern "C" {
-FormatArgsHandle collect_pieces (const char *input, bool append_newline,
- ParseMode parse_mode);
+FFIVec<Piece> collect_pieces (RustHamster input, bool append_newline,
+ ParseMode parse_mode);
-FormatArgsHandle clone_pieces (const FormatArgsHandle &);
-
-void destroy_pieces (FormatArgsHandle);
+FFIVec<Piece> clone_pieces (const FFIVec<Piece> &);
} // extern "C"
@@ -281,33 +377,20 @@ struct Pieces
{
static Pieces collect (const std::string &to_parse, bool append_newline,
ffi::ParseMode parse_mode);
- ~Pieces ();
-
- Pieces (const Pieces &other);
- Pieces &operator= (const Pieces &other);
- Pieces (Pieces &&other);
-
- const std::vector<ffi::Piece> &get_pieces () const { return pieces_vector; }
-
- // {
- // slice = clone_pieces (&other.slice);
- // to_parse = other.to_parse;
-
- // return *this;
- // }
+ const ffi::FFIVec<ffi::Piece> &get_pieces () const { return data->second; }
private:
- Pieces (ffi::FormatArgsHandle handle, std::vector<ffi::Piece>
&&pieces_vector)
- : pieces_vector (std::move (pieces_vector)), handle (handle)
+ Pieces (std::string str, ffi::FFIVec<ffi::Piece> pieces)
+ : data (
+ std::make_shared<decltype (data)::element_type> (std::move (str),
+ std::move (pieces)))
{}
- std::vector<ffi::Piece> pieces_vector;
-
- // this memory is held for FFI reasons - it needs to be released and cloned
- // precisely, so try to not access it/modify it if possible. you should
- // instead work with `pieces_vector`
- ffi::FormatArgsHandle handle;
+ // makes copying simpler
+ // also, we'd need to keep the parsed string in a shared_ptr anyways
+ // since we store pointers into the parsed string
+ std::shared_ptr<std::pair<std::string, ffi::FFIVec<ffi::Piece>>> data;
};
} // namespace Fmt
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc
b/gcc/rust/expand/rust-macro-builtins-asm.cc
index 6cbcf87ebc9..c991ca703e9 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.cc
+++ b/gcc/rust/expand/rust-macro-builtins-asm.cc
@@ -787,12 +787,12 @@ expand_inline_asm_strings (InlineAsmContext
inline_asm_ctx)
auto pieces = Fmt::Pieces::collect (template_str.symbol, false,
Fmt::ffi::ParseMode::InlineAsm);
- auto pieces_vec = pieces.get_pieces ();
+ auto &pieces_vec = pieces.get_pieces ();
std::string transformed_template_str = "";
for (size_t i = 0; i < pieces_vec.size (); i++)
{
- auto piece = pieces_vec[i];
+ auto &piece = pieces_vec[i];
if (piece.tag == Fmt::ffi::Piece::Tag::String)
{
transformed_template_str += piece.string._0.to_string ();
diff --git a/libgrust/libformat_parser/src/lib.rs
b/libgrust/libformat_parser/src/lib.rs
index 72e5971ae80..049403db0b7 100644
--- a/libgrust/libformat_parser/src/lib.rs
+++ b/libgrust/libformat_parser/src/lib.rs
@@ -1,56 +1,197 @@
//! FFI interface for `rustc_format_parser`
+use std::alloc::Layout;
+
// what's the plan? Have a function return something that can be constructed
into a vector?
// or an iterator?
-use std::ffi::CStr;
-
trait IntoFFI<T> {
fn into_ffi(self) -> T;
}
-impl<T> IntoFFI<*const T> for Option<T>
-where
- T: Sized,
-{
- fn into_ffi(self) -> *const T {
- match self.as_ref() {
- None => std::ptr::null(),
- Some(r) => r as *const T,
+// FIXME: Make an ffi module in a separate file
+// FIXME: Remember to leak the boxed type somehow
+// FIXME: How to encode the Option type? As a pointer? Option<T> -> Option<&T>
-> *const T could work maybe?
+pub mod ffi {
+ use super::IntoFFI;
+ use std::marker::PhantomData;
+ use std::mem::MaybeUninit;
+
+ #[repr(C)]
+ pub struct FFIVec<T> {
+ data: *mut T,
+ len: usize,
+ cap: usize
+ }
+
+ impl<T> IntoFFI<FFIVec<T>> for Vec<T> {
+ fn into_ffi(mut self) -> FFIVec<T> {
+ let ret = FFIVec {
+ data: self.as_mut_ptr(),
+ len: self.len(),
+ cap: self.capacity()
+ };
+ self.leak();
+ ret
}
}
-}
-// Extension trait to provide `String::leak` which did not exist in Rust 1.49
-pub trait StringLeakExt {
- fn leak<'a>(self) -> &'a mut str;
-}
+ impl<T> Drop for FFIVec<T> {
+ fn drop(&mut self) {
+ unsafe {
+ Vec::from_raw_parts(self.data, self.len, self.cap);
+ }
+ }
+ }
-impl StringLeakExt for String {
- fn leak<'a>(self) -> &'a mut str {
- Box::leak(self.into_boxed_str())
+ impl<T> FFIVec<T> {
+ fn with_vec_ref<R, F: for<'a> FnOnce(&'a Vec<T>) -> R>(
+ &self, f: F
+ ) -> R {
+ let v = unsafe {
+ Vec::from_raw_parts(self.data, self.len, self.cap)
+ };
+ let ret = f(&v);
+ v.leak();
+ ret
+ }
+
+ // currently unused
+ // may be nice to have later, though
+ #[allow(unused)]
+ fn with_vec_mut_ref<R, F: for<'a> FnOnce(&'a mut Vec<T>) -> R>(
+ &mut self, f: F
+ ) -> R {
+ let mut v = unsafe {
+ Vec::from_raw_parts(self.data, self.len, self.cap)
+ };
+ let ret = f(&mut v);
+ self.data = v.as_mut_ptr();
+ self.len = v.len();
+ self.cap = v.capacity();
+ v.leak();
+ ret
+ }
}
-}
-// FIXME: Make an ffi module in a separate file
-// FIXME: Remember to leak the boxed type somehow
-// FIXME: How to encode the Option type? As a pointer? Option<T> -> Option<&T>
-> *const T could work maybe?
-pub mod ffi {
- use super::IntoFFI;
+ impl<T> Clone for FFIVec<T>
+ where
+ T: Clone
+ {
+ fn clone(&self) -> FFIVec<T> {
+ self.with_vec_ref(|v| v.clone().into_ffi())
+ }
+ }
+
+ #[repr(C)]
+ pub struct FFIOpt<T> {
+ val: MaybeUninit<T>,
+ is_some: bool
+ }
+
+ impl<T> Clone for FFIOpt<T>
+ where
+ T: Clone
+ {
+ fn clone(&self) -> Self {
+ match self.get_opt_ref() {
+ Some(r) => FFIOpt::new_val(r.clone()),
+ None => FFIOpt::new_none()
+ }
+ }
+ }
+
+ impl<T> PartialEq for FFIOpt<T>
+ where
+ T: PartialEq
+ {
+ fn eq(&self, other: &Self) -> bool {
+ match (self.get_opt_ref(), other.get_opt_ref()) {
+ (Some(a), Some(b)) => a.eq(b),
+ _ => false
+ }
+ }
+ }
+
+ impl<T> Eq for FFIOpt<T>
+ where
+ T: Eq
+ {}
+
+ impl<T> Drop for FFIOpt<T>
+ {
+ fn drop(&mut self) {
+ if self.is_some {
+ unsafe { std::ptr::drop_in_place(self.val.as_mut_ptr()) }
+ }
+ }
+ }
+
+ impl<T> IntoFFI<FFIOpt<T>> for Option<T> {
+ fn into_ffi(self) -> FFIOpt<T> {
+ match self {
+ Some(v) => FFIOpt::new_val(v),
+ None => FFIOpt::new_none()
+ }
+ }
+ }
+
+ impl<T> FFIOpt<T> {
+ pub fn new_val(v: T) -> Self {
+ FFIOpt {
+ val: MaybeUninit::new(v),
+ is_some: true
+ }
+ }
+
+ pub fn new_none() -> Self {
+ FFIOpt {
+ val: MaybeUninit::uninit(),
+ is_some: false
+ }
+ }
+
+ pub fn get_opt_ref(&self) -> Option<&T> {
+ if self.is_some {
+ Some(unsafe {&*self.val.as_ptr()})
+ } else {
+ None
+ }
+ }
+
+ pub fn get_opt_ref_mut(&mut self) -> Option<&mut T> {
+ if self.is_some {
+ Some(unsafe {&mut *self.val.as_mut_ptr()})
+ } else {
+ None
+ }
+ }
+ }
// FIXME: We need to ensure we deal with memory properly - whether it's
owned by the C++ side or the Rust side
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(C)]
- pub struct RustHamster {
+ pub struct RustHamster<'a> {
ptr: *const u8,
len: usize,
+ phantom: PhantomData<&'a u8>
}
- impl<'a> From<&'a str> for RustHamster {
- fn from(s: &'a str) -> RustHamster {
+ impl<'a> IntoFFI<RustHamster<'a>> for &'a str {
+ fn into_ffi(self) -> RustHamster<'a> {
RustHamster {
- ptr: s.as_ptr(),
- len: s.len(),
+ ptr: self.as_ptr(),
+ len: self.len(),
+ phantom: PhantomData,
+ }
+ }
+ }
+
+ impl<'a> RustHamster<'a> {
+ pub fn as_str(&self) -> &'a str {
+ unsafe {
+ let slice: &'a [u8] = std::slice::from_raw_parts(self.ptr,
self.len);
+ std::str::from_utf8_unchecked(slice)
}
}
}
@@ -101,11 +242,11 @@ pub mod ffi {
/// A piece is a portion of the format string which represents the next
part
/// to emit. These are emitted as a stream by the `Parser` class.
- #[derive(Debug, Clone, PartialEq)]
+ #[derive(Clone)]
#[repr(C)]
pub enum Piece<'a> {
/// A literal string which should directly be emitted
- String(RustHamster),
+ String(RustHamster<'a>),
/// This describes that formatting should process the next argument (as
/// specified inside) for emission.
// do we need a pointer here? we're doing big cloning anyway
@@ -113,7 +254,7 @@ pub mod ffi {
}
/// Representation of an argument specification.
- #[derive(Copy, Clone, Debug, PartialEq)]
+ #[derive(Clone)]
#[repr(C)]
pub struct Argument<'a> {
/// Where to find this argument
@@ -126,37 +267,37 @@ pub mod ffi {
}
/// Specification for the formatting of an argument in the format string.
- #[derive(Copy, Clone, Debug, PartialEq)]
+ #[derive(Clone)]
#[repr(C)]
pub struct FormatSpec<'a> {
/// Optionally specified character to fill alignment with.
- pub fill: Option<char>,
+ pub fill: FFIOpt<char>,
/// Span of the optionally specified fill character.
- pub fill_span: *const InnerSpan,
+ pub fill_span: FFIOpt<InnerSpan>,
/// Optionally specified alignment.
pub align: Alignment,
/// The `+` or `-` flag.
- pub sign: *const Sign,
+ pub sign: FFIOpt<Sign>,
/// The `#` flag.
pub alternate: bool,
/// The `0` flag.
pub zero_pad: bool,
/// The `x` or `X` flag. (Only for `Debug`.)
- pub debug_hex: *const DebugHex,
+ pub debug_hex: FFIOpt<DebugHex>,
/// The integer precision to use.
pub precision: Count<'a>,
/// The span of the precision formatting flag (for diagnostics).
- pub precision_span: *const InnerSpan,
+ pub precision_span: FFIOpt<InnerSpan>,
/// The string width requested for the resulting format.
pub width: Count<'a>,
/// The span of the width formatting flag (for diagnostics).
- pub width_span: *const InnerSpan,
+ pub width_span: FFIOpt<InnerSpan>,
/// The descriptor string representing the name of the format desired
for
/// this argument, this can be empty or any number of characters,
although
/// it is required to be one word.
- pub ty: &'a str,
+ pub ty: RustHamster<'a>,
/// The span of the descriptor string (for diagnostics).
- pub ty_span: *const InnerSpan,
+ pub ty_span: FFIOpt<InnerSpan>,
}
/// Enum describing where an argument for a format can be located.
@@ -168,7 +309,7 @@ pub mod ffi {
/// The argument is located at a specific index given in the format,
ArgumentIs(usize),
/// The argument has a name.
- ArgumentNamed(&'a str),
+ ArgumentNamed(RustHamster<'a>),
}
/// Enum of alignments which are supported.
@@ -213,7 +354,7 @@ pub mod ffi {
/// The count is specified explicitly.
CountIs(usize),
/// The count is specified by the argument with the given name.
- CountIsName(&'a str, InnerSpan),
+ CountIsName(RustHamster<'a>, InnerSpan),
/// The count is specified by the argument at the given index.
CountIsParam(usize),
/// The count is specified by a star (like in `{:.*}`) that refers to
the argument at the given index.
@@ -225,7 +366,7 @@ pub mod ffi {
impl<'a> From<generic_format_parser::Piece<'a>> for Piece<'a> {
fn from(old: generic_format_parser::Piece<'a>) -> Self {
match old {
- generic_format_parser::Piece::String(x) =>
Piece::String(x.into()),
+ generic_format_parser::Piece::String(x) =>
Piece::String(x.into_ffi()),
generic_format_parser::Piece::NextArgument(x) => {
// FIXME: This is problematic - if we do this, then we
probably run into the issue that the Box
// is freed at the end of the call to collect_pieces. if
we just .leak() it, then we have
@@ -259,7 +400,7 @@ pub mod ffi {
}
generic_format_parser::Position::ArgumentIs(x) =>
Position::ArgumentIs(x.into()),
generic_format_parser::Position::ArgumentNamed(x) => {
- Position::ArgumentNamed(x.into())
+ Position::ArgumentNamed(x.into_ffi())
}
}
}
@@ -277,7 +418,7 @@ pub mod ffi {
impl<'a> From<generic_format_parser::FormatSpec<'a>> for FormatSpec<'a> {
fn from(old: generic_format_parser::FormatSpec<'a>) -> Self {
FormatSpec {
- fill: old.fill,
+ fill: old.fill.into_ffi(),
fill_span: old.fill_span.map(Into::into).into_ffi(),
align: old.align.into(),
sign: old.sign.map(Into::into).into_ffi(),
@@ -288,7 +429,7 @@ pub mod ffi {
precision_span: old.precision_span.map(Into::into).into_ffi(),
width: old.width.into(),
width_span: old.width_span.map(Into::into).into_ffi(),
- ty: old.ty,
+ ty: old.ty.into_ffi(),
ty_span: old.ty_span.map(Into::into).into_ffi(),
}
}
@@ -307,7 +448,7 @@ pub mod ffi {
fn from(old: generic_format_parser::Count<'a>) -> Self {
match old {
generic_format_parser::Count::CountIs(x) => Count::CountIs(x),
- generic_format_parser::Count::CountIsName(x, y) =>
Count::CountIsName(x, y.into()),
+ generic_format_parser::Count::CountIsName(x, y) =>
Count::CountIsName(x.into_ffi(), y.into()),
generic_format_parser::Count::CountIsParam(x) =>
Count::CountIsParam(x),
generic_format_parser::Count::CountIsStar(x) =>
Count::CountIsStar(x),
generic_format_parser::Count::CountImplied =>
Count::CountImplied,
@@ -357,100 +498,66 @@ pub mod rust {
}
// TODO: Should we instead make an FFIVector struct?
-#[repr(C)]
-pub struct PieceSlice {
- base_ptr: *mut ffi::Piece<'static /* FIXME: That's wrong */>,
- len: usize,
- cap: usize,
-}
-
-#[repr(C)]
-// FIXME: we should probably use FFIString here
-pub struct RustString {
- ptr: *const u8,
- len: usize,
- cap: usize,
-}
-
-#[repr(C)]
-pub struct FormatArgsHandle(PieceSlice, RustString);
+type PieceVec<'a> = ffi::FFIVec<ffi::Piece<'a>>;
#[no_mangle]
-pub extern "C" fn collect_pieces(
- input: *const libc::c_char,
+pub extern "C" fn collect_pieces<'a>(
+ input: ffi::RustHamster<'a>,
append_newline: bool,
parse_mode: crate::ffi::ParseMode,
-) -> FormatArgsHandle {
- // FIXME: Add comment
- let str = unsafe { CStr::from_ptr(input) };
- let str = str.to_str().unwrap().to_owned();
-
- // we are never going to free this string here (we leak it later on), so
we can extend its lifetime
- // to send it across an FFI boundary.
- // FIXME: Is that correct?
- let s = &str;
- let s = unsafe { std::mem::transmute::<&'_ str, &'static str>(s) };
-
+) -> PieceVec<'a> {
// FIXME: No unwrap
let pieces: Vec<ffi::Piece<'_>> =
- rust::collect_pieces(s, None, None, append_newline, parse_mode)
+ rust::collect_pieces(input.as_str(), None, None, append_newline,
parse_mode)
.into_iter()
.map(Into::into)
.collect();
- let piece_slice = PieceSlice {
- len: pieces.len(),
- cap: pieces.capacity(),
- base_ptr: pieces.leak().as_mut_ptr(),
- };
- let rust_string = RustString {
- len: str.len(),
- cap: str.capacity(),
- ptr: str.leak().as_ptr(),
- };
-
- FormatArgsHandle(piece_slice, rust_string)
+ pieces.into_ffi()
}
#[no_mangle]
-pub unsafe extern "C" fn destroy_pieces(FormatArgsHandle(piece_slice, s):
FormatArgsHandle) {
- let PieceSlice { base_ptr, len, cap } = piece_slice;
- drop(Vec::from_raw_parts(base_ptr, len, cap));
-
- let RustString { ptr, len, cap } = s;
- drop(String::from_raw_parts(ptr as *mut u8, len, cap));
+pub extern "C" fn clone_pieces<'a, 'b>(
+ piece_vec: &'a PieceVec<'b>
+) -> PieceVec<'b> {
+ piece_vec.clone()
}
-#[no_mangle]
-pub extern "C" fn clone_pieces(
- FormatArgsHandle(piece_slice, s): &FormatArgsHandle,
-) -> FormatArgsHandle {
- let PieceSlice { base_ptr, len, cap } = *piece_slice;
-
- let v = unsafe { Vec::from_raw_parts(base_ptr, len, cap) };
- let cloned_v = v.clone();
-
- // FIXME: Add documentation
- v.leak();
-
- let piece_slice = PieceSlice {
- len: cloned_v.len(),
- cap: cloned_v.capacity(),
- base_ptr: cloned_v.leak().as_mut_ptr(),
- };
-
- let RustString { ptr, len, cap } = *s;
- let s = unsafe { String::from_raw_parts(ptr as *mut u8, len, cap) };
- let cloned_s = s.clone();
+// we need Layout::repeat
+// function signature is a bit different, so call it repeat_x
+trait LayoutExt {
+ fn repeat_x(&self, n: usize) -> Layout;
+}
- // FIXME: Documentation
- s.leak();
+impl LayoutExt for Layout {
+ fn repeat_x(&self, n: usize) -> Layout {
+ let elem = self.pad_to_align();
+ let total_size = elem.size().checked_mul(n).unwrap();
+ Layout::from_size_align(total_size, elem.align()).unwrap()
+ }
+}
- let rust_string = RustString {
- len: cloned_s.len(),
- cap: cloned_s.capacity(),
- ptr: cloned_s.leak().as_ptr(),
- };
+#[no_mangle]
+pub unsafe extern "C" fn rust_ffi_alloc(
+ count: usize, elem_size: usize, align: usize
+) -> *mut u8 {
+ unsafe {
+ std::alloc::alloc(
+ Layout::from_size_align_unchecked(elem_size, align)
+ .repeat_x(count)
+ )
+ }
+}
- FormatArgsHandle(piece_slice, rust_string)
+#[no_mangle]
+pub unsafe extern "C" fn rust_ffi_dealloc(
+ data: *mut u8, count: usize, elem_size: usize, align: usize
+) {
+ unsafe {
+ std::alloc::dealloc(
+ data,
+ Layout::from_size_align_unchecked(elem_size, align)
+ .repeat_x(count)
+ )
+ }
}
--
2.50.1