memory.lisp - clic - Clic is an command line interactive client for gopher written in Common LISP
HTML git clone git://bitreich.org/clic/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/clic/
DIR Log
DIR Files
DIR Refs
DIR Tags
DIR README
DIR LICENSE
---
memory.lisp (19020B)
---
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 ;;;
27
28 (in-package #:cffi-tests)
29
30 (deftest deref.char
31 (with-foreign-object (p :char)
32 (setf (mem-ref p :char) -127)
33 (mem-ref p :char))
34 -127)
35
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)
41
42 (deftest deref.short
43 (with-foreign-object (p :short)
44 (setf (mem-ref p :short) -32767)
45 (mem-ref p :short))
46 -32767)
47
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)
53
54 (deftest deref.int
55 (with-foreign-object (p :int)
56 (setf (mem-ref p :int) -131072)
57 (mem-ref p :int))
58 -131072)
59
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)
65
66 (deftest deref.long
67 (with-foreign-object (p :long)
68 (setf (mem-ref p :long) -536870911)
69 (mem-ref p :long))
70 -536870911)
71
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)
77
78 #+(and darwin openmcl)
79 (pushnew 'deref.long-long rt::*expected-failures*)
80
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)
86
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)
92
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)
98
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*)
104
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*)
110
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)
116
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*)
122
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*)
128
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 scl long-double)
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)
139
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)
145
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))
151
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)))
157 t)
158
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))
165 0)
166
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)
174
175 (defconstant +two+ 2)
176
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)
182 2)
183
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)
191
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))))
201
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))
207
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))))
219
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))
225
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)
232 1)
233
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)
243
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)
253
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)
262
263 (cffi:defcstruct mem-aref.bare-struct
264 (a :uint8))
265
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))))
275 t)
276
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.
280 ;;;
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))
284
285 (deftest deref.aggregate
286 (with-foreign-object (s 'some-struct)
287 (pointer-eq s (mem-ref s 'some-struct)))
288 t)
289
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))
300
301 ;;; pointer operations
302 (deftest pointer.1
303 (pointer-address (make-pointer 42))
304 42)
305
306 ;;; I suppose this test is not very good. --luis
307 (deftest pointer.2
308 (pointer-address (null-pointer))
309 0)
310
311 (deftest pointer.null
312 (nth-value 0 (ignore-errors (null-pointer-p nil)))
313 nil)
314
315 (deftest foreign-pointer-type.nil
316 (typep nil 'foreign-pointer)
317 nil)
318
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)))
326 0)
327
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)))
333 t)
334
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)))
341 42)
342
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))
351
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))
361
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))
371
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))
380 t))
381 nil)
382
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 ()
386 ()
387 (:actual-type :int)
388 (:simple-parser not-an-int))
389
390 (defmethod translate-to-foreign (value (type not-an-int))
391 (assert (not (integerp value)))
392 0)
393
394 (deftest foreign-alloc.6
395 (let ((ptr (foreign-alloc 'not-an-int :initial-element 'foooo)))
396 (foreign-free ptr)
397 t)
398 t)
399
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))
407 t))
408 nil)
409
410 ;;; The opposite of the above test.
411 (defctype pointer-alias :pointer)
412
413 (deftest foreign-alloc.8
414 (progn
415 (foreign-free (foreign-alloc 'pointer-alias :count 0 :null-terminated-p t))
416 t)
417 t)
418
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)))
426 t)
427
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)))
431 t)
432
433 ;;; Tests for mem-ref with a non-constant type. This is a way to test
434 ;;; the functional interface (without compiler macros).
435
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)
442
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)
449
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)
456
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)
463
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)
470
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)
477
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)
484
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)
491
492 #+(and darwin openmcl)
493 (pushnew 'deref.nonconst.long-long rt::*expected-failures*)
494
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)
501
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)
508
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)
515
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*)
522
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*)
529
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)
536
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*)
543
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*)
550
551 ;;; regression tests: lispworks's %mem-ref and %mem-set compiler
552 ;;; macros were misbehaving.
553
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))))
559
560 (deftest mem-ref.rt.1
561 (mem-ref-rt-1)
562 123 456)
563
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))))
569
570 (deftest mem-ref.rt.2
571 (mem-ref-rt-2)
572 123.0d0 456.0d0)
573
574 (deftest incf-pointer.1
575 (let ((ptr (null-pointer)))
576 (incf-pointer ptr)
577 (pointer-address ptr))
578 1)
579
580 (deftest incf-pointer.2
581 (let ((ptr (null-pointer)))
582 (incf-pointer ptr 42)
583 (pointer-address ptr))
584 42)
585
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)
592
593 (deftest pointerp.2
594 (let ((p (make-pointer #xFEFF)))
595 (values
596 (pointerp p)
597 (typep p 'foreign-pointer)))
598 t t)
599
600 (deftest pointerp.3
601 (pointerp 'not-a-pointer)
602 nil)
603
604 (deftest pointerp.4
605 (pointerp 42)
606 nil)
607
608 (deftest pointerp.5
609 (pointerp 0)
610 nil)
611
612 (deftest pointerp.6
613 (pointerp nil)
614 nil)
615
616 (deftest mem-ref.setf.1
617 (with-foreign-object (p :char)
618 (setf (mem-ref p :char) 42))
619 42)
620
621 (define-foreign-type int+1 ()
622 ()
623 (:actual-type :int)
624 (:simple-parser int+1))
625
626 (defmethod translate-to-foreign (value (type int+1))
627 (1+ value))
628
629 (defmethod translate-from-foreign (value (type int+1))
630 (1+ value))
631
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?
637 44)
638
639 (deftest pointer-eq.non-pointers.1
640 (expecting-error (pointer-eq 1 2))
641 :error)
642
643 (deftest pointer-eq.non-pointers.2
644 (expecting-error (pointer-eq 'a 'b))
645 :error)
646
647 (deftest null-pointer-p.non-pointer.1
648 (expecting-error (null-pointer-p 'not-a-pointer))
649 :error)
650
651 (deftest null-pointer-p.non-pointer.2
652 (expecting-error (null-pointer-p 0))
653 :error)
654
655 (deftest null-pointer-p.non-pointer.3
656 (expecting-error (null-pointer-p nil))
657 :error)