Struct assignment from plist calls convert-to-foreign twice

Bug #1948725 reported by Andrew Soutar
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
CFFI
New
Undecided
Unassigned

Bug Description

Consider the following definitions:

```
(defcstruct test-struct
  (:array-field (:array :int 1))
  (:bool-field :boolean))
```

The following would be expected to work:
```
(with-foreign-object (test-obj '(:struct test-struct))
  (setf (mem-ref test-obj '(:struct test-struct)) '(:array-field #(0) :bool-field nil)))
```

However, each of those fails in different ways. The array field errors out:
```
(with-foreign-object (test-obj '(:struct test-struct))
  (setf (mem-ref test-obj '(:struct test-struct)) '(:array-field #(0))))
```

```
The value
  #.(SB-SYS:INT-SAP #X7FCDDCA105B0)
is not of type
  ARRAY
when binding ARRAY
   [Condition of type TYPE-ERROR]

Backtrace:
 0: (AREF #.(SB-SYS:INT-SAP #X7FCDDCA105B0) 0) [more]
 1: (LISP-ARRAY-TO-FOREIGN #.(SB-SYS:INT-SAP #X7FCDDCA105B0) #.(SB-SYS:INT-SAP #X7FCDE3B5FFE0) (:ARRAY :INT 1))
 2: ((:METHOD (SETF CFFI::FOREIGN-STRUCT-SLOT-VALUE) (T T CFFI::AGGREGATE-STRUCT-SLOT)) #.(SB-SYS:INT-SAP #X7FCDDCA105B0) #.(SB-SYS:INT-SAP #X7FCDE3B5FFE0) #<CFFI::AGGREGATE-STRUCT-SLOT {1005854CC3}>) [fa..
 3: (CFFI::FOREIGN-SLOT-SET #.(SB-SYS:INT-SAP #X7FCDDCA105B0) #.(SB-SYS:INT-SAP #X7FCDE3B5FFE0) (:STRUCT TEST-STRUCT) :ARRAY-FIELD)
 4: ((:METHOD TRANSLATE-INTO-FOREIGN-MEMORY (LIST CFFI::FOREIGN-STRUCT-TYPE T)) (:ARRAY-FIELD #(0)) #<TEST-STRUCT-TCLASS TEST-STRUCT> #.(SB-SYS:INT-SAP #X7FCDE3B5FFE0)) [fast-method]
...
```

The bool field gets set to `t` instead of `nil`:
```
(with-foreign-object (test-obj '(:struct test-struct))
  (setf (mem-ref test-obj '(:struct test-struct)) '(:bool-field nil))
  (foreign-slot-value test-obj '(:struct test-struct) :bool-field))
```
returns T.

These are both caused by an extra call to `convert-to-foreign` inside of `(translate-to-foreign-memory list foreign-struct-type t)`. In the array case, `convert-to-foreign` converts the array to a pointer, rather than initializing the slot directly. (This also seems to cause the allocated array to leak; I believe the same behavior occurs with nested structs.) In the :boolean case, `convert-to-foreign` converts `nil` to `0`; when it gets assigned to the slot, `translate-to-foreign` gets called again, and since `0` is truthy, the actual assigned value is `1`. Naively removing that call makes both of the above cases work correctly, but breaks nested struct initialization; this seems to be because structs are treated as aggregates to be initialized from a pointer, even though with the new :struct specifiers they are initialized by value instead, and the extra call to `convert-from-foreign` seems to paper over that inconsistency.

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.