Skip to content

Commit d7d5dfe

Browse files
authored
Merge pull request #3108 from Skgland/issue-3073
emit a more appropriate error when passing the wrong argument count when constructing an ffi struct with the wrong argument count
2 parents 1097961 + 777e6de commit d7d5dfe

File tree

4 files changed

+90
-14
lines changed

4 files changed

+90
-14
lines changed

src/ffi.rs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,17 @@ impl StructImpl {
180180

181181
fn build(
182182
&self,
183+
name: Atom,
183184
structs_table: &HashMap<Atom, StructImpl>,
184185
struct_args: &mut [Value],
185186
) -> Result<FfiStruct, FfiError> {
186-
let args = ArgValue::build_args(struct_args, &self.fields, structs_table)?;
187+
let args = ArgValue::build_args(
188+
name,
189+
ArgCountMismatchKind::Struct,
190+
struct_args,
191+
&self.fields,
192+
structs_table,
193+
)?;
187194

188195
let alloc = FfiStruct::new(self.layout()?, FfiAllocator::Rust)?;
189196

@@ -530,19 +537,30 @@ impl<'val> ArgValue<'val> {
530537
return Err(FfiError::StructNotFound(*arg_type_name));
531538
};
532539

533-
Ok(Self::Struct(struct_type.build(structs_table, args)?))
540+
Ok(Self::Struct(struct_type.build(
541+
*arg_type_name,
542+
structs_table,
543+
args,
544+
)?))
534545
}
535546
FfiType::Void => Err(FfiError::VoidArgumentType),
536547
}
537548
}
538549

539550
fn build_args(
551+
name: Atom,
552+
kind: ArgCountMismatchKind,
540553
args: &'val mut [Value],
541554
types: &[FfiType],
542555
structs_table: &HashMap<Atom, StructImpl>,
543556
) -> Result<Vec<Self>, FfiError> {
544557
if types.len() != args.len() {
545-
return Err(FfiError::ArgCountMismatch);
558+
return Err(FfiError::ArgCountMismatch {
559+
name,
560+
kind,
561+
expected: types.len(),
562+
got: args.len(),
563+
});
546564
}
547565

548566
args.iter_mut()
@@ -699,9 +717,15 @@ impl ForeignFunctionTable {
699717
let fn_impl = self
700718
.table
701719
.get(&fn_name)
702-
.ok_or(FfiError::FunctionNotFound(fn_name))?;
720+
.ok_or(FfiError::FunctionNotFound(fn_name, args.len()))?;
703721

704-
let args = ArgValue::build_args(&mut args, &fn_impl.args, &self.structs)?;
722+
let args = ArgValue::build_args(
723+
fn_name,
724+
ArgCountMismatchKind::Function,
725+
&mut args,
726+
&fn_impl.args,
727+
&self.structs,
728+
)?;
705729

706730
let args = PointerArgs::new(&args);
707731

@@ -760,7 +784,7 @@ impl ForeignFunctionTable {
760784

761785
let (_, args) = args.as_struct()?;
762786

763-
let ffi_struct = struct_impl.build(&self.structs, args)?;
787+
let ffi_struct = struct_impl.build(kind, &self.structs, args)?;
764788

765789
let ptr = ManuallyDrop::new(ffi_struct).ptr;
766790

@@ -946,9 +970,14 @@ pub enum FfiError {
946970
ValueCast(Atom, Atom),
947971
ValueOutOfRange(DomainErrorType, Value),
948972
VoidArgumentType,
949-
FunctionNotFound(Atom),
973+
FunctionNotFound(Atom, usize),
950974
StructNotFound(Atom),
951-
ArgCountMismatch,
975+
ArgCountMismatch {
976+
name: Atom, // ffi function or struct
977+
kind: ArgCountMismatchKind,
978+
expected: usize,
979+
got: usize,
980+
},
952981
AllocationFailed,
953982
// LayoutError should never occour
954983
LayoutError,
@@ -958,6 +987,12 @@ pub enum FfiError {
958987
NullPtr,
959988
}
960989

990+
#[derive(Debug)]
991+
pub(crate) enum ArgCountMismatchKind {
992+
Function,
993+
Struct,
994+
}
995+
961996
impl std::fmt::Display for FfiError {
962997
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
963998
std::fmt::Debug::fmt(self, f)

src/machine/machine_errors.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -447,10 +447,26 @@ impl MachineState {
447447
location: None,
448448
}
449449
}
450-
ExistenceError::FfiFunction(atom) => {
450+
ExistenceError::FfiFunction(name, arity) => {
451+
let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
451452
let stub = functor!(
452453
atom!("existence_error"),
453-
[atom_as_cell((atom!("ffi_function"))), atom_as_cell(atom)]
454+
[atom_as_cell((atom!("ffi_function"))), functor(culprit)]
455+
);
456+
457+
MachineError {
458+
stub,
459+
location: None,
460+
}
461+
}
462+
ExistenceError::FfiStructConstructor(name, arity) => {
463+
let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
464+
let stub = functor!(
465+
atom!("existence_error"),
466+
[
467+
atom_as_cell((atom!("ffi_struct_constructor"))),
468+
functor(culprit)
469+
]
454470
);
455471

456472
MachineError {
@@ -688,13 +704,25 @@ impl MachineState {
688704
}
689705
}
690706
FfiError::ValueOutOfRange(domain, culprit) => self.domain_error(domain, culprit),
691-
FfiError::FunctionNotFound(name) => {
692-
self.existence_error(ExistenceError::FfiFunction(name))
707+
FfiError::FunctionNotFound(name, arity) => {
708+
self.existence_error(ExistenceError::FfiFunction(name, arity))
693709
}
694710
FfiError::StructNotFound(name) => {
695711
self.existence_error(ExistenceError::FfiStructType(name))
696712
}
697-
FfiError::ArgCountMismatch => self.unreachable_error(),
713+
FfiError::ArgCountMismatch {
714+
name,
715+
kind,
716+
expected: _,
717+
got,
718+
} => match kind {
719+
ffi::ArgCountMismatchKind::Function => {
720+
self.existence_error(ExistenceError::FfiFunction(name, got))
721+
}
722+
ffi::ArgCountMismatchKind::Struct => {
723+
self.existence_error(ExistenceError::FfiStructConstructor(name, got))
724+
}
725+
},
698726
FfiError::AllocationFailed => MachineError {
699727
stub: functor!(atom!("resource_error"), [atom_as_cell((atom!("heap")))]),
700728
location: None,
@@ -1137,7 +1165,8 @@ pub enum ExistenceError {
11371165
SourceSink(HeapCellValue),
11381166
Stream(HeapCellValue),
11391167
Process(HeapCellValue),
1140-
FfiFunction(Atom),
1168+
FfiFunction(Atom, usize),
1169+
FfiStructConstructor(Atom, usize),
11411170
FfiStructType(Atom),
11421171
}
11431172

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
:- use_module(library(ffi)).
2+
3+
4+
test :- ffi:array_type(u8, 2, Type), ffi:allocate(rust, Type, [Type, 0], _ArrayPtr).
5+
6+
?- test.
7+
error(existence_error(ffi_struct_constructor,'$[u8;2]'/1),'$ffi_allocate'/4).
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
```trycmd
2+
$ scryer-prolog -f --no-add-history input.pl -g test -g halt
3+
test causes: error(existence_error(ffi_struct_constructor,$[u8;2]/1),$ffi_allocate/4)
4+
5+
```

0 commit comments

Comments
 (0)