mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
fix(ext/ffi): disallow empty ffi structs (#17487)
This patch makes `NativeType` to `libffi::middle::Type` conversion failliable and w.t disallows struct with empty fields. libffi does not handle "empty" struct because they don't exist in C (or Rust). Fixes #17481
This commit is contained in:
parent
638b6ef554
commit
5928925541
5 changed files with 71 additions and 18 deletions
|
@ -278,7 +278,7 @@ where
|
|||
permissions.check(None)?;
|
||||
};
|
||||
|
||||
let symbol = PtrSymbol::new(pointer, &def);
|
||||
let symbol = PtrSymbol::new(pointer, &def)?;
|
||||
let call_args = ffi_parse_args(scope, parameters, &def.parameters)?;
|
||||
let def_result = def.result.clone();
|
||||
|
||||
|
@ -379,7 +379,7 @@ where
|
|||
permissions.check(None)?;
|
||||
};
|
||||
|
||||
let symbol = PtrSymbol::new(pointer, &def);
|
||||
let symbol = PtrSymbol::new(pointer, &def)?;
|
||||
let call_args = ffi_parse_args(scope, parameters, &def.parameters)?;
|
||||
|
||||
let out_buffer = out_buffer
|
||||
|
|
|
@ -40,18 +40,19 @@ pub struct PtrSymbol {
|
|||
}
|
||||
|
||||
impl PtrSymbol {
|
||||
pub fn new(fn_ptr: usize, def: &ForeignFunction) -> Self {
|
||||
pub fn new(fn_ptr: usize, def: &ForeignFunction) -> Result<Self, AnyError> {
|
||||
let ptr = libffi::middle::CodePtr::from_ptr(fn_ptr as _);
|
||||
let cif = libffi::middle::Cif::new(
|
||||
def
|
||||
.parameters
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(libffi::middle::Type::from),
|
||||
def.result.clone().into(),
|
||||
.map(libffi::middle::Type::try_from)
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
def.result.clone().try_into()?,
|
||||
);
|
||||
|
||||
Self { cif, ptr }
|
||||
Ok(Self { cif, ptr })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -578,8 +579,12 @@ where
|
|||
waker: None,
|
||||
}));
|
||||
let cif = Cif::new(
|
||||
args.parameters.into_iter().map(libffi::middle::Type::from),
|
||||
libffi::middle::Type::from(args.result),
|
||||
args
|
||||
.parameters
|
||||
.into_iter()
|
||||
.map(libffi::middle::Type::try_from)
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
libffi::middle::Type::try_from(args.result)?,
|
||||
);
|
||||
|
||||
// SAFETY: CallbackInfo is leaked, is not null and stays valid as long as the callback exists.
|
||||
|
|
|
@ -166,8 +166,9 @@ where
|
|||
.parameters
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(libffi::middle::Type::from),
|
||||
foreign_fn.result.clone().into(),
|
||||
.map(libffi::middle::Type::try_from)
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
foreign_fn.result.clone().try_into()?,
|
||||
);
|
||||
|
||||
let func_key = v8::String::new(scope, &symbol_key).unwrap();
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::type_error;
|
||||
use deno_core::error::AnyError;
|
||||
|
||||
/// Defines the accepted types that can be used as
|
||||
/// parameters and return values in FFI.
|
||||
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq)]
|
||||
|
@ -25,9 +28,11 @@ pub enum NativeType {
|
|||
Struct(Box<[NativeType]>),
|
||||
}
|
||||
|
||||
impl From<NativeType> for libffi::middle::Type {
|
||||
fn from(native_type: NativeType) -> Self {
|
||||
match native_type {
|
||||
impl TryFrom<NativeType> for libffi::middle::Type {
|
||||
type Error = AnyError;
|
||||
|
||||
fn try_from(native_type: NativeType) -> Result<Self, Self::Error> {
|
||||
Ok(match native_type {
|
||||
NativeType::Void => libffi::middle::Type::void(),
|
||||
NativeType::U8 | NativeType::Bool => libffi::middle::Type::u8(),
|
||||
NativeType::I8 => libffi::middle::Type::i8(),
|
||||
|
@ -44,10 +49,18 @@ impl From<NativeType> for libffi::middle::Type {
|
|||
NativeType::Pointer | NativeType::Buffer | NativeType::Function => {
|
||||
libffi::middle::Type::pointer()
|
||||
}
|
||||
NativeType::Struct(fields) => libffi::middle::Type::structure(
|
||||
fields.iter().map(|field| field.clone().into()),
|
||||
),
|
||||
NativeType::Struct(fields) => {
|
||||
libffi::middle::Type::structure(match fields.len() > 0 {
|
||||
true => fields
|
||||
.iter()
|
||||
.map(|field| field.clone().try_into())
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
false => {
|
||||
return Err(type_error("Struct must have at least one field"))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,40 @@ assertThrows(
|
|||
"Failed to register symbol non_existent_symbol",
|
||||
);
|
||||
|
||||
assertThrows(() => {
|
||||
Deno.dlopen(libPath, {
|
||||
print_something: {
|
||||
parameters: [],
|
||||
result: { struct: [] }
|
||||
},
|
||||
}),
|
||||
TypeError,
|
||||
"Struct must have at least one field"
|
||||
});
|
||||
|
||||
assertThrows(() => {
|
||||
Deno.dlopen(libPath, {
|
||||
print_something: {
|
||||
parameters: [ { struct: [] } ],
|
||||
result: "void",
|
||||
},
|
||||
}),
|
||||
TypeError,
|
||||
"Struct must have at least one field"
|
||||
});
|
||||
|
||||
const Empty = { struct: [] }
|
||||
assertThrows(() => {
|
||||
Deno.dlopen(libPath, {
|
||||
print_something: {
|
||||
parameters: [ { struct: [Empty] } ],
|
||||
result: "void",
|
||||
},
|
||||
}),
|
||||
TypeError,
|
||||
"Struct must have at least one field"
|
||||
});
|
||||
|
||||
const Point = ["f64", "f64"];
|
||||
const Size = ["f64", "f64"];
|
||||
const Rect = ["f64", "f64", "f64", "f64"];
|
||||
|
|
Loading…
Reference in a new issue