1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
3 ;;; memory.lisp --- Tests for memory referencing.
5 ;;; Copyright (C) 2005-2006, James Bielman <jamesjb@jamesjb.com>
7 ;;; Permission is hereby granted, free of charge, to any person
8 ;;; obtaining a copy of this software and associated documentation
9 ;;; files (the "Software"), to deal in the Software without
10 ;;; restriction, including without limitation the rights to use, copy,
11 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies
12 ;;; of the Software, and to permit persons to whom the Software is
13 ;;; furnished to do so, subject to the following conditions:
15 ;;; The above copyright notice and this permission notice shall be
16 ;;; included in all copies or substantial portions of the Software.
18 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 ;;; DEALINGS IN THE SOFTWARE.
28 (in-package #:cffi-tests
)
31 (with-foreign-object (p :char
)
32 (setf (mem-ref p
:char
) -
127)
36 (deftest deref.unsigned-char
37 (with-foreign-object (p :unsigned-char
)
38 (setf (mem-ref p
:unsigned-char
) 255)
39 (mem-ref p
:unsigned-char
))
43 (with-foreign-object (p :short
)
44 (setf (mem-ref p
:short
) -
32767)
48 (deftest deref.unsigned-short
49 (with-foreign-object (p :unsigned-short
)
50 (setf (mem-ref p
:unsigned-short
) 65535)
51 (mem-ref p
:unsigned-short
))
55 (with-foreign-object (p :int
)
56 (setf (mem-ref p
:int
) -
131072)
60 (deftest deref.unsigned-int
61 (with-foreign-object (p :unsigned-int
)
62 (setf (mem-ref p
:unsigned-int
) 262144)
63 (mem-ref p
:unsigned-int
))
67 (with-foreign-object (p :long
)
68 (setf (mem-ref p
:long
) -
536870911)
72 (deftest deref.unsigned-long
73 (with-foreign-object (p :unsigned-long
)
74 (setf (mem-ref p
:unsigned-long
) 536870912)
75 (mem-ref p
:unsigned-long
))
78 #+(and darwin openmcl
)
79 (pushnew 'deref.long-long rtest
::*expected-failures
*)
81 (deftest deref.long-long
82 (with-foreign-object (p :long-long
)
83 (setf (mem-ref p
:long-long
) -
9223372036854775807)
84 (mem-ref p
:long-long
))
87 (deftest deref.unsigned-long-long
88 (with-foreign-object (p :unsigned-long-long
)
89 (setf (mem-ref p
:unsigned-long-long
) 18446744073709551615)
90 (mem-ref p
:unsigned-long-long
))
93 (deftest deref.float
.1
94 (with-foreign-object (p :float
)
95 (setf (mem-ref p
:float
) 0.0)
99 (deftest deref.float
.2
100 (with-foreign-object (p :float
)
101 (setf (mem-ref p
:float
) *float-max
*)
105 (deftest deref.float
.3
106 (with-foreign-object (p :float
)
107 (setf (mem-ref p
:float
) *float-min
*)
111 (deftest deref.double
.1
112 (with-foreign-object (p :double
)
113 (setf (mem-ref p
:double
) 0.0d0
)
117 (deftest deref.double
.2
118 (with-foreign-object (p :double
)
119 (setf (mem-ref p
:double
) *double-max
*)
123 (deftest deref.double
.3
124 (with-foreign-object (p :double
)
125 (setf (mem-ref p
:double
) *double-min
*)
129 ;;; TODO: use something like *DOUBLE-MIN/MAX* above once we actually
130 ;;; have an available lisp that supports long double.
131 ;#-cffi-sys::no-long-float
132 #+(and (or ecl scl
) long-float
)
134 (deftest deref.long-double
.1
135 (with-foreign-object (p :long-double
)
136 (setf (mem-ref p
:long-double
) 0.0l0)
137 (mem-ref p
:long-double
))
140 (deftest deref.long-double
.2
141 (with-foreign-object (p :long-double
)
142 (setf (mem-ref p
:long-double
) most-positive-long-float
)
143 (mem-ref p
:long-double
))
144 #.most-positive-long-float
)
146 (deftest deref.long-double
.3
147 (with-foreign-object (p :long-double
)
148 (setf (mem-ref p
:long-double
) least-positive-long-float
)
149 (mem-ref p
:long-double
))
150 #.least-positive-long-float
))
152 ;;; make sure the lisp doesn't convert NULL to NIL
153 (deftest deref.pointer.null
154 (with-foreign-object (p :pointer
)
155 (setf (mem-ref p
:pointer
) (null-pointer))
156 (null-pointer-p (mem-ref p
:pointer
)))
159 ;;; regression test. lisp-string-to-foreign should handle empty strings
160 (deftest lisp-string-to-foreign.empty
161 (with-foreign-pointer (str 2)
162 (setf (mem-ref str
:unsigned-char
) 42)
163 (lisp-string-to-foreign "" str
1)
164 (mem-ref str
:unsigned-char
))
167 ;;; regression test. with-foreign-pointer shouldn't evaluate
168 ;;; the size argument twice.
169 (deftest with-foreign-pointer.evalx2
171 (with-foreign-pointer (x (incf count
) size-var
)
172 (values count size-var
)))
175 (defconstant +two
+ 2)
177 ;;; regression test. cffi-allegro's with-foreign-pointer wasn't
178 ;;; handling constants properly.
179 (deftest with-foreign-pointer.constant-size
180 (with-foreign-pointer (p +two
+ size
)
184 (deftest mem-ref.left-to-right
186 (with-foreign-object (p :char
3)
187 (setf (mem-ref p
:char
0) 66 (mem-ref p
:char
1) 92)
188 (setf (mem-ref p
:char
(incf i
)) (incf i
))
189 (values (mem-ref p
:char
0) (mem-ref p
:char
1) i
)))
192 ;;; This needs to be in a real function for at least Allegro CL or the
193 ;;; compiler macro on %MEM-REF is not expanded and the test doesn't
194 ;;; actually test anything!
195 (defun %mem-ref-left-to-right
()
197 (with-foreign-object (p :char
)
198 (%mem-set
42 p
:char
)
199 (%mem-ref
(progn (push 1 result
) p
) :char
(progn (push 2 result
) 0))
202 ;;; Test left-to-right evaluation of the arguments to %MEM-REF when
203 ;;; optimized by the compiler macro.
204 (deftest %mem-ref.left-to-right
205 (%mem-ref-left-to-right
)
208 ;;; This needs to be in a top-level function for at least Allegro CL
209 ;;; or the compiler macro on %MEM-SET is not expanded and the test
210 ;;; doesn't actually test anything!
211 (defun %mem-set-left-to-right
()
213 (with-foreign-object (p :char
)
214 (%mem-set
(progn (push 1 result
) 0)
215 (progn (push 2 result
) p
)
217 (progn (push 3 result
) 0))
220 ;;; Test left-to-right evaluation of the arguments to %MEM-SET when
221 ;;; optimized by the compiler macro.
222 (deftest %mem-set.left-to-right
223 (%mem-set-left-to-right
)
226 ;; regression test. mem-aref's setf expansion evaluated its type argument twice.
227 (deftest mem-aref.eval-type-x2
229 (with-foreign-pointer (p 1)
230 (setf (mem-aref p
(progn (incf count
) :char
) 0) 127))
234 (deftest mem-aref.left-to-right
236 (with-foreign-pointer (p 2)
238 (setf (mem-aref p
(progn (incf count
) :char
) (incf count
)) (incf count
))
240 (mem-aref (progn (incf count
) p
) :char
(incf count
))
244 ;; regression tests. nested mem-ref's and mem-aref's had bogus getters
245 (deftest mem-ref.nested
246 (with-foreign-object (p :pointer
)
247 (with-foreign-object (i :int
)
248 (setf (mem-ref p
:pointer
) i
)
249 (setf (mem-ref i
:int
) 42)
250 (setf (mem-ref (mem-ref p
:pointer
) :int
) 1984)
254 (deftest mem-aref.nested
255 (with-foreign-object (p :pointer
)
256 (with-foreign-object (i :int
2)
257 (setf (mem-aref p
:pointer
0) i
)
258 (setf (mem-aref i
:int
1) 42)
259 (setf (mem-aref (mem-ref p
:pointer
0) :int
1) 1984)
260 (mem-aref i
:int
1)))
263 (cffi:defcstruct mem-aref.bare-struct
266 ;;; regression test: although mem-aref was dealing with bare struct
267 ;;; types as though they were pointers, it wasn't calculating the
268 ;;; proper offsets. The offsets for bare structs types should be
269 ;;; calculated as aggregate types.
270 (deftest mem-aref.bare-struct
271 (with-foreign-object (a 'mem-aref.bare-struct
2)
272 (eql (- (pointer-address (cffi:mem-aref a
'mem-aref.bare-struct
1))
273 (pointer-address (cffi:mem-aref a
'mem-aref.bare-struct
0)))
274 (foreign-type-size '(:struct mem-aref.bare-struct
))))
277 ;;; regression tests. dereferencing an aggregate type. dereferencing a
278 ;;; struct should return a pointer to the struct itself, not return the
279 ;;; first 4 bytes (or whatever the size of :pointer is) as a pointer.
281 ;;; This important for accessing an array of structs, which is
282 ;;; what the deref.array-of-aggregates test does.
283 (defcstruct some-struct
(x :int
))
285 (deftest deref.aggregate
286 (with-foreign-object (s 'some-struct
)
287 (pointer-eq s
(mem-ref s
'some-struct
)))
290 (deftest deref.array-of-aggregates
291 (with-foreign-object (arr 'some-struct
3)
293 do
(setf (foreign-slot-value (mem-aref arr
'some-struct i
)
297 collect
(foreign-slot-value (mem-aref arr
'some-struct i
)
301 ;;; pointer operations
303 (pointer-address (make-pointer 42))
306 ;;; I suppose this test is not very good. --luis
308 (pointer-address (null-pointer))
311 (deftest pointer.null
312 (nth-value 0 (ignore-errors (null-pointer-p nil
)))
315 (deftest foreign-pointer-type.nil
316 (typep nil
'foreign-pointer
)
319 ;;; Ensure that a pointer to the highest possible address can be
320 ;;; created using MAKE-POINTER. Regression test for CLISP/X86-64.
321 (deftest make-pointer.high
322 (let* ((pointer-length (foreign-type-size :pointer
))
323 (high-address (1- (expt 2 (* pointer-length
8))))
324 (pointer (make-pointer high-address
)))
325 (- high-address
(pointer-address pointer
)))
328 ;;; Ensure that incrementing a pointer by zero bytes returns an
329 ;;; equivalent pointer.
330 (deftest inc-pointer.zero
331 (with-foreign-object (x :int
)
332 (pointer-eq x
(inc-pointer x
0)))
335 ;;; Test the INITIAL-ELEMENT keyword argument to FOREIGN-ALLOC.
336 (deftest foreign-alloc
.1
337 (let ((ptr (foreign-alloc :int
:initial-element
42)))
343 ;;; Test the INITIAL-ELEMENT and COUNT arguments to FOREIGN-ALLOC.
344 (deftest foreign-alloc
.2
345 (let ((ptr (foreign-alloc :int
:count
4 :initial-element
100)))
347 (loop for i from
0 below
4
348 collect
(mem-aref ptr
:int i
))
352 ;;; Test the INITIAL-CONTENTS and COUNT arguments to FOREIGN-ALLOC,
353 ;;; passing a list of initial values.
354 (deftest foreign-alloc
.3
355 (let ((ptr (foreign-alloc :int
:count
4 :initial-contents
'(4 3 2 1))))
357 (loop for i from
0 below
4
358 collect
(mem-aref ptr
:int i
))
362 ;;; Test INITIAL-CONTENTS and COUNT with FOREIGN-ALLOC passing a
363 ;;; vector of initial values.
364 (deftest foreign-alloc
.4
365 (let ((ptr (foreign-alloc :int
:count
4 :initial-contents
#(10 20 30 40))))
367 (loop for i from
0 below
4
368 collect
(mem-aref ptr
:int i
))
372 ;;; Ensure calling FOREIGN-ALLOC with both INITIAL-ELEMENT and
373 ;;; INITIAL-CONTENTS signals an error.
374 (deftest foreign-alloc
.5
377 (let ((ptr (foreign-alloc :int
:initial-element
1
378 :initial-contents
'(1))))
383 ;;; Regression test: FOREIGN-ALLOC shouldn't actually perform translation
384 ;;; on initial-element/initial-contents since MEM-AREF will do that already.
385 (define-foreign-type not-an-int
()
388 (:simple-parser not-an-int
))
390 (defmethod translate-to-foreign (value (type not-an-int
))
391 (assert (not (integerp value
)))
394 (deftest foreign-alloc
.6
395 (let ((ptr (foreign-alloc 'not-an-int
:initial-element
'foooo
)))
400 ;;; Ensure calling FOREIGN-ALLOC with NULL-TERMINATED-P and a non-pointer
401 ;;; type signals an error.
402 (deftest foreign-alloc
.7
405 (let ((ptr (foreign-alloc :int
:null-terminated-p t
)))
410 ;;; The opposite of the above test.
411 (defctype pointer-alias
:pointer
)
413 (deftest foreign-alloc
.8
415 (foreign-free (foreign-alloc 'pointer-alias
:count
0 :null-terminated-p t
))
419 ;;; Ensure calling FOREIGN-ALLOC with NULL-TERMINATED-P actually places
420 ;;; a null pointer at the end. Not a very reliable test apparently.
421 (deftest foreign-alloc
.9
422 (let ((ptr (foreign-alloc :pointer
:count
0 :null-terminated-p t
)))
424 (null-pointer-p (mem-ref ptr
:pointer
))
428 ;;; RT: FOREIGN-ALLOC with :COUNT 0 on CLISP signalled an error.
429 (deftest foreign-alloc
.10
430 (null (foreign-free (foreign-alloc :char
:count
0)))
433 ;;; Tests for mem-ref with a non-constant type. This is a way to test
434 ;;; the functional interface (without compiler macros).
436 (deftest deref.nonconst.char
438 (with-foreign-object (p type
)
439 (setf (mem-ref p type
) -
127)
443 (deftest deref.nonconst.unsigned-char
444 (let ((type :unsigned-char
))
445 (with-foreign-object (p type
)
446 (setf (mem-ref p type
) 255)
450 (deftest deref.nonconst.short
452 (with-foreign-object (p type
)
453 (setf (mem-ref p type
) -
32767)
457 (deftest deref.nonconst.unsigned-short
458 (let ((type :unsigned-short
))
459 (with-foreign-object (p type
)
460 (setf (mem-ref p type
) 65535)
464 (deftest deref.nonconst.int
466 (with-foreign-object (p type
)
467 (setf (mem-ref p type
) -
131072)
471 (deftest deref.nonconst.unsigned-int
472 (let ((type :unsigned-int
))
473 (with-foreign-object (p type
)
474 (setf (mem-ref p type
) 262144)
478 (deftest deref.nonconst.long
480 (with-foreign-object (p type
)
481 (setf (mem-ref p type
) -
536870911)
485 (deftest deref.nonconst.unsigned-long
486 (let ((type :unsigned-long
))
487 (with-foreign-object (p type
)
488 (setf (mem-ref p type
) 536870912)
492 #+(and darwin openmcl
)
493 (pushnew 'deref.nonconst.long-long rtest
::*expected-failures
*)
495 (deftest deref.nonconst.long-long
496 (let ((type :long-long
))
497 (with-foreign-object (p type
)
498 (setf (mem-ref p type
) -
9223372036854775807)
500 -
9223372036854775807)
502 (deftest deref.nonconst.unsigned-long-long
503 (let ((type :unsigned-long-long
))
504 (with-foreign-object (p type
)
505 (setf (mem-ref p type
) 18446744073709551615)
507 18446744073709551615)
509 (deftest deref.nonconst.float
.1
511 (with-foreign-object (p type
)
512 (setf (mem-ref p type
) 0.0)
516 (deftest deref.nonconst.float
.2
518 (with-foreign-object (p type
)
519 (setf (mem-ref p type
) *float-max
*)
523 (deftest deref.nonconst.float
.3
525 (with-foreign-object (p type
)
526 (setf (mem-ref p type
) *float-min
*)
530 (deftest deref.nonconst.double
.1
531 (let ((type :double
))
532 (with-foreign-object (p type
)
533 (setf (mem-ref p type
) 0.0d0
)
537 (deftest deref.nonconst.double
.2
538 (let ((type :double
))
539 (with-foreign-object (p type
)
540 (setf (mem-ref p type
) *double-max
*)
544 (deftest deref.nonconst.double
.3
545 (let ((type :double
))
546 (with-foreign-object (p type
)
547 (setf (mem-ref p type
) *double-min
*)
551 ;;; regression tests: lispworks's %mem-ref and %mem-set compiler
552 ;;; macros were misbehaving.
554 (defun mem-ref-rt-1 ()
555 (with-foreign-object (a :int
2)
556 (setf (mem-aref a
:int
0) 123
557 (mem-aref a
:int
1) 456)
558 (values (mem-aref a
:int
0) (mem-aref a
:int
1))))
560 (deftest mem-ref.rt
.1
564 (defun mem-ref-rt-2 ()
565 (with-foreign-object (a :double
2)
566 (setf (mem-aref a
:double
0) 123.0d0
567 (mem-aref a
:double
1) 456.0d0
)
568 (values (mem-aref a
:double
0) (mem-aref a
:double
1))))
570 (deftest mem-ref.rt
.2
574 (deftest incf-pointer
.1
575 (let ((ptr (null-pointer)))
577 (pointer-address ptr
))
580 (deftest incf-pointer
.2
581 (let ((ptr (null-pointer)))
582 (incf-pointer ptr
42)
583 (pointer-address ptr
))
588 (pointerp (null-pointer))
589 (null-pointer-p (null-pointer))
590 (typep (null-pointer) 'foreign-pointer
))
594 (let ((p (make-pointer #xFEFF
)))
597 (typep p
'foreign-pointer
)))
601 (pointerp 'not-a-pointer
)
616 (deftest mem-ref.setf
.1
617 (with-foreign-object (p :char
)
618 (setf (mem-ref p
:char
) 42))
621 (define-foreign-type int
+1 ()
624 (:simple-parser int
+1))
626 (defmethod translate-to-foreign (value (type int
+1))
629 (defmethod translate-from-foreign (value (type int
+1))
632 (deftest mem-ref.setf
.2
633 (with-foreign-object (p 'int
+1)
634 (values (setf (mem-ref p
'int
+1) 42)
636 42 ; should this be 43?
639 (deftest pointer-eq.non-pointers
.1
640 (expecting-error (pointer-eq 1 2))
643 (deftest pointer-eq.non-pointers
.2
644 (expecting-error (pointer-eq 'a
'b
))
647 (deftest null-pointer-p.non-pointer
.1
648 (expecting-error (null-pointer-p 'not-a-pointer
))
651 (deftest null-pointer-p.non-pointer
.2
652 (expecting-error (null-pointer-p 0))
655 (deftest null-pointer-p.non-pointer
.3
656 (expecting-error (null-pointer-p nil
))