libffi: clean up the ABI enum
[cffi.git] / tests / memory.lisp
blob2623d2013ab85f3d5b65fad99c16a28a25561d68
1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
2 ;;;
3 ;;; memory.lisp --- Tests for memory referencing.
4 ;;;
5 ;;; Copyright (C) 2005-2006, James Bielman <jamesjb@jamesjb.com>
6 ;;;
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:
14 ;;;
15 ;;; The above copyright notice and this permission notice shall be
16 ;;; included in all copies or substantial portions of the Software.
17 ;;;
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.
26 ;;;
28 (in-package #:cffi-tests)
30 (deftest deref.char
31 (with-foreign-object (p :char)
32 (setf (mem-ref p :char) -127)
33 (mem-ref p :char))
34 -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))
40 255)
42 (deftest deref.short
43 (with-foreign-object (p :short)
44 (setf (mem-ref p :short) -32767)
45 (mem-ref p :short))
46 -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))
52 65535)
54 (deftest deref.int
55 (with-foreign-object (p :int)
56 (setf (mem-ref p :int) -131072)
57 (mem-ref p :int))
58 -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))
64 262144)
66 (deftest deref.long
67 (with-foreign-object (p :long)
68 (setf (mem-ref p :long) -536870911)
69 (mem-ref p :long))
70 -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))
76 536870912)
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))
85 -9223372036854775807)
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))
91 18446744073709551615)
93 (deftest deref.float.1
94 (with-foreign-object (p :float)
95 (setf (mem-ref p :float) 0.0)
96 (mem-ref p :float))
97 0.0)
99 (deftest deref.float.2
100 (with-foreign-object (p :float)
101 (setf (mem-ref p :float) *float-max*)
102 (mem-ref p :float))
103 #.*float-max*)
105 (deftest deref.float.3
106 (with-foreign-object (p :float)
107 (setf (mem-ref p :float) *float-min*)
108 (mem-ref p :float))
109 #.*float-min*)
111 (deftest deref.double.1
112 (with-foreign-object (p :double)
113 (setf (mem-ref p :double) 0.0d0)
114 (mem-ref p :double))
115 0.0d0)
117 (deftest deref.double.2
118 (with-foreign-object (p :double)
119 (setf (mem-ref p :double) *double-max*)
120 (mem-ref p :double))
121 #.*double-max*)
123 (deftest deref.double.3
124 (with-foreign-object (p :double)
125 (setf (mem-ref p :double) *double-min*)
126 (mem-ref p :double))
127 #.*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)
133 (progn
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))
138 0.0l0)
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
170 (let ((count 0))
171 (with-foreign-pointer (x (incf count) size-var)
172 (values count size-var)))
173 1 1)
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)
181 size)
184 (deftest mem-ref.left-to-right
185 (let ((i 0))
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)))
190 66 2 2)
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 ()
196 (let ((result nil))
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))
200 (nreverse result))))
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)
206 (1 2))
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 ()
212 (let ((result nil))
213 (with-foreign-object (p :char)
214 (%mem-set (progn (push 1 result) 0)
215 (progn (push 2 result) p)
216 :char
217 (progn (push 3 result) 0))
218 (nreverse result))))
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)
224 (1 2 3))
226 ;; regression test. mem-aref's setf expansion evaluated its type argument twice.
227 (deftest mem-aref.eval-type-x2
228 (let ((count 0))
229 (with-foreign-pointer (p 1)
230 (setf (mem-aref p (progn (incf count) :char) 0) 127))
231 count)
234 (deftest mem-aref.left-to-right
235 (let ((count -1))
236 (with-foreign-pointer (p 2)
237 (values
238 (setf (mem-aref p (progn (incf count) :char) (incf count)) (incf count))
239 (setq count -1)
240 (mem-aref (progn (incf count) p) :char (incf count))
241 count)))
242 2 -1 2 1)
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)
251 (mem-ref i :int)))
252 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)))
261 1984)
263 (cffi:defcstruct mem-aref.bare-struct
264 (a :uint8))
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)
292 (loop for i below 3
293 do (setf (foreign-slot-value (mem-aref arr 'some-struct i)
294 'some-struct 'x)
295 112))
296 (loop for i below 3
297 collect (foreign-slot-value (mem-aref arr 'some-struct i)
298 'some-struct 'x)))
299 (112 112 112))
301 ;;; pointer operations
302 (deftest pointer.1
303 (pointer-address (make-pointer 42))
306 ;;; I suppose this test is not very good. --luis
307 (deftest pointer.2
308 (pointer-address (null-pointer))
311 (deftest pointer.null
312 (nth-value 0 (ignore-errors (null-pointer-p nil)))
313 nil)
315 (deftest foreign-pointer-type.nil
316 (typep nil 'foreign-pointer)
317 nil)
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)))
338 (unwind-protect
339 (mem-ref ptr :int)
340 (foreign-free ptr)))
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)))
346 (unwind-protect
347 (loop for i from 0 below 4
348 collect (mem-aref ptr :int i))
349 (foreign-free ptr)))
350 (100 100 100 100))
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))))
356 (unwind-protect
357 (loop for i from 0 below 4
358 collect (mem-aref ptr :int i))
359 (foreign-free ptr)))
360 (4 3 2 1))
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))))
366 (unwind-protect
367 (loop for i from 0 below 4
368 collect (mem-aref ptr :int i))
369 (foreign-free ptr)))
370 (10 20 30 40))
372 ;;; Ensure calling FOREIGN-ALLOC with both INITIAL-ELEMENT and
373 ;;; INITIAL-CONTENTS signals an error.
374 (deftest foreign-alloc.5
375 (values
376 (ignore-errors
377 (let ((ptr (foreign-alloc :int :initial-element 1
378 :initial-contents '(1))))
379 (foreign-free ptr))
381 nil)
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 ()
387 (:actual-type :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)))
396 (foreign-free ptr)
400 ;;; Ensure calling FOREIGN-ALLOC with NULL-TERMINATED-P and a non-pointer
401 ;;; type signals an error.
402 (deftest foreign-alloc.7
403 (values
404 (ignore-errors
405 (let ((ptr (foreign-alloc :int :null-terminated-p t)))
406 (foreign-free ptr))
408 nil)
410 ;;; The opposite of the above test.
411 (defctype pointer-alias :pointer)
413 (deftest foreign-alloc.8
414 (progn
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)))
423 (unwind-protect
424 (null-pointer-p (mem-ref ptr :pointer))
425 (foreign-free ptr)))
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
437 (let ((type :char))
438 (with-foreign-object (p type)
439 (setf (mem-ref p type) -127)
440 (mem-ref p type)))
441 -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)
447 (mem-ref p type)))
448 255)
450 (deftest deref.nonconst.short
451 (let ((type :short))
452 (with-foreign-object (p type)
453 (setf (mem-ref p type) -32767)
454 (mem-ref p type)))
455 -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)
461 (mem-ref p type)))
462 65535)
464 (deftest deref.nonconst.int
465 (let ((type :int))
466 (with-foreign-object (p type)
467 (setf (mem-ref p type) -131072)
468 (mem-ref p type)))
469 -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)
475 (mem-ref p type)))
476 262144)
478 (deftest deref.nonconst.long
479 (let ((type :long))
480 (with-foreign-object (p type)
481 (setf (mem-ref p type) -536870911)
482 (mem-ref p type)))
483 -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)
489 (mem-ref p type)))
490 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)
499 (mem-ref p type)))
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)
506 (mem-ref p type)))
507 18446744073709551615)
509 (deftest deref.nonconst.float.1
510 (let ((type :float))
511 (with-foreign-object (p type)
512 (setf (mem-ref p type) 0.0)
513 (mem-ref p type)))
514 0.0)
516 (deftest deref.nonconst.float.2
517 (let ((type :float))
518 (with-foreign-object (p type)
519 (setf (mem-ref p type) *float-max*)
520 (mem-ref p type)))
521 #.*float-max*)
523 (deftest deref.nonconst.float.3
524 (let ((type :float))
525 (with-foreign-object (p type)
526 (setf (mem-ref p type) *float-min*)
527 (mem-ref p type)))
528 #.*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)
534 (mem-ref p type)))
535 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*)
541 (mem-ref p type)))
542 #.*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*)
548 (mem-ref p type)))
549 #.*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
561 (mem-ref-rt-1)
562 123 456)
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
571 (mem-ref-rt-2)
572 123.0d0 456.0d0)
574 (deftest incf-pointer.1
575 (let ((ptr (null-pointer)))
576 (incf-pointer ptr)
577 (pointer-address ptr))
580 (deftest incf-pointer.2
581 (let ((ptr (null-pointer)))
582 (incf-pointer ptr 42)
583 (pointer-address ptr))
586 (deftest pointerp.1
587 (values
588 (pointerp (null-pointer))
589 (null-pointer-p (null-pointer))
590 (typep (null-pointer) 'foreign-pointer))
591 t t t)
593 (deftest pointerp.2
594 (let ((p (make-pointer #xFEFF)))
595 (values
596 (pointerp p)
597 (typep p 'foreign-pointer)))
598 t t)
600 (deftest pointerp.3
601 (pointerp 'not-a-pointer)
602 nil)
604 (deftest pointerp.4
605 (pointerp 42)
606 nil)
608 (deftest pointerp.5
609 (pointerp 0)
610 nil)
612 (deftest pointerp.6
613 (pointerp nil)
614 nil)
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 ()
623 (:actual-type :int)
624 (:simple-parser int+1))
626 (defmethod translate-to-foreign (value (type int+1))
627 (1+ value))
629 (defmethod translate-from-foreign (value (type int+1))
630 (1+ value))
632 (deftest mem-ref.setf.2
633 (with-foreign-object (p 'int+1)
634 (values (setf (mem-ref p 'int+1) 42)
635 (mem-ref p 'int+1)))
636 42 ; should this be 43?
639 (deftest pointer-eq.non-pointers.1
640 (expecting-error (pointer-eq 1 2))
641 :error)
643 (deftest pointer-eq.non-pointers.2
644 (expecting-error (pointer-eq 'a 'b))
645 :error)
647 (deftest null-pointer-p.non-pointer.1
648 (expecting-error (null-pointer-p 'not-a-pointer))
649 :error)
651 (deftest null-pointer-p.non-pointer.2
652 (expecting-error (null-pointer-p 0))
653 :error)
655 (deftest null-pointer-p.non-pointer.3
656 (expecting-error (null-pointer-p nil))
657 :error)