[UFFI-Users] get-slot-value and nested structures
Joerg-Cyril.Hoehle at t-systems.com
Mon Sep 13 06:27:57 MDT 2004
I'm a little more puzzled about get-slot-value. CLSQL has the following in db-mysql/mysql-api.lisp:
(length (* :unsigned-long))
(is-null (* mysql-bool))
and in db-mysql/mysql-sql.lisp:
(defmethod database-prepare [...]
(setf (uffi:get-slot-value binding 'mysql-bind 'buffer-length) 0)
(setf (uffi:get-slot-value binding 'mysql-bind 'is-null)
(+ i (uffi:pointer-address is-null-ptr)))
(setf (uffi:get-slot-value binding 'mysql-bind 'length)
(+ (* i 8) (uffi:pointer-address length-ptr)))
My naive understanding is that
[interpretation a] this should be a type error for both slots 'length and 'is-null because a call to uffi:make-pointer is missing to convert an int to a foreign pointer value for (* :unsigned-long) and (* mysql-bool).
IMHO, it's not acceptable to store an integer in a pointer object (although I believe this works in Allegro).
Alternatively [interpretation b], the existing pointer in the slot is used, not modified, and the given integer/bool value is dropped into the location that it points to.
This is what CLISP's FFI is doing, but that's not what I expected from UFFI after the previous discussion, because a recursive descent along pointers is not what I would expect from a sort of thin layer or least common denominator approach.
So what is the above code (more precisely, get-slot-value) doing and what is it supposed to do?
a1) yield a type error
a2) store a new pointer in the slots is-null and length
b) store an integer into the memory pointed to by the pointer slots?
>From looking at the surrounding code in mysql-sql.lisp, I suspect interpretation a2) is expected.
This IMHO means that the code is in fact missing (uffi:make-pointer around (+ ... uffi:pointer-address #) to be type-correct.
There are a few places in clsql where make-pointer is already used.
BTW, I fail to understand why the code setting the 'length slot uses (* i 8) instead of 4. It looks like a real buffer overflow bug. It's an array of num-fields :unsigned-long values which was allocated. The UFFI docs says it's implementation-dependent whether :unsigned-long is 32 or 64 bits. uffi:size-of-foreign-type may be required here?!?
I'm now wondering if this manual pointer arithmetic is necessary at all. In CLISP I could do something like the following and have the FFI correctly deal with pointer arithmetic and object sizes:
(dotimes (i num-fields)
(with-c-place (binding ...)
(setf (slot binding 'is-null) ; of some pointer type
(c-var-address (element is-null-ptr i)))))
or (foreign-address (ffi::%element is-null-ptr i)))))
It would require some uffi operation to take the address of an array element, which I haven't seen in the UFFI manual. (Additionaly, CLISP's ffi:element performs boundary checking).
Thanks for enlightening me,
More information about the UFFI-Users