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 #-cffi-features
:no-long-long
80 #+(and cffi-features
:darwin openmcl
)
81 (pushnew 'deref.long-long rt
::*expected-failures
*)
83 (deftest deref.long-long
84 (with-foreign-object (p :long-long
)
85 (setf (mem-ref p
:long-long
) -
9223372036854775807)
86 (mem-ref p
:long-long
))
89 (deftest deref.unsigned-long-long
90 (with-foreign-object (p :unsigned-long-long
)
91 (setf (mem-ref p
:unsigned-long-long
) 18446744073709551615)
92 (mem-ref p
:unsigned-long-long
))
93 18446744073709551615))
95 (deftest deref.float
.1
96 (with-foreign-object (p :float
)
97 (setf (mem-ref p
:float
) 0.0)
101 (deftest deref.float
.2
102 (with-foreign-object (p :float
)
103 (setf (mem-ref p
:float
) *float-max
*)
107 (deftest deref.float
.3
108 (with-foreign-object (p :float
)
109 (setf (mem-ref p
:float
) *float-min
*)
113 (deftest deref.double
.1
114 (with-foreign-object (p :double
)
115 (setf (mem-ref p
:double
) 0.0d0
)
119 (deftest deref.double
.2
120 (with-foreign-object (p :double
)
121 (setf (mem-ref p
:double
) *double-max
*)
125 (deftest deref.double
.3
126 (with-foreign-object (p :double
)
127 (setf (mem-ref p
:double
) *double-min
*)
131 ;;; TODO: use something like *DOUBLE-MIN/MAX* above once we actually
132 ;;; have an available lisp that supports long double.
133 ;#-cffi-features:no-long-float
134 #+(and scl long-double
)
136 (deftest deref.long-double
.1
137 (with-foreign-object (p :long-double
)
138 (setf (mem-ref p
:long-double
) 0.0l0)
139 (mem-ref p
:long-double
))
142 (deftest deref.long-double
.2
143 (with-foreign-object (p :long-double
)
144 (setf (mem-ref p
:long-double
) most-positive-long-float
)
145 (mem-ref p
:long-double
))
146 #.most-positive-long-float
)
148 (deftest deref.long-double
.3
149 (with-foreign-object (p :long-double
)
150 (setf (mem-ref p
:long-double
) least-positive-long-float
)
151 (mem-ref p
:long-double
))
152 #.least-positive-long-float
))
154 ;;; make sure the lisp doesn't convert NULL to NIL
155 (deftest deref.pointer.null
156 (with-foreign-object (p :pointer
)
157 (setf (mem-ref p
:pointer
) (null-pointer))
158 (null-pointer-p (mem-ref p
:pointer
)))
161 ;;; regression test. lisp-string-to-foreign should handle empty strings
162 (deftest lisp-string-to-foreign.empty
163 (with-foreign-pointer (str 2)
164 (setf (mem-ref str
:unsigned-char
) 42)
165 (lisp-string-to-foreign "" str
1)
166 (mem-ref str
:unsigned-char
))
169 ;; regression test. with-foreign-pointer shouldn't evaluate
170 ;; the size argument twice.
171 (deftest with-foreign-pointer.evalx2
173 (with-foreign-pointer (x (incf count
) size-var
)
174 (values count size-var
)))
177 (deftest mem-ref.left-to-right
179 (with-foreign-object (p :char
3)
180 (setf (mem-ref p
:char
0) 66 (mem-ref p
:char
1) 92)
181 (setf (mem-ref p
:char
(incf i
)) (incf i
))
182 (values (mem-ref p
:char
0) (mem-ref p
:char
1) i
)))
185 ;;; This needs to be in a real function for at least Allegro CL or the
186 ;;; compiler macro on %MEM-REF is not expanded and the test doesn't
187 ;;; actually test anything!
188 (defun %mem-ref-left-to-right
()
190 (with-foreign-object (p :char
)
191 (%mem-set
42 p
:char
)
192 (%mem-ref
(progn (push 1 result
) p
) :char
(progn (push 2 result
) 0))
195 ;;; Test left-to-right evaluation of the arguments to %MEM-REF when
196 ;;; optimized by the compiler macro.
197 (deftest %mem-ref.left-to-right
198 (%mem-ref-left-to-right
)
201 ;;; This needs to be in a top-level function for at least Allegro CL
202 ;;; or the compiler macro on %MEM-SET is not expanded and the test
203 ;;; doesn't actually test anything!
204 (defun %mem-set-left-to-right
()
206 (with-foreign-object (p :char
)
207 (%mem-set
(progn (push 1 result
) 0)
208 (progn (push 2 result
) p
)
210 (progn (push 3 result
) 0))
213 ;;; Test left-to-right evaluation of the arguments to %MEM-SET when
214 ;;; optimized by the compiler macro.
215 (deftest %mem-set.left-to-right
216 (%mem-set-left-to-right
)
219 ;; regression test. mem-aref's setf expansion evaluated its type argument twice.
220 (deftest mem-aref.eval-type-x2
222 (with-foreign-pointer (p 1)
223 (setf (mem-aref p
(progn (incf count
) :char
) 0) 127))
227 (deftest mem-aref.left-to-right
229 (with-foreign-pointer (p 2)
231 (setf (mem-aref p
(progn (incf count
) :char
) (incf count
)) (incf count
))
233 (mem-aref (progn (incf count
) p
) :char
(incf count
))
237 ;; regression tests. nested mem-ref's and mem-aref's had bogus getters
238 (deftest mem-ref.nested
239 (with-foreign-object (p :pointer
)
240 (with-foreign-object (i :int
)
241 (setf (mem-ref p
:pointer
) i
)
242 (setf (mem-ref i
:int
) 42)
243 (setf (mem-ref (mem-ref p
:pointer
) :int
) 1984)
247 (deftest mem-aref.nested
248 (with-foreign-object (p :pointer
)
249 (with-foreign-object (i :int
2)
250 (setf (mem-aref p
:pointer
0) i
)
251 (setf (mem-aref i
:int
1) 42)
252 (setf (mem-aref (mem-ref p
:pointer
0) :int
1) 1984)
253 (mem-aref i
:int
1)))
256 ;;; regression tests. dereferencing an aggregate type. dereferencing a
257 ;;; struct should return a pointer to the struct itself, not return the
258 ;;; first 4 bytes (or whatever the size of :pointer is) as a pointer.
260 ;;; This important for accessing an array of structs, which is
261 ;;; what the deref.array-of-aggregates test does.
262 (defcstruct some-struct
(x :int
))
264 (deftest deref.aggregate
265 (with-foreign-object (s 'some-struct
)
266 (pointer-eq s
(mem-ref s
'some-struct
)))
269 (deftest deref.array-of-aggregates
270 (with-foreign-object (arr 'some-struct
3)
272 do
(setf (foreign-slot-value (mem-aref arr
'some-struct i
)
276 collect
(foreign-slot-value (mem-aref arr
'some-struct i
)
280 ;;; pointer operations
282 (pointer-address (make-pointer 42))
285 ;;; I suppose this test is not very good. --luis
287 (pointer-address (null-pointer))
290 ;;; Ensure that a pointer to the highest possible address can be
291 ;;; created using MAKE-POINTER. Regression test for CLISP/X86-64.
292 (deftest make-pointer.high
293 (let* ((pointer-length (foreign-type-size :pointer
))
294 (high-address (1- (expt 2 (* pointer-length
8))))
295 (pointer (make-pointer high-address
)))
296 (- high-address
(pointer-address pointer
)))
299 ;;; Ensure that incrementing a pointer by zero bytes returns an
300 ;;; equivalent pointer.
301 (deftest inc-pointer.zero
302 (with-foreign-object (x :int
)
303 (pointer-eq x
(inc-pointer x
0)))
306 ;;; Test the INITIAL-ELEMENT keyword argument to FOREIGN-ALLOC.
307 (deftest foreign-alloc
.1
308 (let ((ptr (foreign-alloc :int
:initial-element
42)))
314 ;;; Test the INITIAL-ELEMENT and COUNT arguments to FOREIGN-ALLOC.
315 (deftest foreign-alloc
.2
316 (let ((ptr (foreign-alloc :int
:count
4 :initial-element
100)))
318 (loop for i from
0 below
4
319 collect
(mem-aref ptr
:int i
))
323 ;;; Test the INITIAL-CONTENTS and COUNT arguments to FOREIGN-ALLOC,
324 ;;; passing a list of initial values.
325 (deftest foreign-alloc
.3
326 (let ((ptr (foreign-alloc :int
:count
4 :initial-contents
'(4 3 2 1))))
328 (loop for i from
0 below
4
329 collect
(mem-aref ptr
:int i
))
333 ;;; Test INITIAL-CONTENTS and COUNT with FOREIGN-ALLOC passing a
334 ;;; vector of initial values.
335 (deftest foreign-alloc
.4
336 (let ((ptr (foreign-alloc :int
:count
4 :initial-contents
#(10 20 30 40))))
338 (loop for i from
0 below
4
339 collect
(mem-aref ptr
:int i
))
343 ;;; Ensure calling FOREIGN-ALLOC with both INITIAL-ELEMENT and
344 ;;; INITIAL-CONTENTS signals an error.
345 (deftest foreign-alloc
.5
348 (let ((ptr (foreign-alloc :int
:initial-element
1 :initial-contents
'(1))))
353 ;;; Regression test: FOREIGN-ALLOC shouldn't actually perform translation
354 ;;; on initial-element/initial-contents since MEM-AREF will do that already.
355 (define-foreign-type not-an-int
()
358 (:simple-parser not-an-int
))
360 (defmethod translate-to-foreign (value (type not-an-int
))
361 (assert (not (integerp value
)))
364 (deftest foreign-alloc
.6
365 (let ((ptr (foreign-alloc 'not-an-int
:initial-element
'foooo
)))
370 ;;; Ensure calling FOREIGN-ALLOC with NULL-TERMINATED-P and a non-pointer
371 ;;; type signals an error.
372 (deftest foreign-alloc
.7
375 (let ((ptr (foreign-alloc :int
:null-terminated-p t
)))
380 ;;; The opposite of the above test.
381 (defctype pointer-alias
:pointer
)
383 (deftest foreign-alloc
.8
385 (foreign-free (foreign-alloc 'pointer-alias
:count
0 :null-terminated-p t
))
389 ;;; Ensure calling FOREIGN-ALLOC with NULL-TERMINATED-P actually places
390 ;;; a null pointer at the end. Not a very reliable test apparently.
391 (deftest foreign-alloc
.9
392 (let ((ptr (foreign-alloc :pointer
:count
0 :null-terminated-p t
)))
394 (null-pointer-p (mem-ref ptr
:pointer
))
398 ;;; Tests for mem-ref with a non-constant type. This is a way to test
399 ;;; the functional interface (without compiler macros).
401 (deftest deref.nonconst.char
403 (with-foreign-object (p type
)
404 (setf (mem-ref p type
) -
127)
408 (deftest deref.nonconst.unsigned-char
409 (let ((type :unsigned-char
))
410 (with-foreign-object (p type
)
411 (setf (mem-ref p type
) 255)
415 (deftest deref.nonconst.short
417 (with-foreign-object (p type
)
418 (setf (mem-ref p type
) -
32767)
422 (deftest deref.nonconst.unsigned-short
423 (let ((type :unsigned-short
))
424 (with-foreign-object (p type
)
425 (setf (mem-ref p type
) 65535)
429 (deftest deref.nonconst.int
431 (with-foreign-object (p type
)
432 (setf (mem-ref p type
) -
131072)
436 (deftest deref.nonconst.unsigned-int
437 (let ((type :unsigned-int
))
438 (with-foreign-object (p type
)
439 (setf (mem-ref p type
) 262144)
443 (deftest deref.nonconst.long
445 (with-foreign-object (p type
)
446 (setf (mem-ref p type
) -
536870911)
450 (deftest deref.nonconst.unsigned-long
451 (let ((type :unsigned-long
))
452 (with-foreign-object (p type
)
453 (setf (mem-ref p type
) 536870912)
457 #-cffi-features
:no-long-long
459 #+(and cffi-features
:darwin openmcl
)
460 (pushnew 'deref.nonconst.long-long rt
::*expected-failures
*)
462 (deftest deref.nonconst.long-long
463 (let ((type :long-long
))
464 (with-foreign-object (p type
)
465 (setf (mem-ref p type
) -
9223372036854775807)
467 -
9223372036854775807)
469 (deftest deref.nonconst.unsigned-long-long
470 (let ((type :unsigned-long-long
))
471 (with-foreign-object (p type
)
472 (setf (mem-ref p type
) 18446744073709551615)
474 18446744073709551615))
476 (deftest deref.nonconst.float
.1
478 (with-foreign-object (p type
)
479 (setf (mem-ref p type
) 0.0)
483 (deftest deref.nonconst.float
.2
485 (with-foreign-object (p type
)
486 (setf (mem-ref p type
) *float-max
*)
490 (deftest deref.nonconst.float
.3
492 (with-foreign-object (p type
)
493 (setf (mem-ref p type
) *float-min
*)
497 (deftest deref.nonconst.double
.1
498 (let ((type :double
))
499 (with-foreign-object (p type
)
500 (setf (mem-ref p type
) 0.0d0
)
504 (deftest deref.nonconst.double
.2
505 (let ((type :double
))
506 (with-foreign-object (p type
)
507 (setf (mem-ref p type
) *double-max
*)
511 (deftest deref.nonconst.double
.3
512 (let ((type :double
))
513 (with-foreign-object (p type
)
514 (setf (mem-ref p type
) *double-min
*)
518 ;;; regression tests: lispworks's %mem-ref and %mem-set compiler
519 ;;; macros were misbehaving.
521 (defun mem-ref-rt-1 ()
522 (with-foreign-object (a :int
2)
523 (setf (mem-aref a
:int
0) 123
524 (mem-aref a
:int
1) 456)
525 (values (mem-aref a
:int
0) (mem-aref a
:int
1))))
527 (deftest mem-ref.rt
.1
531 (defun mem-ref-rt-2 ()
532 (with-foreign-object (a :double
2)
533 (setf (mem-aref a
:double
0) 123.0d0
534 (mem-aref a
:double
1) 456.0d0
)
535 (values (mem-aref a
:double
0) (mem-aref a
:double
1))))
537 (deftest mem-ref.rt
.2
541 (deftest incf-pointer
.1
542 (let ((ptr (null-pointer)))
544 (pointer-address ptr
))
547 (deftest incf-pointer
.2
548 (let ((ptr (null-pointer)))
549 (incf-pointer ptr
42)
550 (pointer-address ptr
))
555 (pointerp (null-pointer))
556 (null-pointer-p (null-pointer))
557 (typep (null-pointer) 'foreign-pointer
))
561 (let ((p (make-pointer #xFEFF
)))
564 (typep p
'foreign-pointer
)))