struct by value doesn't work without runtime translation

Bug #1528719 reported by Attila Lendvai
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
CFFI
New
Undecided
Unassigned

Bug Description

the issue:

(progn
  (asdf:test-system :cffi-tests)
  (in-package :cffi-tests))

(with-foreign-object (arg '(:struct struct-pair))
  (convert-into-foreign-memory '(40 . 2) '(:struct pair) arg)
  (sumpair arg))

=> a runtime error because the current fsbv assumes that everything goes through runtime translators.

Revision history for this message
Attila Lendvai (attila-lendvai) wrote :

and a half-working solution:

defcstruct's define a lisp class to represent the struct type, and this lisp class inherits from both (CFFI::FOREIGN-STRUCT-TYPE CFFI::TRANSLATABLE-FOREIGN-TYPE).

after a long session of staring at trace output and letting my creativity loose in the forest of EXPAND-TO-FOREIGN-DYN, EXPAND-TO-FOREIGN-DYN-INDIRECT, TRANSLATE-TO-FOREIGN, TRANSLATE-INTO-FOREIGN-MEMORY, and friends... i've identified the magic 3 lines that fixes this:

(defmethod expand-to-foreign-dyn-indirect (value var body (type foreign-struct-type))
  `(let ((,var ,value))
     ,@body))

the problem is that this breaks type translation because it kicks in before the method specialized on TRANSLATABLE-FOREIGN-TYPE.

maybe there's someone with more insight into the cffi type internals who can come up with a fix for this?

unfortunately FOREIGN-POINTER is not a class, so we cannot dispatch on the value in CFFI::TRANSLATE-INTO-FOREIGN-MEMORY.

description: updated
description: updated
Revision history for this message
Attila Lendvai (attila-lendvai) wrote :

FTR, redefining this function achieves the goal and keeps all the tests running:

(defmethod expand-to-foreign-dyn-indirect :around
    (value var body (type translatable-foreign-type))
  (let ((*runtime-translator-form*
          `(if (typep ,value 'foreign-pointer)
               (let ((,var ,value))
                 ,@body)
               (with-foreign-object (,var ',(unparse-type type))
                 (translate-into-foreign-memory ,value ,type ,var)
                 ,@body))))
    (call-next-method)))

but it's kludgy, because it should dispatch on foreign-struct-type, and shouldn't duplicate ,@body.

Revision history for this message
Angel Peralta (acort3255) wrote :

Is this truly a bug? It seems like passing pointer to foreign struct should not be passed by value to the corresponding c function:

(defcfun "sumpair" :int
  (p (:struct struct-pair)))

corresponding failing test:

(deftest (fsbv.wfo :expected-to-fail t)
    (with-foreign-object (arg '(:struct struct-pair))
      (convert-into-foreign-memory '(40 . 2) '(:struct struct-pair) arg)
      (sumpair arg))
  42)

Is there something I'm missing here?

Revision history for this message
Attila Lendvai (attila-lendvai) wrote :

that's arguable, but i think it is indeed a bug.

rationale:

the CFFI domain does not have a concept of pointers (i.e. there's only one way using with-foreign-object to get hold of a new :struct). and it's an implementation detail how that struct is accounted for. and therefore, it's reasonable to expect CFFI to automatically do the right thing when such a struct is passed to a C fuction that expects a struct by value, or a struct pointer.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.