▼ |  | FFI: PLT Scheme Foreign Interface

1 | Overview
2 | Loading Foreign Libraries
3 | C Types
4 | Pointer Functions
5 | Miscellaneous Support
6 | Derived Utilities
7 | Unexported Primitive Functions
8 | Macros for Unsafety
| Index

► | 4 | Pointer Functions

4.1 | Unsafe Pointer Operations
4.2 | Unsafe Memory Management

On this page:

cpointer?
ptr-equal?
ptr-add
offset-ptr?
ptr-offset
4.1`` Unsafe Pointer Operations
set-ptr-offset!
ptr-add!
ptr-ref
ptr-set!
memmove
memcpy
memset
cpointer-tag
set-cpointer-tag!
4.2`` Unsafe Memory Management
malloc
free
end-stubborn-change
malloc-immobile-cell
free-immobile-cell
register-finalizer
make-sized-byte-string

Version: 4.1.4
top← prev up next →

### 4`` Pointer Functions

(cpointer? v) → boolean?
v : any/c

Returns #t if v is a C pointer or a value that can be used as a pointer: #f (used as a NULL pointer), byte strings (used as memory blocks), or some additional internal objects (ffi-objs and callbacks, see Unexported Primitive Functions). Returns #f for other values.

(ptr-equal? cptr1 cptr2) → boolean?
cptr1 : cpointer?
cptr2 : cpointer?

Compares the values of the two pointers. Two different Scheme pointer objects can contain the same pointer.

(ptr-add cptr offset [type]) → cpointer?
cptr : cpointer?
offset : exact-integer?
type : ctype? = _byte

Returns a cpointer that is like cptr offset by offset instances of ctype.

The resulting cpointer keeps the base pointer and offset separate. The two pieces are combined at the last minute before any operation on the pointer, such as supplying the pointer to a foreign function. In particular, the pointer and offset are not combined until after all allocation leading up to a foreign-function call; if the called function does not itself call anything that can trigger a garbage collection, it can safely use pointers that are offset into the middle of a GCable object.

(offset-ptr? cptr) → boolean?
cptr : cpointer?

A predicate for cpointers that have an offset, such as pointers that were created using ptr-add. Returns #t even if such an offset happens to be 0. Returns #f for other cpointers and non-cpointers.

(ptr-offset cptr) → exact-integer?
cptr : cpointer?

Returns the offset of a pointer that has an offset. The resulting offset is always in bytes.

#### 4.1`` Unsafe Pointer Operations

(set-ptr-offset! cptr offset [ctype]) → void?
cptr : cpointer?
offset : exact-integer?
ctype : ctype? = _byte

Sets the offset component of an offset pointer. The arguments are used in the same way as ptr-add. If cptr has no offset, the exn:fail:contract exception is raised.

(ptr-add! cptr offset [ctype]) → void?
cptr : cpointer?
offset : exact-integer?
ctype : ctype? = _byte

Like ptr-add, but destructively modifies the offset contained in a pointer. The same operation could be performed using ptr-offset and set-ptr-offset!.

