]> git.proxmox.com Git - perlmod.git/blob - perlmod/src/ffi.rs
document errno and serializ_error in the #[export] doc
[perlmod.git] / perlmod / src / ffi.rs
1 //! Unsafe ffi code.
2 //!
3 //! You should not use this code directly. This is used by the binding generator to implement xsubs
4 //! for exported functions.
5
6 /// Raw perl subroutine pointer value. This should not be used directly.
7 #[repr(C)]
8 pub struct CV {
9 _ffi: usize,
10 }
11
12 /// Raw scalar-ish perl value. This should not be used directly.
13 #[repr(C)]
14 pub struct SV {
15 _ffi: usize,
16 }
17
18 /// Raw perl array value. This should not be used directly.
19 #[repr(C)]
20 pub struct AV {
21 _ffi: usize,
22 }
23
24 /// Raw perl hash value. This should not be used directly.
25 #[repr(C)]
26 pub struct HV {
27 _ffi: usize,
28 }
29
30 /// Raw perl hash entry iterator. This should not be used directly.
31 #[repr(C)]
32 pub struct HE {
33 _ffi: usize,
34 }
35
36 /// Raw perl MAGIC struct, we don't actually make its contents available.
37 #[repr(C)]
38 pub struct MAGIC {
39 _ffi: usize,
40 }
41
42 #[allow(clippy::len_without_is_empty)]
43 impl MAGIC {
44 pub fn vtbl(&self) -> Option<&MGVTBL> {
45 unsafe { RSPL_MAGIC_virtual(self as *const MAGIC).as_ref() }
46 }
47
48 pub fn ptr(&self) -> *const libc::c_char {
49 unsafe { RSPL_MAGIC_ptr(self as *const MAGIC) }
50 }
51
52 pub fn len(&self) -> isize {
53 unsafe { RSPL_MAGIC_len(self as *const MAGIC) }
54 }
55 }
56
57 #[repr(C)]
58 pub struct Unsupported {
59 _ffi: usize,
60 }
61
62 #[cfg(perlmod = "multiplicity")]
63 #[repr(C)]
64 pub struct Interpreter {
65 _ffi: usize,
66 }
67
68 /// Build perl-compatible functions and fn types (`pTHX` macro equivalent).
69 ///
70 /// Takes an `extern "C" fn` (with or without body) and potentially inserts the a
71 /// `*const Interpreter` as first parameter depending on the perl configuration, so it can be used
72 /// for xsub implementations.
73 #[macro_export]
74 macro_rules! perl_fn {
75 // inherited visibility
76 ($(
77 $(#[$attr:meta])*
78 extern "C" fn($($args:tt)*) $(-> $re:ty)?
79 )*) => {
80 $crate::perl_fn_impl! {
81 $(
82 $(#[$attr])*
83 () extern "C" fn($($args)*) $(-> $re)?
84 )*
85 }
86 };
87 ($(
88 $(#[$attr:meta])*
89 extern "C" fn $name:ident $(<($($gen:tt)*)>)? ($($args:tt)*) $(-> $re:ty)?
90 $(where ($($where_clause:tt)*))?
91 {
92 $($code:tt)*
93 }
94 )*) => {
95 $crate::perl_fn_impl! {
96 $(
97 $(#[$attr])*
98 () extern "C" fn $name $(<($($gen)*)>)? ($($args)*) $(-> $re)?
99 $(where ($($where_clause)*))?
100 {
101 $($code)*
102 }
103 )*
104 }
105 };
106
107 // same with 'pub' visibility
108 ($(
109 $(#[$attr:meta])*
110 pub $(($($vis:tt)+))? extern "C" fn($($args:tt)*) $(-> $re:ty)?
111 )*) => {
112 $crate::perl_fn_impl! {
113 $(
114 $(#[$attr])*
115 (pub $(($($vis)+))?) extern "C" fn($($args)*) $(-> $re)?
116 )*
117 }
118 };
119 ($(
120 $(#[$attr:meta])*
121 pub $(($($vis:tt)+))?
122 extern "C" fn $name:ident $(<($($gen:tt)*)>)? ($($args:tt)*) $(-> $re:ty)?
123 $(where ($($where_clause:tt)*))?
124 {
125 $($code:tt)*
126 }
127 )*) => {
128 $crate::perl_fn_impl! {
129 $(
130 $(#[$attr])*
131 (pub $(($($vis)+))?) extern "C" fn $name $(<($($gen)*)>)? ($($args)*) $(-> $re)?
132 $(where ($($where_clause)*))?
133 {
134 $($code)*
135 }
136 )*
137 }
138 };
139 }
140
141 #[cfg(perlmod = "multiplicity")]
142 mod vtbl_types_impl {
143 use super::{Interpreter, MAGIC, SV};
144 use libc::c_int;
145
146 pub type Get = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
147 pub type Set = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
148 pub type Len = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> u32;
149 pub type Clear = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
150 pub type Free = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
151 pub type Copy = extern "C" fn(
152 _perl: *const Interpreter,
153 sv: *mut SV,
154 mg: *mut MAGIC,
155 nsv: *mut SV,
156 name: *const libc::c_char,
157 namelen: i32,
158 ) -> c_int;
159 pub type Dup = extern "C" fn(
160 _perl: *const Interpreter,
161 sv: *mut SV,
162 mg: *mut MAGIC,
163 clone_parms: *mut super::Unsupported,
164 ) -> c_int;
165 pub type Local = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
166
167 #[doc(hidden)]
168 #[macro_export]
169 macro_rules! perl_fn_impl {
170 ($(
171 $(#[$attr:meta])*
172 ($($vis:tt)*) extern "C" fn($($args:tt)*) $(-> $re:ty)?
173 )*) => {$(
174 $(#[$attr])*
175 $($vis)* extern "C" fn(*const $crate::ffi::Interpreter, $($args)*) $(-> $re)?
176 )*};
177 ($(
178 $(#[$attr:meta])*
179 ($($vis:tt)*)
180 extern "C" fn $name:ident $(<($($gen:tt)*)>)? ($($args:tt)*) $(-> $re:ty)?
181 $(where ($($where_clause:tt)*))?
182 {
183 $($code:tt)*
184 }
185 )*) => {$(
186 $(#[$attr])*
187 $($vis)* extern "C" fn $name $(<$($gen)*>)? (
188 _perl: *const $crate::ffi::Interpreter,
189 $($args)*
190 ) $(-> $re)?
191 $(where $($where_clause)*)?
192 {
193 $($code)*
194 }
195 )*};
196 }
197 }
198
199 #[cfg(not(perlmod = "multiplicity"))]
200 mod vtbl_types_impl {
201 use super::{Interpreter, MAGIC, SV};
202 use libc::c_int;
203
204 pub type Get = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
205 pub type Set = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
206 pub type Len = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> u32;
207 pub type Clear = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
208 pub type Free = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
209 pub type Copy = extern "C" fn(
210 sv: *mut SV,
211 mg: *mut MAGIC,
212 nsv: *mut SV,
213 name: *const libc::c_char,
214 namelen: i32,
215 ) -> c_int;
216 pub type Dup =
217 extern "C" fn(sv: *mut SV, mg: *mut MAGIC, clone_parms: *mut super::Unsupported) -> c_int;
218 pub type Local = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
219
220 #[doc(hidden)]
221 #[macro_export]
222 macro_rules! perl_fn_impl {
223 ($(
224 $(#[$attr:meta])*
225 ($($vis:tt)*) extern "C" fn($($args:tt)*) $(-> $re:ty)?
226 )*) => {$(
227 $(#[$attr])*
228 $($vis)* extern "C" fn($($args)*) $(-> $re)?
229 )*};
230 ($(
231 $(#[$attr:meta])*
232 ($($vis:tt)*)
233 extern "C" fn $name:ident $(<($($gen:tt)*)>)? ($($args:tt)*) $(-> $re:ty)?
234 $(where ($($where_clause:tt)*))?
235 {
236 $($code:tt)*
237 }
238 )*) => {$(
239 $(#[$attr])*
240 $($vis)* extern "C" fn $name $(<$($gen)*>)? ($($args)*) $(-> $re)?
241 $(where $($where_clause)*)?
242 {
243 $($code)*
244 }
245 )*};
246 }
247 }
248
249 /// The types in this module depend on the configuration of your perl installation.
250 ///
251 /// If the perl interpreter has been compiled with `USEMULTIPLICITY`, these methods have an
252 /// additional parameter.
253 pub mod vtbl_types {
254 pub use super::vtbl_types_impl::*;
255 }
256
257 #[derive(Clone, Copy)]
258 #[repr(C)]
259 pub struct MGVTBL {
260 pub get: Option<vtbl_types::Get>,
261 pub set: Option<vtbl_types::Set>,
262 pub len: Option<vtbl_types::Len>,
263 pub clear: Option<vtbl_types::Clear>,
264 pub free: Option<vtbl_types::Free>,
265 pub copy: Option<vtbl_types::Copy>,
266 pub dup: Option<vtbl_types::Dup>,
267 pub local: Option<vtbl_types::Local>,
268 }
269
270 impl MGVTBL {
271 /// Let's not expose this directly, we need there to be distinct instances of these, so they
272 /// should be created via `MGVTBL::zero()`.
273 const EMPTY: Self = Self {
274 get: None,
275 set: None,
276 len: None,
277 clear: None,
278 free: None,
279 copy: None,
280 dup: None,
281 local: None,
282 };
283
284 /// Create a new all-zeroes vtbl as perl docs suggest this is the safest way to
285 /// make sure what a `PERL_MAGIC_ext` magic actually means, as the ptr value
286 /// may be arbitrary.
287 ///
288 /// # Safety
289 ///
290 /// This must not be deallocated as long as it is attached to a perl value, so best use this as
291 /// `const` variables, rather than dynamically allocating it.
292 pub const fn zero() -> Self {
293 Self::EMPTY
294 }
295 }
296
297 // in our glue:
298 #[link(name = "glue", kind = "static")]
299 extern "C" {
300 pub fn RSPL_StackMark_count(this: usize) -> usize;
301
302 pub fn RSPL_stack_get(offset: usize) -> *mut SV;
303
304 pub fn RSPL_croak_sv(sv: *mut SV) -> !;
305
306 pub fn RSPL_newXS_flags(
307 name: *const i8,
308 subaddr: *const i8,
309 filename: *const i8,
310 proto: *const i8,
311 flags: u32,
312 ) -> *mut CV;
313
314 pub fn RSPL_SvNV(sv: *mut SV) -> f64;
315 pub fn RSPL_SvIV(sv: *mut SV) -> isize;
316 pub fn RSPL_SvPVutf8(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
317 pub fn RSPL_SvPV(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
318 pub fn RSPL_SvUTF8(sv: *mut SV) -> bool;
319 /// This calls `sv_utf8_downgrade` first to avoid croaking, instead returns `NULL` on error.
320 pub fn RSPL_SvPVbyte(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
321 pub fn RSPL_sv_2mortal(sv: *mut SV) -> *mut SV;
322 pub fn RSPL_get_undef() -> *mut SV;
323 pub fn RSPL_get_yes() -> *mut SV;
324 pub fn RSPL_get_no() -> *mut SV;
325 pub fn RSPL_pop_markstack_ptr() -> usize;
326 pub fn RSPL_stack_resize_by(count: isize);
327 pub fn RSPL_stack_shrink_to(count: usize);
328 pub fn RSPL_stack_sp() -> *mut *mut SV;
329 pub fn RSPL_newRV_inc(sv: *mut SV) -> *mut SV;
330 pub fn RSPL_newSViv(v: isize) -> *mut SV;
331 pub fn RSPL_newSVuv(v: usize) -> *mut SV;
332 pub fn RSPL_newSVnv(v: f64) -> *mut SV;
333 pub fn RSPL_newSVpvn(v: *const libc::c_char, len: libc::size_t) -> *mut SV;
334 pub fn RSPL_newSVpvn_utf8(v: *const libc::c_char, len: libc::size_t) -> *mut SV;
335 pub fn RSPL_SvREFCNT_inc(sv: *mut SV) -> *mut SV;
336 pub fn RSPL_SvREFCNT_dec(sv: *mut SV);
337 pub fn RSPL_is_reference(sv: *mut SV) -> bool;
338 pub fn RSPL_dereference(sv: *mut SV) -> *mut SV;
339 pub fn RSPL_is_array(sv: *mut SV) -> bool;
340 pub fn RSPL_is_hash(sv: *mut SV) -> bool;
341 pub fn RSPL_type_flags(sv: *mut SV) -> u32;
342 pub fn RSPL_svtype(sv: *mut SV) -> u32;
343 pub fn RSPL_SvOK(sv: *mut SV) -> bool;
344 pub fn RSPL_SvANY(sv: *mut SV) -> bool;
345 pub fn RSPL_SvTRUE(sv: *mut SV) -> bool;
346
347 pub fn RSPL_is_defined(sv: *mut SV) -> bool;
348
349 pub fn RSPL_newAV() -> *mut AV;
350 pub fn RSPL_av_extend(av: *mut AV, len: libc::ssize_t);
351 pub fn RSPL_av_push(av: *mut AV, sv: *mut SV);
352 pub fn RSPL_av_pop(av: *mut AV) -> *mut SV;
353 pub fn RSPL_av_len(av: *mut AV) -> usize;
354 pub fn RSPL_av_fetch(av: *mut AV, index: libc::ssize_t, lval: i32) -> *mut *mut SV;
355
356 pub fn RSPL_newHV() -> *mut HV;
357 pub fn RSPL_HvTOTALKEYS(hv: *mut HV) -> usize;
358 pub fn RSPL_hv_fetch(
359 hv: *mut HV,
360 key: *const libc::c_char,
361 klen: i32,
362 lval: i32,
363 ) -> *mut *mut SV;
364 /// Always consumes ownership of `value`.
365 pub fn RSPL_hv_store(hv: *mut HV, key: *const libc::c_char, klen: i32, value: *mut SV) -> bool;
366 pub fn RSPL_hv_store_ent(hv: *mut HV, key: *mut SV, value: *mut SV) -> bool;
367 pub fn RSPL_hv_iterinit(hv: *mut HV);
368 pub fn RSPL_hv_iternextsv(
369 hv: *mut HV,
370 key: *mut *mut libc::c_char,
371 retlen: *mut i32,
372 ) -> *mut SV;
373 pub fn RSPL_hv_iternext(hv: *mut HV) -> *mut HE;
374 pub fn RSPL_hv_iterkeysv(he: *mut HE) -> *mut SV;
375 pub fn RSPL_hv_iterval(hv: *mut HV, he: *mut HE) -> *mut SV;
376
377 pub fn RSPL_gv_stashsv(name: *const SV, flags: i32) -> *mut HV;
378 pub fn RSPL_sv_bless(sv: *mut SV, stash: *mut HV) -> *mut SV;
379
380 pub fn RSPL_ENTER();
381 pub fn RSPL_SAVETMPS();
382 pub fn RSPL_FREETMPS();
383 pub fn RSPL_LEAVE();
384
385 pub fn RSPL_sv_reftype(sv: *const SV, ob: libc::c_int) -> *const libc::c_char;
386
387 pub fn RSPL_PVLV() -> u32;
388 pub fn RSPL_LvTARG(sv: *mut SV) -> *mut SV;
389 //pub fn RSPL_LvTYPE(sv: *mut SV) -> u8;
390 pub fn RSPL_vivify_defelem(sv: *mut SV);
391
392 //pub fn RSPL_SvFLAGS(sv: *mut SV) -> u32;
393 pub fn RSPL_SvGETMAGIC(sv: *mut SV) -> bool;
394
395 pub fn RSPL_sv_magicext(
396 sv: *mut SV,
397 obj: *mut SV,
398 how: libc::c_int,
399 vtbl: Option<&MGVTBL>,
400 name: *const libc::c_char,
401 namelen: i32,
402 ) -> *mut MAGIC;
403 pub fn RSPL_sv_unmagicext(sv: *mut SV, ty: libc::c_int, vtbl: Option<&MGVTBL>);
404 pub fn RSPL_mg_findext(sv: *const SV, ty: libc::c_int, vtbl: Option<&MGVTBL>) -> *const MAGIC;
405 pub fn RSPL_MAGIC_virtual(mg: *const MAGIC) -> *const MGVTBL;
406 pub fn RSPL_MAGIC_ptr(mg: *const MAGIC) -> *const libc::c_char;
407 pub fn RSPL_MAGIC_len(mg: *const MAGIC) -> isize;
408 pub fn RSPL_PERL_MAGIC_ext() -> libc::c_int;
409
410 pub fn RSPL_PERL_MAGIC_substr() -> libc::c_int;
411 pub fn RSPL_vtbl_substr() -> *const MGVTBL;
412 pub fn RSPL_substr(orig: *mut SV, off: usize, len: usize) -> *mut SV;
413
414 pub fn RSPL_defstash() -> *mut HV;
415
416 pub fn RSPL_set_use_safe_putenv(on: libc::c_int);
417 }
418
419 /// Argument marker for the stack.
420 pub struct StackMark(usize);
421
422 impl StackMark {
423 pub fn count(&self) -> usize {
424 unsafe { RSPL_StackMark_count(self.0) }
425 }
426
427 pub fn iter(&self) -> StackIter {
428 StackIter {
429 at: self.0 + 1,
430 end: self.0 + 1 + self.count(),
431 }
432 }
433
434 /// Shrink the perl stack to this mark.
435 ///
436 /// # Safety
437 ///
438 /// This is only valid if the mark is still valid (smaller than `PL_stack_sp`) and all values
439 /// still remaining on the stack are mortal (which should normally be the case anyway).
440 pub unsafe fn set_stack(self) {
441 unsafe {
442 RSPL_stack_shrink_to(self.0);
443 }
444 }
445 }
446
447 /// Iterator over the stack up to the [`StackMark`].
448 pub struct StackIter {
449 at: usize,
450 end: usize,
451 }
452
453 impl Iterator for StackIter {
454 type Item = crate::Scalar;
455
456 fn next(&mut self) -> Option<Self::Item> {
457 let at = self.at;
458 if at == self.end {
459 return None;
460 }
461 unsafe {
462 let ptr = RSPL_stack_get(self.at);
463 self.at += 1;
464 if ptr.is_null() {
465 None
466 } else {
467 Some(crate::Scalar::from_raw_ref(ptr))
468 }
469 }
470 }
471 }
472
473 /// Pop the current argument marker off of the argument marker stack.
474 ///
475 /// # Safety
476 ///
477 /// Read up on `PL_markstack_ptr` in perlguts. This is equivalent to `*PL_markstack_ptr--` in C.
478 pub unsafe fn pop_arg_mark() -> StackMark {
479 StackMark(unsafe { RSPL_pop_markstack_ptr() })
480 }
481
482 /// Push a value to the stack.
483 ///
484 /// # Safety
485 ///
486 /// Read up on mortals and the stack and when it is legal to put a value onto it. Typically a
487 /// mortal value with no more references to it to avoid leaking if they aren't used later on.
488 pub unsafe fn stack_push_raw(value: *mut SV) {
489 unsafe {
490 RSPL_stack_resize_by(1);
491 *RSPL_stack_sp() = value;
492 }
493 }
494
495 pub fn stack_push(value: crate::Mortal) {
496 unsafe {
497 stack_push_raw(value.into_raw());
498 }
499 }
500
501 /// This calls perl's `croak_sv`.
502 ///
503 /// # Safety
504 ///
505 /// This seems to perform a `longjmp` and is thus never truly safe in rust code. You really want to
506 /// limit this to the top entry point of your rust call stack in a separate `extern "C" fn` where
507 /// no rust values with `Drop` handlers or anything similar are active.
508 ///
509 /// The `perlmod_macro`'s `export` attribute typically creates 2 wrapper functions of the form:
510 ///
511 /// ```no_run
512 /// # use serde::Serialize;
513 ///
514 /// # struct Output;
515 /// # impl Serialize for Output {
516 /// # fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
517 /// # serializer.serialize_unit()
518 /// # }
519 /// # }
520 ///
521 /// # fn code_to_extract_parameters() {}
522 /// # fn actual_rust_function(_arg: ()) -> Result<Output, String> { Ok(Output) }
523 /// #[no_mangle]
524 /// pub extern "C" fn exported_name(/* pTHX parameter, */ cv: &::perlmod::ffi::CV) {
525 /// unsafe {
526 /// match private_implementation_name(cv) {
527 /// Ok(sv) => ::perlmod::ffi::stack_push_raw(sv),
528 /// Err(sv) => ::perlmod::ffi::croak(sv),
529 /// }
530 /// }
531 /// }
532 ///
533 /// #[inline(never)]
534 /// fn private_implementation_name(
535 /// _cv: &::perlmod::ffi::CV,
536 /// ) -> Result<*mut ::perlmod::ffi::SV, *mut ::perlmod::ffi::SV> {
537 /// let args = code_to_extract_parameters();
538 /// // ...
539 /// let result = match actual_rust_function(args) {
540 /// Ok(output) => output,
541 /// Err(err) => {
542 /// return Err(::perlmod::Value::new_string(&err.to_string())
543 /// .into_mortal()
544 /// .into_raw());
545 /// }
546 /// };
547 ///
548 /// match ::perlmod::to_value(&result) {
549 /// Ok(value) => Ok(value.into_mortal().into_raw()),
550 /// Err(err) => Err(::perlmod::Value::new_string(&err.to_string())
551 /// .into_mortal()
552 /// .into_raw()),
553 /// }
554 /// }
555 /// ```
556 pub unsafe fn croak(sv: *mut SV) -> ! {
557 unsafe {
558 RSPL_croak_sv(sv);
559 }
560 }
561
562 /// Create a pseudo-block for mortals & temps to be freed after it.
563 /// This calls `ENTER; SAVETMPS;` before and `FREETMPS; LEAVE;` after the provided closure.
564 pub fn pseudo_block<F, R>(func: F) -> R
565 where
566 F: FnOnce() -> R,
567 {
568 unsafe {
569 RSPL_ENTER();
570 RSPL_SAVETMPS();
571 }
572
573 let res = func();
574
575 unsafe {
576 RSPL_FREETMPS();
577 RSPL_LEAVE();
578 }
579
580 res
581 }
582
583 /// Tell perl to use a "safe" `putenv` call instead of manually manipulating the `environ`
584 /// variable. Without this, changing environment variables can lead to crashes.
585 pub fn use_safe_putenv(on: bool) {
586 unsafe { RSPL_set_use_safe_putenv(on as _) }
587 }