#lang scribble/doc @(require "mz.rkt" (for-label racket/unsafe/ops racket/flonum racket/fixnum racket/extflonum (only-in ffi/vector f64vector? f64vector-ref f64vector-set! u16vector? u16vector-ref u16vector-set! s16vector? s16vector-ref s16vector-set!))) @title[#:tag "unsafe"]{Unsafe Operations} @defmodule[racket/unsafe/ops] All functions and forms provided by @racketmodname[racket/base] and @racketmodname[racket] check their arguments to ensure that the arguments conform to contracts and other constraints. For example, @racket[vector-ref] checks its arguments to ensure that the first argument is a vector, that the second argument is an exact integer, and that the second argument is between @racket[0] and one less than the vector's length, inclusive. Functions provided by @racketmodname[racket/unsafe/ops] are @deftech{unsafe}. They have certain constraints, but the constraints are not checked, which allows the system to generate and execute faster code. If arguments violate an unsafe function's constraints, the function's behavior and result is unpredictable, and the entire system can crash or become corrupted. All of the exported bindings of @racketmodname[racket/unsafe/ops] are protected in the sense of @racket[protect-out], so access to unsafe operations can be prevented by adjusting the code inspector (see @secref["modprotect"]). @section{Unsafe Numeric Operations} @deftogether[( @defproc[(unsafe-fx+ [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fx- [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fx* [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fxquotient [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fxremainder [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fxmodulo [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fxabs [a fixnum?]) fixnum?] )]{ For @tech{fixnums}: Like @racket[+], @racket[-], @racket[*], @racket[quotient], @racket[remainder], @racket[modulo], and @racket[abs], but constrained to consume @tech{fixnums} and produce a @tech{fixnum} result. The mathematical operation on @racket[a] and @racket[b] must be representable as a @tech{fixnum}. In the case of @racket[unsafe-fxquotient], @racket[unsafe-fxremainder], and @racket[unsafe-fxmodulo], @racket[b] must not be @racket[0].} @deftogether[( @defproc[(unsafe-fxand [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fxior [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fxxor [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fxnot [a fixnum?]) fixnum?] @defproc[(unsafe-fxlshift [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fxrshift [a fixnum?] [b fixnum?]) fixnum?] )]{ For @tech{fixnums}: Like @racket[bitwise-and], @racket[bitwise-ior], @racket[bitwise-xor], @racket[bitwise-not], and @racket[arithmetic-shift], but constrained to consume @tech{fixnums}; the result is always a @tech{fixnum}. The @racket[unsafe-fxlshift] and @racket[unsafe-fxrshift] operations correspond to @racket[arithmetic-shift], but require non-negative arguments; @racket[unsafe-fxlshift] is a positive (i.e., left) shift, and @racket[unsafe-fxrshift] is a negative (i.e., right) shift, where the number of bits to shift must be less than the number of bits used to represent a @tech{fixnum}. In the case of @racket[unsafe-fxlshift], bits in the result beyond the number of bits used to represent a @tech{fixnum} are effectively replaced with a copy of the high bit.} @deftogether[( @defproc[(unsafe-fx= [a fixnum?] [b fixnum?]) boolean?] @defproc[(unsafe-fx< [a fixnum?] [b fixnum?]) boolean?] @defproc[(unsafe-fx> [a fixnum?] [b fixnum?]) boolean?] @defproc[(unsafe-fx<= [a fixnum?] [b fixnum?]) boolean?] @defproc[(unsafe-fx>= [a fixnum?] [b fixnum?]) boolean?] @defproc[(unsafe-fxmin [a fixnum?] [b fixnum?]) fixnum?] @defproc[(unsafe-fxmax [a fixnum?] [b fixnum?]) fixnum?] )]{ For @tech{fixnums}: Like @racket[=], @racket[<], @racket[>], @racket[<=], @racket[>=], @racket[min], and @racket[max], but constrained to consume @tech{fixnums}.} @deftogether[( @defproc[(unsafe-fl+ [a flonum?] [b flonum?]) flonum?] @defproc[(unsafe-fl- [a flonum?] [b flonum?]) flonum?] @defproc[(unsafe-fl* [a flonum?] [b flonum?]) flonum?] @defproc[(unsafe-fl/ [a flonum?] [b flonum?]) flonum?] @defproc[(unsafe-flabs [a flonum?]) flonum?] )]{ For @tech{flonums}: Unchecked versions of @racket[fl+], @racket[fl-], @racket[fl*], @racket[fl/], and @racket[flabs].} @deftogether[( @defproc[(unsafe-fl= [a flonum?] [b flonum?]) boolean?] @defproc[(unsafe-fl< [a flonum?] [b flonum?]) boolean?] @defproc[(unsafe-fl> [a flonum?] [b flonum?]) boolean?] @defproc[(unsafe-fl<= [a flonum?] [b flonum?]) boolean?] @defproc[(unsafe-fl>= [a flonum?] [b flonum?]) boolean?] @defproc[(unsafe-flmin [a flonum?] [b flonum?]) flonum?] @defproc[(unsafe-flmax [a flonum?] [b flonum?]) flonum?] )]{ For @tech{flonums}: Unchecked versions of @racket[fl=], @racket[fl<], @racket[fl>], @racket[fl<=], @racket[fl>=], @racket[flmin], and @racket[flmax].} @deftogether[( @defproc[(unsafe-flround [a flonum?]) flonum?] @defproc[(unsafe-flfloor [a flonum?]) flonum?] @defproc[(unsafe-flceiling [a flonum?]) flonum?] @defproc[(unsafe-fltruncate [a flonum?]) flonum?] )]{ For @tech{flonums}: Unchecked (potentially) versions of @racket[flround], @racket[flfloor], @racket[flceiling], and @racket[fltruncate]. Currently, these bindings are simply aliases for the corresponding safe bindings.} @deftogether[( @defproc[(unsafe-flsin [a flonum?]) flonum?] @defproc[(unsafe-flcos [a flonum?]) flonum?] @defproc[(unsafe-fltan [a flonum?]) flonum?] @defproc[(unsafe-flasin [a flonum?]) flonum?] @defproc[(unsafe-flacos [a flonum?]) flonum?] @defproc[(unsafe-flatan [a flonum?]) flonum?] @defproc[(unsafe-fllog [a flonum?]) flonum?] @defproc[(unsafe-flexp [a flonum?]) flonum?] @defproc[(unsafe-flsqrt [a flonum?]) flonum?] @defproc[(unsafe-flexpt [a flonum?] [b flonum?]) flonum?] )]{ For @tech{flonums}: Unchecked (potentially) versions of @racket[flsin], @racket[flcos], @racket[fltan], @racket[flasin], @racket[flacos], @racket[flatan], @racket[fllog], @racket[flexp], @racket[flsqrt], and @racket[flexpt]. Currently, some of these bindings are simply aliases for the corresponding safe bindings.} @deftogether[( @defproc[(unsafe-make-flrectangular [a flonum?] [b flonum?]) (and/c complex? (lambda (c) (flonum? (real-part c))) (lambda (c) (flonum? (imag-part c))))] @defproc[(unsafe-flreal-part [a (and/c complex? (lambda (c) (flonum? (real-part c))) (lambda (c) (flonum? (imag-part c))))]) flonum?] @defproc[(unsafe-flimag-part [a (and/c complex? (lambda (c) (flonum? (real-part c))) (lambda (c) (flonum? (imag-part c))))]) flonum?] )]{ For @tech{flonums}: Unchecked versions of @racket[make-flrectangular], @racket[flreal-part], and @racket[flimag-part].} @deftogether[( @defproc[(unsafe-fx->fl [a fixnum?]) flonum?] @defproc[(unsafe-fl->fx [a flonum?]) fixnum?] )]{ Unchecked conversion of a fixnum to an integer flonum and vice versa. These are similar to the safe bindings @racket[->fl] and @racket[fl->exact-integer], but further constrained to consume or produce a fixnum. } @defproc[(unsafe-flrandom [rand-gen pseudo-random-generator?]) (and flonum? (>/c 0) (integer ch) 255)))] @defproc[(unsafe-string-set! [str (and/c string? (not/c immutable?))] [k fixnum?] [ch char?]) void?] )]{ Unsafe versions of @racket[string-length], @racket[string-ref], and @racket[string-set!]. The @racket[unsafe-string-ref] procedure can be used only when the result will be a Latin-1 character. A string's size can never be larger than a @tech{fixnum} (so even @racket[string-length] always returns a fixnum).} @deftogether[( @defproc[(unsafe-bytes-length [bstr bytes?]) fixnum?] @defproc[(unsafe-bytes-ref [bstr bytes?] [k fixnum?]) byte?] @defproc[(unsafe-bytes-set! [bstr (and/c bytes? (not/c immutable?))] [k fixnum?] [b byte?]) void?] )]{ Unsafe versions of @racket[bytes-length], @racket[bytes-ref], and @racket[bytes-set!]. A bytes's size can never be larger than a @tech{fixnum} (so even @racket[bytes-length] always returns a fixnum).} @deftogether[( @defproc[(unsafe-fxvector-length [v fxvector?]) fixnum?] @defproc[(unsafe-fxvector-ref [v fxvector?] [k fixnum?]) fixnum?] @defproc[(unsafe-fxvector-set! [v fxvector?] [k fixnum?] [x fixnum?]) void?] )]{ Unsafe versions of @racket[fxvector-length], @racket[fxvector-ref], and @racket[fxvector-set!]. A @tech{fxvector}'s size can never be larger than a @tech{fixnum} (so even @racket[fxvector-length] always returns a fixnum).} @deftogether[( @defproc[(unsafe-flvector-length [v flvector?]) fixnum?] @defproc[(unsafe-flvector-ref [v flvector?] [k fixnum?]) flonum?] @defproc[(unsafe-flvector-set! [v flvector?] [k fixnum?] [x flonum?]) void?] )]{ Unsafe versions of @racket[flvector-length], @racket[flvector-ref], and @racket[flvector-set!]. A @tech{flvector}'s size can never be larger than a @tech{fixnum} (so even @racket[flvector-length] always returns a fixnum).} @deftogether[( @defproc[(unsafe-f64vector-ref [vec f64vector?] [k fixnum?]) flonum?] @defproc[(unsafe-f64vector-set! [vec f64vector?] [k fixnum?] [n flonum?]) void?] )]{ Unsafe versions of @racket[f64vector-ref] and @racket[f64vector-set!].} @deftogether[( @defproc[(unsafe-s16vector-ref [vec s16vector?] [k fixnum?]) (integer-in -32768 32767)] @defproc[(unsafe-s16vector-set! [vec s16vector?] [k fixnum?] [n (integer-in -32768 32767)]) void?] )]{ Unsafe versions of @racket[s16vector-ref] and @racket[s16vector-set!].} @deftogether[( @defproc[(unsafe-u16vector-ref [vec u16vector?] [k fixnum?]) (integer-in 0 65535)] @defproc[(unsafe-u16vector-set! [vec u16vector?] [k fixnum?] [n (integer-in 0 65535)]) void?] )]{ Unsafe versions of @racket[u16vector-ref] and @racket[u16vector-set!].} @deftogether[( @defproc[(unsafe-struct-ref [v any/c] [k fixnum?]) any/c] @defproc[(unsafe-struct-set! [v any/c] [k fixnum?] [val any/c]) void?] @defproc[(unsafe-struct*-ref [v (not/c impersonator?)] [k fixnum?]) any/c] @defproc[(unsafe-struct*-set! [v (not/c impersonator?)] [k fixnum?] [val any/c]) void?] )]{ Unsafe field access and update for an instance of a structure type, where the @schemeidfont{struct*} variants can be faster but do not work on @tech{impersonators}. The index @racket[k] must be between @racket[0] (inclusive) and the number of fields in the structure (exclusive). In the case of @racket[unsafe-struct-set!], the field must be mutable.} @deftogether[( @defproc[(unsafe-mutable-hash-iterate-first [h (and/c hash? (not/c immutable?) (not/c hash-weak?))]) (or/c #f any/c)] @defproc[(unsafe-mutable-hash-iterate-next [h (and/c hash? (not/c immutable?) (not/c hash-weak?))] [i any/c]) (or/c #f any/c)] @defproc[(unsafe-mutable-hash-iterate-key [h (and/c hash? (not/c immutable?) (not/c hash-weak?))] [i any/c]) any/c] @defproc[(unsafe-mutable-hash-iterate-value [h (and/c hash? (not/c immutable?) (not/c hash-weak?))] [i any/c]) any/c] @defproc[(unsafe-mutable-hash-iterate-key+value [h (and/c hash? (not/c immutable?) (not/c hash-weak?))] [i any/c]) (values any/c any/c)] @defproc[(unsafe-mutable-hash-iterate-pair [h (and/c hash? (not/c immutable?) (not/c hash-weak?))] [i any/c]) pair?] @defproc[(unsafe-immutable-hash-iterate-first [h (and/c hash? immutable?)]) (or/c #f any/c)] @defproc[(unsafe-immutable-hash-iterate-next [h (and/c hash? immutable?)] [i any/c]) (or/c #f any/c)] @defproc[(unsafe-immutable-hash-iterate-key [h (and/c hash? immutable?)] [i any/c]) any/c] @defproc[(unsafe-immutable-hash-iterate-value [h (and/c hash? immutable?)] [i any/c]) any/c] @defproc[(unsafe-immutable-hash-iterate-key+value [h (and/c hash? immutable?)] [i any/c]) (values any/c any/c)] @defproc[(unsafe-immutable-hash-iterate-pair [h (and/c hash? immutable?)] [i any/c]) pair?] @defproc[(unsafe-weak-hash-iterate-first [h (and/c hash? hash-weak?)]) (or/c #f any/c)] @defproc[(unsafe-weak-hash-iterate-next [h (and/c hash? hash-weak?)] [i any/c]) (or/c #f any/c)] @defproc[(unsafe-weak-hash-iterate-key [h (and/c hash? hash-weak?)] [i any/c]) any/c] @defproc[(unsafe-weak-hash-iterate-value [h (and/c hash? hash-weak?)] [i any/c]) any/c] @defproc[(unsafe-weak-hash-iterate-key+value [h (and/c hash? hash-weak?)] [i any/c]) (values any/c any/c)] @defproc[(unsafe-weak-hash-iterate-pair [h (and/c hash? hash-weak?)] [i any/c]) pair?] )]{ Unsafe versions of @racket[hash-iterate-key] and similar ops. These operations support @tech{chaperones} and @tech{impersonators}. Each unsafe @code{-first} and @code{-next} operation may not return a number index but rather an internal representation of a view into the hash structure, enabling faster iteration. The result of these @code{-first} and @code{-next}] functions should be given to the corresponding unsafe accessor functions. If the key or value at the position returned by the @code{-first} and @code{-next} ops becomes invalid (e.g., because of mutation or garbage collection), then the operations @exnraise[exn:fail:contract]. @history[#:added "6.4.0.6"] } @; ------------------------------------------------------------------------ @section[#:tag "unsafeextfl"]{Unsafe Extflonum Operations} @deftogether[( @defproc[(unsafe-extfl+ [a extflonum?] [b extflonum?]) extflonum?] @defproc[(unsafe-extfl- [a extflonum?] [b extflonum?]) extflonum?] @defproc[(unsafe-extfl* [a extflonum?] [b extflonum?]) extflonum?] @defproc[(unsafe-extfl/ [a extflonum?] [b extflonum?]) extflonum?] @defproc[(unsafe-extflabs [a extflonum?]) extflonum?] )]{ Unchecked versions of @racket[extfl+], @racket[extfl-], @racket[extfl*], @racket[extfl/], and @racket[extflabs].} @deftogether[( @defproc[(unsafe-extfl= [a extflonum?] [b extflonum?]) boolean?] @defproc[(unsafe-extfl< [a extflonum?] [b extflonum?]) boolean?] @defproc[(unsafe-extfl> [a extflonum?] [b extflonum?]) boolean?] @defproc[(unsafe-extfl<= [a extflonum?] [b extflonum?]) boolean?] @defproc[(unsafe-extfl>= [a extflonum?] [b extflonum?]) boolean?] @defproc[(unsafe-extflmin [a extflonum?] [b extflonum?]) extflonum?] @defproc[(unsafe-extflmax [a extflonum?] [b extflonum?]) extflonum?] )]{ Unchecked versions of @racket[extfl=], @racket[extfl<], @racket[extfl>], @racket[extfl<=], @racket[extfl>=], @racket[extflmin], and @racket[extflmax].} @deftogether[( @defproc[(unsafe-extflround [a extflonum?]) extflonum?] @defproc[(unsafe-extflfloor [a extflonum?]) extflonum?] @defproc[(unsafe-extflceiling [a extflonum?]) extflonum?] @defproc[(unsafe-extfltruncate [a extflonum?]) extflonum?] )]{ Unchecked (potentially) versions of @racket[extflround], @racket[extflfloor], @racket[extflceiling], and @racket[extfltruncate]. Currently, these bindings are simply aliases for the corresponding safe bindings.} @deftogether[( @defproc[(unsafe-extflsin [a extflonum?]) extflonum?] @defproc[(unsafe-extflcos [a extflonum?]) extflonum?] @defproc[(unsafe-extfltan [a extflonum?]) extflonum?] @defproc[(unsafe-extflasin [a extflonum?]) extflonum?] @defproc[(unsafe-extflacos [a extflonum?]) extflonum?] @defproc[(unsafe-extflatan [a extflonum?]) extflonum?] @defproc[(unsafe-extfllog [a extflonum?]) extflonum?] @defproc[(unsafe-extflexp [a extflonum?]) extflonum?] @defproc[(unsafe-extflsqrt [a extflonum?]) extflonum?] @defproc[(unsafe-extflexpt [a extflonum?] [b extflonum?]) extflonum?] )]{ Unchecked (potentially) versions of @racket[extflsin], @racket[extflcos], @racket[extfltan], @racket[extflasin], @racket[extflacos], @racket[extflatan], @racket[extfllog], @racket[extflexp], @racket[extflsqrt], and @racket[extflexpt]. Currently, some of these bindings are simply aliases for the corresponding safe bindings.} @deftogether[( @defproc[(unsafe-fx->extfl [a fixnum?]) extflonum?] @defproc[(unsafe-extfl->fx [a extflonum?]) fixnum?] )]{ Unchecked conversion of a @tech{fixnum} to an integer @tech{extflonum} and vice versa. These are similar to the safe bindings @racket[->extfl] and @racket[extfl->exact-integer], but further constrained to consume or produce a fixnum. } @deftogether[( @defproc[(unsafe-extflvector-length [v extflvector?]) fixnum?] @defproc[(unsafe-extflvector-ref [v extflvector?] [k fixnum?]) extflonum?] @defproc[(unsafe-extflvector-set! [v extflvector?] [k fixnum?] [x extflonum?]) void?] )]{ Unchecked versions of @racket[extflvector-length], @racket[extflvector-ref], and @racket[extflvector-set!]. A @tech{extflvector}'s size can never be larger than a @tech{fixnum} (so even @racket[extflvector-length] always returns a fixnum).} @; ------------------------------------------------------------------------ @section{Unsafe Impersonators and Chaperones} @defproc[(unsafe-impersonate-procedure [proc procedure?] [replacement-proc procedure?] [prop impersonator-property?] [prop-val any] ... ...) (and/c procedure? impersonator?)]{ Like @racket[impersonate-procedure], but assumes that @racket[replacement-proc] calls @racket[proc] itself. When the result of @racket[unsafe-impersonate-procedure] is applied to arguments, the arguments are passed on to @racket[replacement-proc] directly, ignoring @racket[proc]. At the same time, @racket[impersonator-of?] reports @racket[#t] when given the result of @racket[unsafe-impersonate-procedure] and @racket[proc]. If @racket[proc] is itself an impersonator that is derived from @racket[impersonate-procedure*] or @racket[chaperone-procedure*], beware that @racket[replacement-proc] will not be able to call it correctly. Specifically, the impersonator produced by @racket[unsafe-impersonate-procedure] will not get passed to a wrapper procedure that was supplied to @racket[impersonate-procedure*] or @racket[chaperone-procedure*] to generate @racket[proc]. Finally, unlike @racket[impersonate-procedure], @racket[unsafe-impersonate-procedure] does not specially handle @racket[impersonator-prop:application-mark] as a @racket[prop]. The unsafety of @racket[unsafe-impersonate-procedure] is limited to the above differences from @racket[impersonate-procedure]. The contracts on the arguments of @racket[unsafe-impersonate-procedure] are checked when the arguments are supplied. As an example, assuming that @racket[f] accepts a single argument and is not derived from @racket[impersonate-procedure*] or @racket[chaperone-procedure*], then @racketblock[(λ (f) (unsafe-impersonate-procedure f (λ (x) (if (number? x) (error 'no-numbers!) (f x)))))] is equivalent to @racketblock[(λ (f) (impersonate-procedure f (λ (x) (if (number? x) (error 'no-numbers!) x))))] Similarly, with the same assumptions about @racket[f], the following two procedures @racket[_wrap-f1] and @racket[_wrap-f2] are almost equivalent; they differ only in the error message produced when their arguments are functions that return multiple values (and that they update different global variables). The version using @racket[unsafe-impersonate-procedure] will signal an error in the @racket[let] expression about multiple return values, whereas the one using @racket[impersonate-procedure] signals an error from @racket[impersonate-procedure] about multiple return values. @racketblock[(define log1-args '()) (define log1-results '()) (define wrap-f1 (λ (f) (impersonate-procedure f (λ (arg) (set! log1-args (cons arg log1-args)) (values (λ (res) (set! log1-results (cons res log1-results)) res) arg))))) (define log2-args '()) (define log2-results '()) (define wrap-f2 (λ (f) (unsafe-impersonate-procedure f (λ (arg) (set! log2-args (cons arg log2-args)) (let ([res (f arg)]) (set! log2-results (cons res log2-results)) res)))))] @history[#:added "6.4.0.4"] } @defproc[(unsafe-chaperone-procedure [proc procedure?] [wrapper-proc procedure?] [prop impersonator-property?] [prop-val any] ... ...) (and/c procedure? chaperone?)]{ Like @racket[unsafe-impersonate-procedure], but creates a @tech{chaperone}. Since @racket[wrapper-proc] will be called in lieu of @racket[proc], @racket[wrapper-proc] is assumed to return a chaperone of the value that @racket[proc] would return. @history[#:added "6.4.0.4"] } @; ------------------------------------------------------------------------ @include-section["unsafe-undefined.scrbl"]