(ptr-ref cptr type [offset]) → any
cptr : cpointer?
type : ctype?
offset : exact-nonnegative-integer? = 0
(ptr-ref cptr type abs-tag offset) → any
cptr : cpointer?
type : ctype?
abs-tag : (one-of/c 'abs)
offset : exact-nonnegative-integer?
(ptr-set! cptr type val) → void?
cptr : cpointer?
type : ctype?
val : any/c
(ptr-set! cptr type offset val) → void?
cptr : cpointer?
type : ctype?
offset : exact-nonnegative-integer?
val : any/c
(ptr-set! cptr type abs-tag offset val) → void?
cptr : cpointer?
type : ctype?
abs-tag : (one-of/c 'abs)
offset : exact-nonnegative-integer?
val : any/c

The ptr-ref procedure returns the object referenced by cptr, using the given type. The ptr-set! procedure stores the val in the memory cptr points to, using the given type for the conversion.

In each case, offset defaults to 0 (which is the only value that should be used with ffi-obj objects, see Unexported Primitive Functions). If an offset index is non-0, the value is read or stored at that location, considering the pointer as a vector of types – so the actual address is the pointer plus the size of type multiplied by offset. In addition, a 'abs flag can be used to use the offset as counting bytes rather then increments of the specified type.

Beware that the ptr-ref and ptr-set! procedure do not keep any meta-information on how pointers are used. It is the programmer’s responsibility to use this facility only when appropriate. For example, on a little-endian machine:

> (define block (malloc _int 5))
> (ptr-set! block _int 0 196353)
> (map (lambda (i) (ptr-ref block _byte i)) '(0 1 2 3))
,( schemeresultfont "(1 255 2 0)")

In addition, ptr-ref and ptr-set! cannot detect when offsets are beyond an object’s memory bounds; out-of-bounds access can easily lead to a segmentation fault or memory corruption.

(memmove cptr src-cptr count [type]) → void?
cptr : cpointer?
src-cptr : cpointer?
count : exact-nonnegative-integer?
type : ctype? = _byte
(memmove cptr offset src-cptr count [type]) → void?
cptr : cpointer?
offset : exact-integer?
src-cptr : cpointer?
count : exact-nonnegative-integer?
type : ctype? = _byte

(memmove |  | cptr |  |  |  |
|  | offset |  |  |  |
|  | src-cptr |  |  |  |
|  | src-offset |  |  |  |
|  | count |  |  |  |
| [ | type]) |  | → |  | void?

cptr : cpointer?
offset : exact-integer?
src-cptr : cpointer?
src-offset : exact-integer?
count : exact-nonnegative-integer?
type : ctype? = _byte

Copies to cptr from src-cptr. The destination pointer can be offset by an optional offset, which is in type instances. The source pointer can be similarly offset by src-offset. The number of bytes copied from source to destination is determined by count, which is in type instances when supplied.

(memcpy cptr src-cptr count [type]) → void?
cptr : cpointer?
src-cptr : cpointer?
count : exact-nonnegative-integer?
type : ctype? = _byte
(memcpy cptr offset src-cptr count [type]) → void?
cptr : cpointer?
offset : exact-integer?
src-cptr : cpointer?
count : exact-nonnegative-integer?
type : ctype? = _byte

(memcpy |  | cptr |  |  |  |
|  | offset |  |  |  |
|  | src-cptr |  |  |  |
|  | src-offset |  |  |  |
|  | count |  |  |  |
| [ | type]) |  | → |  | void?

cptr : cpointer?
offset : exact-integer?
src-cptr : cpointer?
src-offset : exact-integer?
count : exact-nonnegative-integer?
type : ctype? = _byte

Like memmove, but the result is undefined if the destination and source overlap.

(memset cptr byte count [type]) → void?
cptr : cpointer?
byte : byte?
count : exact-nonnegative-integer?
type : ctype? = _byte
(memset cptr offset byte count [type]) → void?
cptr : cpointer?
offset : exact-integer?
byte : byte?
count : exact-nonnegative-integer?
type : ctype? = _byte

Similar to memmove, but the destination is uniformly filled with byte (i.e., an exact integer between 0 and 255 inclusive).

(cpointer-tag cptr) → any
cptr : cpointer?

Returns the Scheme object that is the tag of the given cptr pointer.

(set-cpointer-tag! cptr tag) → void?
cptr : cpointer?
tag : any/c

Sets the tag of the given cptr. The tag argument can be any arbitrary value; other pointer operations ignore it. When a cpointer value is printed, its tag is shown if it is a symbol, a byte string, a string. In addition, if the tag is a pair holding one of these in its car, the car is shown (so that the tag can contain other information).

#### 4.2`` Unsafe Memory Management

For general information on C-level memory management with PLT Scheme, see Inside: PLT Scheme C API.

(malloc |  | bytes-or-type |  |  |  |
| [ | type-or-bytes |  |  |  |
|  | cptr |  |  |  |
|  | mode |  |  |  |
|  | fail-mode]) |  | → |  | cpointer?

bytes-or-type : (or/c exact-nonnegative-integer? ctype?)

| type-or-bytes |  | : |  | (or/c exact-nonnegative-integer? ctype?)
|  |  | = |  | absent

cptr : cpointer? = absent

mode

:

(one-of/c 'nonatomic 'stubborn 'uncollectable
'eternal 'interior 'atomic-interior
'raw)

=

absent

fail-mode : (one-of/c 'failok) = absent

Allocates a memory block of a specified size using a specified allocation. The result is a cpointer to the allocated memory. Although not reflected above, the four arguments can appear in any order since they are all different types of Scheme objects; a size specification is required at minimum:

- If a C type bytes-or-type is given, its size is used to the block allocation size.

- If an integer bytes-or-type is given, it specifies the required size in bytes.

- If both bytes-or-type and type-or-bytes are given, then the allocated size is for a vector of values (the multiplication of the size of the C type and the integer).

- If a cptr pointer is given, its content is copied to the new block.

- A symbol mode argument can be given, which specifies what allocation function to use. It should be one of 'nonatomic (uses scheme_malloc from PLT Scheme’s C API), 'atomic (scheme_malloc_atomic), 'stubborn (scheme_malloc_stubborn), 'uncollectable (scheme_malloc_uncollectable), 'eternal (scheme_malloc_eternal), 'interior (scheme_malloc_allow_interior), 'atomic-interior (scheme_malloc_atomic_allow_interior), or 'raw (uses the operating system’s malloc, creating a GC-invisible block).

- If an additional 'failok flag is given, then scheme_malloc_fail_ok is used to wrap the call.

If no mode is specified, then 'nonatomic allocation is used when the type is any pointer-based type, and 'atomic allocation is used otherwise.

(free cptr) → void
cptr : cpointer?

Uses the operating system’s free function for 'raw-allocated pointers, and for pointers that a foreign library allocated and we should free. Note that this is useful as part of a finalizer (see below) procedure hook (e.g., on the Scheme pointer object, freeing the memory when the pointer object is collected, but beware of aliasing).

(end-stubborn-change cptr) → void?
cptr : cpointer?

Uses scheme_end_stubborn_change on the given stubborn-allocated pointer.

(malloc-immobile-cell v) → cpointer?
v : any/c

Allocates memory large enough to hold one arbitrary (collectable) Scheme value, but that is not itself collectable or moved by the memory manager. The cell is initialized with v; use the type _scheme with ptr-ref and ptr-set! to get or set the cell’s value. The cell must be explicitly freed with free-immobile-cell.

(free-immobile-cell cptr) → void?
cptr : cpointer?

Frees an immobile cell created by malloc-immobile-cell.

(register-finalizer obj finalizer) → void?
obj : any/c
finalizer : (any/c . -> . any)

Registers a finalizer procedure finalizer-proc with the given obj, which can be any Scheme (GC-able) object. The finalizer is registered with a will executor; see make-will-executor. The finalizer is invoked when obj is about to be collected. (This is done by a thread that is in charge of triggering these will executors.)

Finalizers are mostly intended to be used with cpointer objects (for freeing unused memory that is not under GC control), but it can be used with any Scheme object – even ones that have nothing to do with foreign code. Note, however, that the finalizer is registered for the Scheme object. If you intend to free a pointer object, then you must be careful to not register finalizers for two cpointers that point to the same address. Also, be careful to not make the finalizer a closure that holds on to the object.

For example, suppose that you’re dealing with a foreign function that returns a C string that you should free. Here is an attempt at creating a suitable type:

(define bytes/free
(make-ctype _pointer
#f ; a Scheme bytes can be used as a pointer
(lambda (x)
(let ([b (make-byte-string x)])
(register-finalizer x free)
b))))

The above code is wrong: the finalizer is registered for x, which is no longer needed once the byte string is created. Changing this to register the finalizer for b correct this problem, but then free will be invoked on it instead of on x. In an attempt to fix this, we will be careful and print out a message for debugging:

(define bytes/free
(make-ctype _pointer
#f ; a Scheme bytes can be used as a pointer
(lambda (x)
(let ([b (make-byte-string x)])
(register-finalizer b
(lambda (ignored)
(printf "Releasing ~s\n" b)
(free x)))
b))))

but we never see any printout. The problem is that the finalizer is a closure that keeps a reference to b. To fix this, you should use the input argument to the finalizer. Simply changing ignored to b will solve this problem. (Removing the debugging message also avoids the problem, since the finalization procedure would then not close over b.)

(make-sized-byte-string cptr length) → bytes?
cptr : cpointer?
length : exact-nonnegative-integer?

Returns a byte string made of the given pointer and the given length. No copying is done. This can be used as an alternative to make pointer values accessible in Scheme when the size is known.

If cptr is an offset pointer created by ptr-add, the offset is immediately added to the pointer. Thus, this function cannot be used with ptr-add to create a substring of a Scheme byte string, because the offset pointer would be to the middle of a collectable object (which is not allowed).

top← prev up next →