ffi/unsafe: defend against some finalization bugs
Turn use of a finalized ffi callout into a reported error, instead of a crash. Clarify the existence of the finalizer in the docs. Fix error logging of the finalizer thread. Merge to v5.3.1
This commit is contained in:
parent
d77803b687
commit
9708a01a0a
|
@ -1702,6 +1702,7 @@
|
||||||
(cweh
|
(cweh
|
||||||
(lambda (exn)
|
(lambda (exn)
|
||||||
(log-message logger
|
(log-message logger
|
||||||
|
'error
|
||||||
(if (exn? exn)
|
(if (exn? exn)
|
||||||
(exn-message exn)
|
(exn-message exn)
|
||||||
(format "~s" exn))
|
(format "~s" exn))
|
||||||
|
|
|
@ -485,6 +485,11 @@ For @tech{callouts} to foreign functions with the generated type:
|
||||||
that values managed by the Racket garbage collector might be
|
that values managed by the Racket garbage collector might be
|
||||||
moved in memory by the garbage collector.}
|
moved in memory by the garbage collector.}
|
||||||
|
|
||||||
|
@item{A @tech{callout} object is finalized internally. Beware
|
||||||
|
of trying to use a @tech{callout} object that is reachable
|
||||||
|
only from a finalized object, since the two objects
|
||||||
|
might be finalized in either order.}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
For @tech{callbacks} to Racket functions with the generated type:
|
For @tech{callbacks} to Racket functions with the generated type:
|
||||||
|
|
32
collects/tests/racket/ffi-call-final.rkt
Normal file
32
collects/tests/racket/ffi-call-final.rkt
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
;; Check for a good effort at error reporting on an attempt to
|
||||||
|
;; use a foreign function that is finalized already.
|
||||||
|
|
||||||
|
(define src
|
||||||
|
'(module m racket/base
|
||||||
|
(require ffi/unsafe)
|
||||||
|
(for ([i 10])
|
||||||
|
(for ([i 10])
|
||||||
|
(define m (get-ffi-obj 'fabs #f (_fun _double -> _double)))
|
||||||
|
;; Since `m' is accessible only via the finalized value, it
|
||||||
|
;; can be finalized before `(list m)':
|
||||||
|
(register-finalizer (list m) (lambda (p) ((car p) 10.0))))
|
||||||
|
(collect-garbage))))
|
||||||
|
|
||||||
|
(define l (make-logger))
|
||||||
|
(define r (make-log-receiver l 'error))
|
||||||
|
|
||||||
|
(parameterize ([current-namespace (make-base-namespace)]
|
||||||
|
[current-logger l])
|
||||||
|
(eval src)
|
||||||
|
(namespace-require ''m))
|
||||||
|
|
||||||
|
;; Print logged errors, of which there are likely to be
|
||||||
|
;; some (although it's not guaranteed) if the finalizer
|
||||||
|
;; thread is logging correctly:
|
||||||
|
(let loop ()
|
||||||
|
(define m (sync/timeout 0 r))
|
||||||
|
(when m
|
||||||
|
(printf "~s\n" m)
|
||||||
|
(loop)))
|
|
@ -3055,7 +3055,7 @@ Scheme_Object *ffi_do_call(void *data, int argc, Scheme_Object *argv[])
|
||||||
#ifdef MZ_USE_PLACES
|
#ifdef MZ_USE_PLACES
|
||||||
int orig_place = SCHEME_TRUEP(SCHEME_VEC_ELS(data)[7]);
|
int orig_place = SCHEME_TRUEP(SCHEME_VEC_ELS(data)[7]);
|
||||||
#endif
|
#endif
|
||||||
int nargs = cif->nargs;
|
int nargs /* = cif->nargs, after checking cif */;
|
||||||
/* When the foreign function is called, we need an array (ivals) of nargs
|
/* When the foreign function is called, we need an array (ivals) of nargs
|
||||||
* ForeignAny objects to store the actual C values that are created, and we
|
* ForeignAny objects to store the actual C values that are created, and we
|
||||||
* need another array (avalues) for the pointers to these values (this is
|
* need another array (avalues) for the pointers to these values (this is
|
||||||
|
@ -3082,6 +3082,13 @@ Scheme_Object *ffi_do_call(void *data, int argc, Scheme_Object *argv[])
|
||||||
if (orig_place && (scheme_current_place_id == 0))
|
if (orig_place && (scheme_current_place_id == 0))
|
||||||
orig_place = 0;
|
orig_place = 0;
|
||||||
#endif
|
#endif
|
||||||
|
if (!cif) {
|
||||||
|
scheme_signal_error("ffi-call: foreign-function reference was already finalized%s%s",
|
||||||
|
name ? "\n name: " : "",
|
||||||
|
name ? name : "");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
nargs = cif->nargs;
|
||||||
if ((nargs <= MAX_QUICK_ARGS)) {
|
if ((nargs <= MAX_QUICK_ARGS)) {
|
||||||
ivals = stack_ivals;
|
ivals = stack_ivals;
|
||||||
avalues = stack_avalues;
|
avalues = stack_avalues;
|
||||||
|
@ -3151,8 +3158,9 @@ Scheme_Object *ffi_do_call(void *data, int argc, Scheme_Object *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see below */
|
/* see below */
|
||||||
void free_fficall_data(void *ignored, void *p)
|
void free_fficall_data(void *data, void *p)
|
||||||
{
|
{
|
||||||
|
SCHEME_VEC_ELS(data)[4] = NULL;
|
||||||
free(((ffi_cif*)p)->arg_types);
|
free(((ffi_cif*)p)->arg_types);
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2411,7 +2411,7 @@ Scheme_Object *ffi_do_call(void *data, int argc, Scheme_Object *argv[])
|
||||||
#ifdef MZ_USE_PLACES
|
#ifdef MZ_USE_PLACES
|
||||||
int orig_place = SCHEME_TRUEP(SCHEME_VEC_ELS(data)[7]);
|
int orig_place = SCHEME_TRUEP(SCHEME_VEC_ELS(data)[7]);
|
||||||
#endif
|
#endif
|
||||||
int nargs = cif->nargs;
|
int nargs /* = cif->nargs, after checking cif */;
|
||||||
/* When the foreign function is called, we need an array (ivals) of nargs
|
/* When the foreign function is called, we need an array (ivals) of nargs
|
||||||
* ForeignAny objects to store the actual C values that are created, and we
|
* ForeignAny objects to store the actual C values that are created, and we
|
||||||
* need another array (avalues) for the pointers to these values (this is
|
* need another array (avalues) for the pointers to these values (this is
|
||||||
|
@ -2438,6 +2438,13 @@ Scheme_Object *ffi_do_call(void *data, int argc, Scheme_Object *argv[])
|
||||||
if (orig_place && (scheme_current_place_id == 0))
|
if (orig_place && (scheme_current_place_id == 0))
|
||||||
orig_place = 0;
|
orig_place = 0;
|
||||||
#endif
|
#endif
|
||||||
|
if (!cif) {
|
||||||
|
scheme_signal_error("ffi-call: foreign-function reference was already finalized%s%s",
|
||||||
|
name ? "\n name: " : "",
|
||||||
|
name ? name : "");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
nargs = cif->nargs;
|
||||||
if ((nargs <= MAX_QUICK_ARGS)) {
|
if ((nargs <= MAX_QUICK_ARGS)) {
|
||||||
ivals = stack_ivals;
|
ivals = stack_ivals;
|
||||||
avalues = stack_avalues;
|
avalues = stack_avalues;
|
||||||
|
@ -2507,8 +2514,9 @@ Scheme_Object *ffi_do_call(void *data, int argc, Scheme_Object *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see below */
|
/* see below */
|
||||||
void free_fficall_data(void *ignored, void *p)
|
void free_fficall_data(void *data, void *p)
|
||||||
{
|
{
|
||||||
|
SCHEME_VEC_ELS(data)[4] = NULL;
|
||||||
free(((ffi_cif*)p)->arg_types);
|
free(((ffi_cif*)p)->arg_types);
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user