1 ;;;; callback tests with side effects
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; While most of SBCL is derived from the CMU CL system, the test
7 ;;;; files (like this one) were written from scratch after the fork
10 ;;;; This software is in the public domain and is provided with
11 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
12 ;;;; more information.
16 ;;; callbacks only on a few platforms
17 ;;; (actually, all platforms claim to support them now,
18 ;;; and :alien-callbacks is almost everywhere defined.
19 ;;; However mips doesn't seem to correctly implement them,
20 ;;; making the feature indicator somewhat useless)
21 #+(or (not alien-callbacks
) mips
) (invoke-restart 'run-tests
::skip-file
)
23 ;;; simple callback for a function
29 (sb-alien::alien-callback
(function c-string
) #'thunk
))
31 (with-test (:name
(:callback
:c-string
)
32 ;; The whole file is broken, report one test
34 :broken-on
:interpreter
)
35 (assert (equal (with-output-to-string (*standard-output
*)
36 (alien-funcall *thunk
*))
39 ;; WITH-ALIEN is broken when interpreted, e.g.
40 ;; (with-alien ((x int 10)) x), see lp#992362, lp#1731556
41 (when (eq sb-ext
:*evaluator-mode
* :interpret
)
42 (invoke-restart 'run-tests
::skip-file
))
44 ;;; simple callback for a symbol
46 (defun add-two-ints (arg1 arg2
)
49 (defvar *add-two-ints
*
50 (sb-alien::alien-callback
(function int int int
) 'add-two-ints
))
52 (assert (= (alien-funcall *add-two-ints
* 555 444444) 444999))
54 ;;; actually using a callback with foreign code
56 #+win32
(sb-alien:load-shared-object
"ntdll.dll")
58 (define-alien-routine qsort void
62 (compar (function int
(* double
) (* double
))))
64 (define-alien-callable double
*-cmp int
((arg1 (* double
)) (arg2 (* double
)))
65 (let ((a1 (deref arg1
))
71 (let* ((vector (coerce '(0.1d0
0.5d0
0.2d0
1.2d0
1.5d0
2.5d0
0.0d0
0.1d0
0.2d0
0.3d0
)
72 '(vector double-float
)))
73 (sorted (sort (copy-seq vector
) #'<)))
75 (sb-sys:with-pinned-objects
(vector)
76 (qsort (sb-sys:vector-sap vector
)
78 (alien-size double
:bytes
)
79 (alien-callable-function 'double
*-cmp
)))
80 (assert (equalp vector sorted
)))
84 (define-alien-callable redefined-fun int
()
88 '(define-alien-callable redefined-fun int
()
91 (assert (= 42 (alien-funcall (alien-callable-function 'redefined-fun
))))
93 (define-alien-callable return-single float
((x float
))
96 (define-alien-callable return-double double
((x double
))
99 (defconstant spi
(coerce pi
'single-float
))
101 (assert (= spi
(alien-funcall (alien-callable-function 'return-single
) spi
)))
102 (assert (= pi
(alien-funcall (alien-callable-function 'return-double
) pi
)))
104 ;;; redefining and invalidating alien callables
106 (define-alien-callable foo int
()
109 (defvar *old-foo
* (alien-callable-function 'foo
))
111 (multiple-value-bind (p valid
) (sb-alien::alien-callback-p
*old-foo
*)
115 (assert (= 13 (alien-funcall *old-foo
*)))
117 (define-alien-callable foo int
()
120 (multiple-value-bind (p valid
) (sb-alien::alien-callback-p
*old-foo
*)
122 (assert (not valid
)))
124 (multiple-value-bind (res err
)
125 (ignore-errors (alien-funcall *old-foo
*))
126 (assert (and (not res
) (typep err
'error
))))
128 (assert (= 26 (alien-funcall (alien-callable-function 'foo
))))
130 ;;; callbacks with void return values
132 (with-test (:name
:void-return
)
133 (sb-alien::alien-lambda void
()
136 ;;; tests for integer-width problems in callback result handling
138 (defvar *add-two-ints
*
139 (sb-alien::alien-callback
(function int int int
) #'+))
140 (defvar *add-two-shorts
*
141 (sb-alien::alien-callback
(function short short short
) #'+))
143 ;;; The original test cases here were what are now (:int-result
144 ;;; :sign-extension) and (:int-result :underflow-detection), the latter
145 ;;; of which would fail on 64-bit platforms. Upon further investigation,
146 ;;; it turned out that the same tests with a SHORT return type instead of
147 ;;; an INT return type would also fail on 32-bit platforms.
149 (with-test (:name
(:short-result
:sign-extension
))
150 (assert (= (alien-funcall *add-two-shorts
* #x-8000
1) -
32767)))
152 (with-test (:name
(:short-result
:underflow-detection
))
153 (assert-error (alien-funcall *add-two-shorts
* #x-8000 -
1)))
155 (with-test (:name
(:int-result
:sign-extension
))
156 (assert (= (alien-funcall *add-two-ints
* #x-80000000
1) -
2147483647)))
158 (with-test (:name
(:int-result
:underflow-detection
))
159 (assert-error (alien-funcall *add-two-ints
* #x-80000000 -
1)))
161 ;;; tests for handling 64-bit arguments - this was causing problems on
162 ;;; ppc - CLH, 2005-12-01
164 (defvar *add-two-long-longs
*
165 (sb-alien::alien-callback
166 (function (integer 64) (integer 64) (integer 64)) 'add-two-ints
))
167 (with-test (:name
:long-long-callback-arg
)
168 (assert (= (alien-funcall *add-two-long-longs
*
173 (defvar *add-two-unsigned-long-longs
*
174 (sb-alien::alien-callback
175 (function (unsigned 64) (unsigned 64) (unsigned 64))
177 (with-test (:name
:unsigned-long-long-callback-arg
)
178 (assert (= (alien-funcall *add-two-unsigned-long-longs
*
183 ;;; test for callbacks of various arities
186 (defmacro alien-apply-form
(f args
)
188 `(alien-funcall ,,f
,@a
)))
190 (defmacro alien-apply
(f &rest args
)
191 `(eval (alien-apply-form ,f
,@args
)))
193 (defun iota (x) (if (equalp x
1) (list x
) (cons x
(iota (1- x
)))))
195 (defparameter *type-abbreviations
*
196 '((sb-alien:char .
"c")
197 (sb-alien:unsigned-char .
"uc")
198 (sb-alien:short .
"h")
199 (sb-alien:unsigned-short .
"uh")
201 (sb-alien:unsigned-int .
"ui")
202 ((sb-alien:integer
64) .
"l")
203 ((sb-alien:unsigned
64) .
"ul")
204 (sb-alien:long-long .
"ll")
205 (sb-alien:unsigned-long-long .
"ull")
206 (sb-alien:float .
"f")
207 (sb-alien:double .
"d")))
209 (defun parse-callback-arg-spec (spec)
210 (let ((l (coerce spec
'list
)))
211 (loop for g in l by
#'cddr
212 collect
(car (rassoc (string-downcase g
) *type-abbreviations
* :test
#'equal
)))))
214 (defmacro define-callback-adder
(&rest types
)
215 (let ((fname (format nil
"*add-~{~A~^-~}*"
218 (cdr (assoc x
*type-abbreviations
*)))
220 #'(lambda (y) (find-symbol (string-upcase y
) 'sb-alien
))
223 (defparameter ,(intern
224 (string-upcase fname
))
225 (sb-alien::alien-callback
(function ,@types
) '+)))))
227 (with-test (:name
:define-2-int-callback
)
228 (define-callback-adder int int int
))
229 (with-test (:name
:call-2-int-callback
)
230 (assert (= (alien-apply *add-i-i
* (iota 2)) 3)))
232 (with-test (:name
:define-3-int-callback
)
233 (define-callback-adder int int int int
))
234 (with-test (:name
:call-3-int-callback
)
235 (assert (= (alien-apply *add-i-i-i
* (iota 3)) 6)))
237 (with-test (:name
:define-4-int-callback
)
238 (define-callback-adder int int int int int
))
239 (with-test (:name
:call-4-int-callback
)
240 (assert (= (alien-apply *add-i-i-i-i
* (iota 4)) 10)))
242 (with-test (:name
:define-5-int-callback
)
243 (define-callback-adder int int int int int int
))
244 (with-test (:name
:call-5-int-callback
)
245 (assert (= (alien-apply *add-i-i-i-i-i
* (iota 5)) 15)))
247 (with-test (:name
:define-6-int-callback
)
248 (define-callback-adder int int int int int int int
))
249 (with-test (:name
:call-6-int-callback
)
250 (assert (= (alien-apply *add-i-i-i-i-i-i
* (iota 6)) 21)))
252 (with-test (:name
:define-7-int-callback
)
253 (define-callback-adder int int int int int int int int
))
254 (with-test (:name
:call-7-int-callback
)
255 (assert (= (alien-apply *add-i-i-i-i-i-i-i
* (iota 7)) 28)))
257 (with-test (:name
:define-8-int-callback
)
258 (define-callback-adder int int int int int int int int int
))
259 (with-test (:name
:call-8-int-callback
)
260 (assert (= (alien-apply *add-i-i-i-i-i-i-i-i
* (iota 8)) 36)))
262 (with-test (:name
:define-9-int-callback
)
263 (define-callback-adder int int int int int int int int int int
))
264 (with-test (:name
:call-9-int-callback
)
265 (assert (= (alien-apply *add-i-i-i-i-i-i-i-i-i
* (iota 9)) 45)))
267 (with-test (:name
:define-10-int-callback
)
268 (define-callback-adder int int int int int int int int int int int
))
269 (with-test (:name
:call-10-int-callback
)
270 (assert (= (alien-apply *add-i-i-i-i-i-i-i-i-i-i
* (iota 10)) 55)))
272 (with-test (:name
:define-11-int-callback
)
273 (define-callback-adder int int int int int int int int int int int int
))
274 (with-test (:name
:call-11-int-callback
)
275 (assert (= (alien-apply *add-i-i-i-i-i-i-i-i-i-i-i
* (iota 11)) 66)))
277 (with-test (:name
:define-12-int-callback
)
278 (define-callback-adder int int int int int int int int int int int int int
))
279 (with-test (:name
:call-12-int-callback
)
280 (assert (= (alien-apply *add-i-i-i-i-i-i-i-i-i-i-i-i
* (iota 12)) 78)))
282 (with-test (:name
:define-2-float-callback
)
283 (define-callback-adder float float float
))
284 (with-test (:name
:call-2-float-callback
)
285 (assert (= (alien-apply *add-f-f
* (iota 2.0s0
)) 3.0s0
)))
287 (with-test (:name
:define-3-float-callback
)
288 (define-callback-adder float float float float
))
289 (with-test (:name
:call-3-float-callback
)
290 (assert (= (alien-apply *add-f-f-f
* (iota 3.0s0
)) 6.0s0
)))
292 (with-test (:name
:define-4-float-callback
)
293 (define-callback-adder float float float float float
))
294 (with-test (:name
:call-4-float-callback
)
295 (assert (= (alien-apply *add-f-f-f-f
* (iota 4.0s0
)) 10.0s0
)))
297 (with-test (:name
:define-5-float-callback
)
298 (define-callback-adder float float float float float float
))
299 (with-test (:name
:call-5-float-callback
)
300 (assert (= (alien-apply *add-f-f-f-f-f
* (iota 5.0s0
)) 15.0s0
)))
302 (with-test (:name
:define-6-float-callback
)
303 (define-callback-adder float float float float float float float
))
304 (with-test (:name
:call-6-float-callback
)
305 (assert (= (alien-apply *add-f-f-f-f-f-f
* (iota 6.0s0
)) 21.0s0
)))
307 (with-test (:name
:define-7-float-callback
)
308 (define-callback-adder float float float float float float float float
))
309 (with-test (:name
:call-7-float-callback
)
310 (assert (= (alien-apply *add-f-f-f-f-f-f-f
* (iota 7.0s0
)) 28.0s0
)))
312 (with-test (:name
:define-8-float-callback
)
313 (define-callback-adder float float float float float float float float float
))
314 (with-test (:name
:call-8-float-callback
)
315 (assert (= (alien-apply *add-f-f-f-f-f-f-f-f
* (iota 8.0s0
)) 36.0s0
)))
317 (with-test (:name
:define-9-float-callback
)
318 (define-callback-adder float float float float float float float float float float
))
319 (with-test (:name
:call-9-float-callback
)
320 (assert (= (alien-apply *add-f-f-f-f-f-f-f-f-f
* (iota 9.0s0
)) 45.0s0
)))
322 (with-test (:name
:define-10-float-callback
)
323 (define-callback-adder float float float float float float float float float float float
))
324 (with-test (:name
:call-10-float-callback
)
325 (assert (= (alien-apply *add-f-f-f-f-f-f-f-f-f-f
* (iota 10.0s0
)) 55.0s0
)))
327 (with-test (:name
:define-11-float-callback
)
328 (define-callback-adder float float float float float float float float float float float float
))
329 (with-test (:name
:call-11-float-callback
)
330 (assert (= (alien-apply *add-f-f-f-f-f-f-f-f-f-f-f
* (iota 11.0s0
)) 66.0s0
)))
332 (with-test (:name
:define-12-float-callback
)
333 (define-callback-adder float float float float float float float float float float float float float
))
334 (with-test (:name
:call-12-float-callback
)
335 (assert (= (alien-apply *add-f-f-f-f-f-f-f-f-f-f-f-f
* (iota 12.0s0
)) 78.0s0
)))
337 (with-test (:name
:define-2-double-callback
)
338 (define-callback-adder double double double
))
339 (with-test (:name
:call-2-double-callback
)
340 (assert (= (alien-apply *add-d-d
* (iota 2.0d0
)) 3.0d0
)))
342 (with-test (:name
:define-3-double-callback
)
343 (define-callback-adder double double double double
))
344 (with-test (:name
:call-3-double-callback
)
345 (assert (= (alien-apply *add-d-d-d
* (iota 3.0d0
)) 6.0d0
)))
347 (with-test (:name
:define-4-double-callback
)
348 (define-callback-adder double double double double double
))
349 (with-test (:name
:call-4-double-callback
)
350 (assert (= (alien-apply *add-d-d-d-d
* (iota 4.0d0
)) 10.0d0
)))
352 (with-test (:name
:define-5-double-callback
)
353 (define-callback-adder double double double double double double
))
354 (with-test (:name
:call-5-double-callback
)
355 (assert (= (alien-apply *add-d-d-d-d-d
* (iota 5.0d0
)) 15.0d0
)))
357 (with-test (:name
:define-6-double-callback
)
358 (define-callback-adder double double double double double double double
))
359 (with-test (:name
:call-6-double-callback
)
360 (assert (= (alien-apply *add-d-d-d-d-d-d
* (iota 6.0d0
)) 21.0d0
)))
362 (with-test (:name
:define-7-double-callback
)
363 (define-callback-adder double double double double double double double double
))
364 (with-test (:name
:call-7-double-callback
)
365 (assert (= (alien-apply *add-d-d-d-d-d-d-d
* (iota 7.0d0
)) 28.0d0
)))
367 (with-test (:name
:define-8-double-callback
)
368 (define-callback-adder double double double double double double double double double
))
369 (with-test (:name
:call-8-double-callback
)
370 (assert (= (alien-apply *add-d-d-d-d-d-d-d-d
* (iota 8.0d0
)) 36.0d0
)))
372 (with-test (:name
:define-9-double-callback
)
373 (define-callback-adder double double double double double double double double double double
))
374 (with-test (:name
:call-9-double-callback
)
375 (assert (= (alien-apply *add-d-d-d-d-d-d-d-d-d
* (iota 9.0d0
)) 45.0d0
)))
377 (with-test (:name
:define-10-double-callback
)
378 (define-callback-adder double double double double double double double double double double double
))
379 (with-test (:name
:call-10-double-callback
)
380 (assert (= (alien-apply *add-d-d-d-d-d-d-d-d-d-d
* (iota 10.0d0
)) 55.0d0
)))
382 (with-test (:name
:define-11-double-callback
)
383 (define-callback-adder double double double double double double double double double double double double
))
384 (with-test (:name
:call-11-double-callback
)
385 (assert (= (alien-apply *add-d-d-d-d-d-d-d-d-d-d-d
* (iota 11.0d0
)) 66.0d0
)))
387 (with-test (:name
:define-12-double-callback
)
388 (define-callback-adder double double double double double double double double double double double double double
))
389 (with-test (:name
:call-12-double-callback
)
390 (assert (= (alien-apply *add-d-d-d-d-d-d-d-d-d-d-d-d
* (iota 12.0d0
)) 78.0d0
)))
392 (with-test (:name
:define-int-float-callback
)
393 (define-callback-adder float int float
))
394 (with-test (:name
:call-int-float-callback
)
395 (assert (= (alien-funcall *add-i-f
* 1 2.0s0
) 3.0s0
)))
397 (with-test (:name
:define-float-int-callback
)
398 (define-callback-adder float float int
))
399 (with-test (:name
:call-float-int-callback
)
400 (assert (= (alien-funcall *add-f-i
* 2.0s0
1) 3.0s0
)))
402 (with-test (:name
:define-int-double-callback
)
403 (define-callback-adder double int double
))
404 (with-test (:name
:call-int-double-callback
)
405 (assert (= (alien-funcall *add-i-d
* 1 2.0d0
) 3.0d0
)))
407 (with-test (:name
:define-double-int-callback
)
408 (define-callback-adder double double int
))
409 (with-test (:name
:call-double-int-callback
)
410 (assert (= (alien-funcall *add-d-i
* 2.0d0
1) 3.0d0
)))
412 (with-test (:name
:define-double-float-callback
)
413 (define-callback-adder double double float
))
414 (with-test (:name
:call-double-float-callback
)
415 (assert (= (alien-funcall *add-d-f
* 2.0d0
1.0s0
) 3.0d0
)))
417 (with-test (:name
:define-float-double-callback
)
418 (define-callback-adder double float double
))
419 (with-test (:name
:call-float-double-callback
)
420 (assert (= (alien-funcall *add-f-d
* 1.0s0
2.0d0
) 3.0d0
)))
422 (with-test (:name
:define-double-float-int-callback
)
423 (define-callback-adder double double float int
))
424 (with-test (:name
:call-double-float-int-callback
)
425 (assert (= (alien-funcall *add-d-f-i
* 2.0d0
1.0s0
1) 4.0d0
)))
427 (with-test (:name
:define-float-float-double-callback
)
428 (define-callback-adder double float float double
))
429 (with-test (:name
:call-float-float-double-callback
)
430 (assert (= (alien-funcall *add-f-f-d
* 2.0s0
1.0s0
3.0d0
) 6.0d0
)))
432 (with-test (:name
:define-int-float-double-callback
)
433 (define-callback-adder double int float double
))
434 (with-test (:name
:call-int-float-double-callback
)
435 (assert (= (alien-funcall *add-i-f-d
* 1 1.0s0
2.0d0
) 4.0d0
)))
437 (with-test (:name
:define-int-ulonglong-callback
)
438 (define-callback-adder unsigned-long-long int unsigned-long-long
))
439 (with-test (:name
:call-int-ulonglong-callback
)
440 (assert (= (alien-funcall *add-i-ull
* 1 #x200000003
) #x200000004
)))
442 (with-test (:name
:define-int-int-int-int-int-ulonglong-callback
)
443 (define-callback-adder unsigned-long-long int int int int int unsigned-long-long
))
444 (with-test (:name
:call-int-int-int-int-int-ulonglong-callback
)
445 (assert (= (alien-funcall *add-i-i-i-i-i-ull
* 0 0 0 0 1 #x200000003
) #x200000004
)))